Skip to content

feat(sync): activate the push + schedule cascade - #65

Merged
kyle-sexton merged 1 commit into
mainfrom
feat/sync-triggers
Jul 7, 2026
Merged

feat(sync): activate the push + schedule cascade#65
kyle-sexton merged 1 commit into
mainfrom
feat/sync-triggers

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Stage 2 of the caller activation, now that the pilot is confirmed (melodic-software/github-iac#37 — merged):

  • push trigger on main, paths-filtered to the distributed files (modules/**, root hygiene files, stub sources, the manifest) — upstream edits cascade immediately.
  • weekly schedule (Mon 06:00 UTC) — drift repair even without upstream pushes.
  • Both are real runs (inputs.dry-run || false; inputs is empty on those events). Dispatch keeps its dry-run-default preview + targets allowlist.
  • Engine pin bumped to 789abbe (client-id mint, ci-workflows#59); secret flipped to STANDARDS_SYNC_APP_CLIENT_ID in lockstep. STANDARDS_SYNC_APP_ID gets deleted after this merges.
  • Plan doc: the ready-to-paste caller snippet is replaced by a pointer to the live workflow (single source, no drift).

Note: until the App is installed on the kyle-sexton account (manual step, in progress), the three personal-account sync legs fail while the org legs succeed (fail-fast: false).

Verification

actionlint + zizmor + markdownlint (module config) clean locally.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GbDWhcUtduCejgi7mcbMfy


Note

Medium Risk
Merging enables real cross-repo PR opens on every qualifying main push and weekly cron; auth secret renames must be in place or sync legs will fail until the App is fully installed on all target accounts.

Overview
Stage 2 activation for Track B config distribution: the standards-sync caller now runs on push to main (path-filtered to distributed files) and on a weekly Monday 06:00 UTC schedule, so upstream edits cascade immediately and drift can be repaired without a push. Manual workflow_dispatch still defaults to dry-run with an optional targets allowlist; push and schedule use inputs.dry-run || false and inputs.targets || '' so those events perform real syncs (not preview-only).

The reusable engine ref is bumped to 789abbe, and caller secrets move from app-id / STANDARDS_SYNC_APP_ID to app-client-id / STANDARDS_SYNC_APP_CLIENT_ID in line with the engine’s client-id minting change.

Docs: config-distribution-plan.md drops the long inline caller YAML snippet and points to .github/workflows/sync.yml as the single source of truth, noting the two-stage activation (dispatch-only pilot, then push + schedule).

Reviewed by Cursor Bugbot for commit 3f3b355. Bugbot is set up for automated code reviews on this repo. Configure here.

@claude

claude Bot commented Jul 7, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 35s —— View job


PR Review

  • Gather context (CLAUDE.md, REVIEW.md, changed files)
  • Review .github/workflows/sync.yml changes
  • Review docs/dedup-program/config-distribution-plan.md changes
  • Post final review

The changes are correct and the activation logic is sound. A few observations:

dry-run expression

sync.yml L42: ${{ inputs.dry-run || false }} is correct — on push/schedule events inputs is an empty context, so the falsy fallback makes both non-dispatch triggers real runs while workflow_dispatch passes through whatever the user chose. The warning comment about the == 'schedule' antipattern is a useful guard for future editors.

Push paths filter scope

sync.yml L9-L15: The filter covers modules/**, the two root stubs (ruff.toml, .gitleaks.toml), the root hygiene files, and the manifest. However, the Layer 2 distributed set in the plan doc also includes pyrightconfig.json, .shellcheckrc, _typos.toml, .editorconfig-checker.json, and PSScriptAnalyzerSettings.psd1. Edits to those files will not trigger an immediate cascade; they rely on the weekly schedule for drift repair. This looks intentional (stubs and module files change more often than the others) but isn't explicitly called out — worth a brief comment if the intent is "stubs + modules cascade immediately; everything else drifts at most one week."

targets fallback

sync.yml L43: ${{ inputs.targets || '' }} is correct — the empty string signals "all targets" to the engine, and on non-dispatch events this is what you want.

Secret rename

app-idapp-client-id / STANDARDS_SYNC_APP_IDSTANDARDS_SYNC_APP_CLIENT_ID is an in-lockstep rename with the engine bump to 789abbe. The PR description notes STANDARDS_SYNC_APP_ID is a manual delete post-merge — worth confirming that's tracked somewhere (e.g. github-iac) so it doesn't get left as an orphan secret.

Engine SHA pin

sync.yml L36: Pin bump from 9cf6d13789abbe with the inline date comment follows the repo's D5 pinning convention. No issues.

Doc update

Replacing the ready-to-paste snippet with a pointer to the live file is the right call — the snippet was already a drift vector the moment it was written.


Overall: logic is correct, the || false fallback is applied properly, and the doc cleanup is clean. The only non-trivial note is the narrow paths scope for push — make sure it's a deliberate choice (and if so, a one-line comment would make it obvious to the next reader). Approved subject to that clarification.

The single-target pilot passed (github-iac PR #37 carried exactly the
accumulated drift), so the caller gains its remaining triggers: push to
main on distributed paths and the weekly cron, both real runs via
`inputs.dry-run || false` (dispatch keeps its dry-run default). Pin
bumped to the engine's client-id mint (ci-workflows #59) and the secret
flipped to STANDARDS_SYNC_APP_CLIENT_ID in lockstep. The plan doc's
ready-to-paste snippet is superseded by the live workflow — replaced
with a pointer so the two cannot drift.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbDWhcUtduCejgi7mcbMfy

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Risk: medium. Cursor Bugbot completed successfully with no findings requiring human review. Approved; no reviewers assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@kyle-sexton
kyle-sexton merged commit e41b1f5 into main Jul 7, 2026
38 checks passed
@kyle-sexton
kyle-sexton deleted the feat/sync-triggers branch July 7, 2026 02:13
kyle-sexton added a commit that referenced this pull request Jul 15, 2026
…on governance (#123)

## Summary

Closes decisions **#27**, **#63**, and **#65** from the [Decisions
Log](https://claude.ai/code/artifact/232ecdce-8316-4880-8c0a-dc3c7dcf3a63)
(evidence/rationale:
https://claude.ai/code/artifact/3160ae0e-c02f-4619-8de3-60d73faa1100).

### #63 metadata-standards-copy-vs-cite-doctrine

Decision: **keep the "copy" adoption path, require back-link +
drift-check.**

Adds `distribution/governance-process.md`. `conventions/README.md`
already documents two adoption paths for reasoning-only prose — copy
into the consumer's tree, or point at this repo. The copy path stays
available (prose has no runtime coupling to enforce reconciliation the
way `sync-manifest.yml` does), but a copy now carries two mandatory
requirements:

- **Back-link** — every copied file cites its exact canonical source
(repo + path, inline header where the format allows it), using the same
stable-anchor citation discipline `reference-dont-duplicate.md` already
prescribes for the "Expose" file role.
- **Drift-check** — the adopting repo owns a periodic diff of its copy
against the current canonical source, with a named owner and trigger,
mirroring the recheck-trigger discipline
`documentation-and-citations.md` already requires for time-bound
external claims.

The doc is explicit that this is distinct from a `managed`
`sync-manifest.yml` component, which already reconciles automatically
and deliberately carries no downstream receipt — the
back-link/drift-check burden applies only where nothing else keeps a
copy current.

### #65 naming-cross-doc-reconciliation-process-ownership

Decision: **establish a standing cross-reference review step for
normative-doc changes.**

Same doc adds the standing process step: before a change to a normative
doc (`naming.md`, `process/issue-tracker.md`, `review/code-quality.md`,
and any other file in the catalog stating a rule another doc cites or
assumes) merges, a cross-reference check confirms no other doc now
contradicts it.

Ownership is named explicitly rather than left implicit:
`required_approving_review_count` stays at `0` org-wide (decision #11,
single-maintainer), so there is no independent blocking reviewer to gate
this. The step is documented as a **self-review checklist item the
author performs before merge**, with a documented future automation path
— extending the periodic cross-plugin-source consistency check (decision
#37, for `claude-code-plugins`) to this repo's own normative docs once
that check exists, so the control stops depending solely on author
diligence.

`conventions/README.md` gets a new "Changing a normative file" pointer
to this requirement; `distribution/README.md` gets a pointer alongside
its existing `THREAT-MODEL.md` reference.

### #27 tooling-gov-conventions-graduate-to-enforced

Decision: **graduate mechanically-checkable rules into
sync-manifest-tracked components.**

Reviewed every file under `conventions/` against
`enforceability-tiers.md`'s
deterministic/detect-then-judge/reasoning-only split. Finding: **no
ungraduated deterministic rule exists to graduate.** Every deterministic
(mechanically-checkable) rule already points to its owning component
instead of restating it:

| Convention area | Deterministic rule | Owning component | Tracked in
`sync-manifest.yml`? |
|---|---|---|---|
| Secrets (`review/security.md`) | no secrets in source | `gitleaks` |
yes |
| Comments (`review/code-quality.md`) | debt markers / tracker
provenance | `comment-hygiene` | yes (`comment-hygiene-action`) |
| Citations (`documentation-and-citations.md`) | cited URL resolves |
link check | yes (`lychee`) |
| TypeScript/JS (`review/overlays/typescript.md`) | lint/format/import
order, type correctness | `biome`, `tsconfig` | **no** — deliberately
native-package (`extends`) adoption per `distribution/README.md`'s
ownership model, not exact materialization |
| Python (`review/overlays/python.md`) | lint/format, type correctness |
`ruff`, `pyright` | yes |
| .NET (`review/overlays/dotnet.md`) | analyzers, code style, banned
symbols | `dotnet-analysis` | yes |
| Container build (`container-supply-chain.md`) | Docker Build checks,
OSV scans | *(none yet)* | **no** — the convention itself explicitly
defers this pending live-consumer admission evidence per
`docs/component-lifecycle.md`; graduating it without that evidence would
violate the same lifecycle contract |
| PR titles (`review/code-quality.md`) | Conventional Commits format |
*(ci-workflows `pr-title.yml`)* | out of this repo's materialization
surface — owned by `ci-workflows`, per README.md's ownership boundaries
|
| Naming (`naming.md`), label/issue-tracker usage
(`process/issue-tracker.md`), duplication
(`reference-dont-duplicate.md`) | — | — | self-declared reasoning-only;
no deterministic subset exists to graduate |

No `sync-manifest.yml` change is included. The one adjacent orphan
noticed in passing — `components/lefthook-typescript` exists, is fully
built, but is not registered in `sync-manifest.yml` for any target — is
tooling infrastructure, not a `conventions/` rule, and assigning it to a
target's `managed:` list is a separate adoption decision requiring its
own admission evidence; flagging it here for a follow-up rather than
folding it into this PR.

## Test plan

- [x] `npx markdownlint-cli2` — 0 errors across the full repo (71 files,
including the new/changed docs)
- [x] `lychee` — 21/21 links OK on the changed files (0 errors)
- [x] `typos` — clean on the changed files
- [x] `lefthook` pre-commit (typos, editorconfig, gitleaks,
markdownlint) — all passed at commit time
- [ ] Maintainer confirms the #27 classification table before merge — no
code/config changed, so this PR is prose-only and carries no behavioral
risk

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant