actions/docs-sync — vendored doctrine, machine-verified (.ceremony/ mirror) #19
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:docs
scope:guards
scope:labels
scope:release-flow
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/ceremony#19
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Part of #1's family, required by PR #17's consumption model. Blocked by #2 (harness), #5 (the composite pattern). Blocks #13 (conversions vendor the doctrine) and #16.
Goal
actions/docs-sync— the materialization machinery for doctrine. Workflows and actions are consumed by reference: GitHub fetches them from the pinned ref at run time, so no copy exists in a consumer. Documents have no such runtime — their "runtime" is an agent reading the working tree of the repo it stands in, so the agent-facing doc set must exist in each governed repo's tree. This action makes that copy safe: a mirror that is machine-written and machine-verified, so drift is unrepresentable — the only kind of copy the org allows.The vendored set
Defined by a manifest in this repo —
docs/VENDORED.txt, one path per line:AGENTS.md is the router — the file that makes "you are a reviewer here" a sufficient launch prompt (agent harnesses auto-load root AGENTS.md; the consumer's thin root stub forwards to
.ceremony/AGENTS.md).The manifest is the single source of what gets mirrored (the sync script must not hardcode the list). Consumers receive these under
.ceremony/, byte-identical to this repo at the consumer's pinned ref, plus one generated.ceremony/README.mdstating: machine-managed byactions/docs-sync; never edit here — edit in heavy-duty/ceremony; the pin lives in.github/workflows/release.yml. (A generated README rather than per-file banners, so every vendored file stays byte-identical to its source and the check is a plain diff.)Relative links inside the set (
[LABELS.md](LABELS.md)etc.) resolve within.ceremony/because the whole set travels together — PR #17 already made the four files self-contained (no links out of the set).The tool — one script, two modes
actions/docs-sync/docs-sync.sh(composite action per the #5 pattern; script runnable directly for local use and tests):.github/workflows/release.yml— the singleuses: heavy-duty/ceremony/.github/workflows/release.yml@<ref>line. Exactly one such line must match; zero or several → refuse with a message naming the file (never guess a ref). This is what makes "one pin governs machinery and doctrine" literally true: there is no second pin to fall out of sync.--check(the default; what CI runs): fetch this repo at the pin (public repo — tarball fetch, no auth), diff manifest ∪.ceremony/as an exact mirror: a drifted file, a missing file, an extra file under.ceremony/not in the manifest (README excepted), or a missing.ceremony/entirely all fail, each with a message that names the offender and says the fix (run docs-sync --fix, orre-run after bumping the pin). Red on drift is the whole point — say it plainly.--fix: write the mirror to match the pin exactly — copy the manifest set, generate the README, delete vendored files no longer in the manifest (mirror means mirror). Prints what changed. Additionally, if the consumer has no rootAGENTS.md, scaffold the thin stub ("governed by heavy-duty/ceremony; read.ceremony/AGENTS.mdfirst; repo specifics in CONTRIBUTING") — created once, never overwritten: the root stub is per-repo content the moment the repo edits it, so--checkignores its content and asserts only that it exists.--source <dir>override: use a local directory instead of fetching — this is how tests run offline, and how a ceremony PR can be previewed against a consumer before release.mode(check|fix, defaultcheck). The action runs after the consumer's own checkout, like every guard.Consumer wiring (goes into docs/CONSUMERS.md, #12)
uses: heavy-duty/ceremony/actions/docs-sync@<tag>alongside the other guards..ceremony/(run--fixlocally, or let the red--checkon the bump PR tell you). The guard makes a half-done bump (pin without mirror, mirror without pin) unmergeable.--fixonce; commit.ceremony/with the callers.Tests (
test/docs-sync.test.sh) — offline via--source.ceremony/absent → each fails with its own message.--fixfrom empty → writes exact set + README + root AGENTS.md stub;--fixafter manifest removal → deletes the orphan;--fixis idempotent (second run changes nothing, exits 0).--fixwith an existing (edited) root AGENTS.md → untouched;--checkwith root AGENTS.md missing → fails ("run --fix"); present-but-custom → passes.Acceptance criteria
--checkviauses: ./actions/docs-syncagainst a fixture consumer (constructed in the test job) — proving the composite wiring.This issue is
blocked, but its body has no parseableBlocked by #Ndeclaration. The sweep will not guess the dependency.Unblocked →
ready.Named blockers have landed: #2 (harness, PR #25) and #5 (
actions/changelog-armed, PR #33 — the composite pattern). Nothing else stands in the way; a builder can claim it now.Note it still blocks #13 and #16, so it is on the critical path for the conversions.
🔨 claiming — starting on
actions/docs-sync. Draft PR soon.