diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5490034..cf2aa97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,3 +96,43 @@ jobs: with: changelog: CHANGELOG.monotonic.scratch.md base-ref: monotonic-fixture-base + + # Exercises actions/docs-sync the way a consumer does (issue #19's + # acceptance criterion). Its own job, unlike the exercises above: the + # composite reads the CONSUMER's tree at the workspace root, and a + # `uses:` step cannot change directory — so the fixture consumer must BE + # the workspace root, with ceremony itself checked out to a subdirectory + # (that path also serves as the action reference and the --source + # override; no ref carrying docs/VENDORED.txt exists to fetch until this + # lands, and the exercised bytes should be THIS PR's anyway). + docs-sync-exercise: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + path: ceremony-src + - name: Construct a fixture consumer at the workspace root + # The pin ref is scratch — --source overrides the fetch, but the + # pin line itself is still parsed and required (one pin governs + # machinery and doctrine; a consumer without one has nothing for + # the mirror to be verified against). + run: | + mkdir -p .github/workflows + printf '%s\n' \ + 'name: release' \ + 'on:' \ + ' push:' \ + ' branches: [main]' \ + 'jobs:' \ + ' release:' \ + ' uses: heavy-duty/ceremony/.github/workflows/release.yml@0.0.0-fixture' \ + > .github/workflows/release.yml + - name: Bootstrap the mirror (--fix) + uses: ./ceremony-src/actions/docs-sync + with: + mode: fix + source: ceremony-src + - name: Verify the mirror (--check, the mode consumers run) + uses: ./ceremony-src/actions/docs-sync + with: + source: ceremony-src diff --git a/docs/CONSUMERS.md b/docs/CONSUMERS.md index f430e4b..420a3b0 100644 --- a/docs/CONSUMERS.md +++ b/docs/CONSUMERS.md @@ -113,3 +113,48 @@ rows remain consumer-owned because paths and surfaces differ by repository. After adding the caller and configuration, run `workflow_dispatch` once to bootstrap labels on a fresh repository. Scheduled and PR-triggered runs only reconcile; they do not repeatedly upsert the taxonomy. + +## Doctrine mirror + +Machinery is consumed by reference — GitHub fetches the workflows and +actions above from the pin at run time — but documents have no runtime: an +agent reads the working tree it stands in. So the agent-facing doc set +(ceremony's `docs/VENDORED.txt`: AGENTS.md, TRIAGE.md, BUILDER.md, +REVIEWER.md, LABELS.md) is vendored into each consumer at **`.ceremony/`**, +byte-identical to ceremony at the pin, plus a generated `.ceremony/README.md` +marking the directory machine-managed. `actions/docs-sync` owns the copy: +`--fix` writes it (and deletes what the manifest dropped — mirror means +mirror), `--check` re-diffs it in CI on every PR, so a hand edit or a stale +pin goes red instead of quietly governing. + +The consumer's ci.yml gains the guard alongside the others: + +```yaml + - uses: actions/checkout@v4 + - uses: heavy-duty/ceremony/actions/docs-sync@ +``` + +`mode` defaults to `check`. There is no ref input: the action reads the pin +from the consumer's own `.github/workflows/release.yml` — the same single +`uses: …/release.yml@` line that pins the machinery, so one pin governs +machinery and doctrine alike, and a second pin cannot fall out of sync. + +**Bootstrap on adoption**: add the release and labels callers first (the pin +must exist — the mirror is verified against it), then run `--fix` once from +the repo root and commit `.ceremony/` together with the callers: + +```sh +curl -fsSL "https://raw.githubusercontent.com/heavy-duty/ceremony//actions/docs-sync/docs-sync.sh" \ + | bash -s -- --fix +``` + +If the repo has no root `AGENTS.md`, `--fix` also scaffolds the thin stub +that routes agents to `.ceremony/AGENTS.md` — created once, never +overwritten; it is per-repo content the moment you edit it, so `--check` +asserts only that it exists. + +**The pin-bump procedure**: bumping the pin is one PR — the pin line change +plus the re-synced mirror (run `--fix` locally, or let the red `--check` on +the bump PR say what is stale). The guard makes a half-done bump — pin +without mirror, mirror without pin — unmergeable, which is how a process +change rolls out: deliberately, per repo, reviewed.