From 8c29424519a01cdbf48df96aa24ace87eb096956 Mon Sep 17 00:00:00 2001 From: Andriujose <43181885+andriujoseba@users.noreply.github.com> Date: Mon, 3 Aug 2026 18:26:58 +0000 Subject: [PATCH] docs: correct release gate mechanics --- CONTRIBUTING.md | 2 +- RELEASES.md | 32 +++++++++++++++++++------------- changelog.d/248.md | 2 +- docs/VENDORED.txt | 1 + test/docs-sync.test.sh | 6 ++++++ 5 files changed, 28 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b1666c..9c8a7b7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,7 +96,7 @@ Two consumption modes, split by what has a runtime: "runtime" is an agent reading the working tree of the repo it stands in — a doc that requires a cross-repo fetch before it governs is a doc that sometimes goes unread. So the agent-facing set — **AGENTS.md, TRIAGE.md, - BUILDER.md, REVIEWER.md, LABELS.md** — is vendored into each governed + BUILDER.md, REVIEWER.md, LABELS.md, RELEASES.md** — is vendored into each governed repo at **`.ceremony/`**, byte-identical to this repo at the pinned ref, by the sync tool (issue #19). A CI guard diffs the mirror against the pin on every PR: hand-editing a vendored file, or bumping the pin without diff --git a/RELEASES.md b/RELEASES.md index 7942650..d3d6816 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -27,21 +27,24 @@ maps the ladder whose `0.1.2` working surface moved from the crufty ledger Each version epic declares `Blocked by `. Special ordering — a double gate or an out-of-chain gate — is written explicitly on that epic; -there is no hidden global schedule. The epic carries `epic`, the repository's -release label, and `blocked` while the gate stands. Shipping closes the current -epic; the ordinary blocker-cleared sweep path then replaces `blocked` with -`ready` on the next epic in the same pass. No special epic promotion exists or -is required: the reconciler dispatches `blocked` before `epic`. +there is no hidden global schedule. The epic carries `epic` and the +repository's release label, with no queue label. Its `Blocked by` line is a +declaration a human reads: shipping closes the predecessor, then triage opens +the next window by hand as the first step of release-init. The issue-flow +sweep does not promote version epics; automating that gate would require a +separately specified change to its queue-category model. The gate orders windows, not their contents. Members enter a release only by -decision during release-init. The double gate on heavy-duty/crew#163 and the +decision during release-init. The double gate on +[heavy-duty/crew#163](https://github.com/heavy-duty/crew/issues/163) and the out-of-chain track on [heavy-duty/crew#348](https://github.com/heavy-duty/crew/issues/348) are worked examples of exceptions declared where they apply. ## Release-init -A `ready` version epic is the trigger, and today triage must notice it and run -the cycle. [heavy-duty/ceremony#253](https://github.com/heavy-duty/ceremony/issues/253) +The predecessor closing and clearing the next epic's declared gate is the +trigger, and today triage must notice it and open that window by hand. +[heavy-duty/ceremony#253](https://github.com/heavy-duty/ceremony/issues/253) tracks the not-yet-shipped sweep announcement of that duty; do not treat the announcement as present until the consumer's pin carries it. Triage runs five steps: @@ -80,11 +83,14 @@ small crew-side bridge remains in the primary window. ## Flip mechanics -To admit a member, strike its live `Blocked by ` declaration and -swap `blocked` to `ready` in the same edit. Never preserve history by negating -the marker phrase — the blocker parser unions declarations even when prose -says they no longer apply. Preserve the old text only after striking or -rewriting the parseable clause, then verify the parser's resulting set. +To admit a member, delete or rewrite its literal, parseable +`Blocked by ` declaration and swap `blocked` to `ready` in the same +edit. Markdown or HTML strikethrough is insufficient: the blocker parser reads +the raw marker text and still returns the reference. Never preserve history by +negating the marker phrase — the parser unions declarations even when prose +says they no longer apply. Preserve the history only after rewriting the +marker into non-parseable prose, then verify that the parser returns an empty +set for the release gate. Release membership is a decision, never a sweep default. Triage performs each flip only after the operator blesses the wave; the issue-flow sweep may resolve diff --git a/changelog.d/248.md b/changelog.d/248.md index e33c4f6..d6c3bbd 100644 --- a/changelog.d/248.md +++ b/changelog.d/248.md @@ -1,3 +1,3 @@ ### Added -- Document the optional, operator-ruled release-epic flow for governed repositories. +- Document the optional, operator-ruled release-epic flow for governed repositories. (#248) diff --git a/docs/VENDORED.txt b/docs/VENDORED.txt index 10c20a3..ff41f35 100644 --- a/docs/VENDORED.txt +++ b/docs/VENDORED.txt @@ -3,3 +3,4 @@ TRIAGE.md BUILDER.md REVIEWER.md LABELS.md +RELEASES.md diff --git a/test/docs-sync.test.sh b/test/docs-sync.test.sh index 6987304..f5ecae9 100644 --- a/test/docs-sync.test.sh +++ b/test/docs-sync.test.sh @@ -18,6 +18,12 @@ SCRIPT="$ROOT/actions/docs-sync/docs-sync.sh" TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT +# RELEASES.md's consumer-availability promise is true only when the real +# manifest carries it (#248's review round). The fixture cases below prove +# manifest-driven behavior; this row binds that behavior to the promised file. +check "real manifest includes the release doctrine" 0 "RELEASES.md" \ + grep -Fx RELEASES.md "$ROOT/docs/VENDORED.txt" + # --- fixture builders -------------------------------------------------------- # The main fake ceremony tree: three manifest entries, one in a subdirectory