From 60e4f09f6371a492a8fdcab461d7224dbb792b98 Mon Sep 17 00:00:00 2001 From: claude-bot-andresmgsl Date: Fri, 24 Jul 2026 17:07:44 +0000 Subject: [PATCH 1/4] =?UTF-8?q?release:=200.3.0=20=E2=80=94=20bump=20VERSI?= =?UTF-8?q?ON=20from=200.2.1-dev?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs #160 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a5fea60..0d91a54 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.1-dev +0.3.0 -- 2.45.2 From d6b175f19f665ab0c2bf909209eb13e5d720c922 Mon Sep 17 00:00:00 2001 From: claude-bot-andresmgsl Date: Fri, 24 Jul 2026 17:07:44 +0000 Subject: [PATCH 2/4] =?UTF-8?q?release:=200.3.0=20=E2=80=94=20assemble=20t?= =?UTF-8?q?he=20changelog=20section=20from=20twelve=20fragments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bin/changelog-assemble 0.3.0: the section and the fragment deletions in one commit, per the issue's spec (#160). Refs #160 --- CHANGELOG.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ changelog.d/130.md | 1 - changelog.d/131.md | 1 - changelog.d/134.md | 1 - changelog.d/135.md | 10 ---------- changelog.d/137.md | 8 -------- changelog.d/139.md | 1 - changelog.d/144.md | 8 -------- changelog.d/145.md | 1 - changelog.d/149.md | 1 - changelog.d/151.md | 9 --------- changelog.d/154.md | 1 - changelog.d/159.md | 1 - 13 files changed, 46 insertions(+), 43 deletions(-) delete mode 100644 changelog.d/130.md delete mode 100644 changelog.d/131.md delete mode 100644 changelog.d/134.md delete mode 100644 changelog.d/135.md delete mode 100644 changelog.d/137.md delete mode 100644 changelog.d/139.md delete mode 100644 changelog.d/144.md delete mode 100644 changelog.d/145.md delete mode 100644 changelog.d/149.md delete mode 100644 changelog.d/151.md delete mode 100644 changelog.d/154.md delete mode 100644 changelog.d/159.md diff --git a/CHANGELOG.md b/CHANGELOG.md index b5060a9..ca4ed8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,52 @@ fragments — one `changelog.d/.md` per PR, never an edit to this file — and the release PR assembles them into the next section here (`bin/changelog-assemble`, #112). +## 0.3.0 — 2026-07-24 + +- Make `changelog-armed` reject fragment shape drift on the PR that introduces it. +- A directive hold now has a written ending, not just a beginning: BUILDER.md's shape 5 says the hold ends where it began — on the labels — with the hold owner's most recent queue-label event governing over any stale prose, the timeline read (`gh api .../issues/{n}/timeline`) named as the move before standing down or up on a hold, a claim against stale prose required to cite the events it read, and a refused claim given its two exits. TRIAGE.md now requires re-reading label events before asserting label-borne state in prose, and makes correcting a lifted hold's stale body header triage's move in the same tick. On 2026-07-24 the unranked signals split two builders reading one board (#149, #151); both acted defensibly — the doctrine, not the builders, lacked the rule (#154). +- Doctrine names the second `Closes #N` exception: a same-repo PR whose + authorizing issue marks an acceptance criterion post-merge uses `Refs #N`, + and triage closes the issue by hand on the evidence — merging #143 + auto-closed #137 with exactly such a criterion unmet, and no role had been + told otherwise. TRIAGE.md now requires a post-merge criterion to carry its + own mechanism (post-merge, triage closes, `Refs #N`), REVIEWER.md lists + `Refs #N` beside `Closes #N` and `Part of /#N` and stops + treating the reference-only PR as a defect, and CONTRIBUTING.md points at + BUILDER.md as the rule's one home (#151). +- FLEET.md — the Reviewers wake describes the deployed sweep, not the `gh search` trigger the bench replaced: the pulls-API `requested_reviewers` sweep across the org plus the named bot forks is source 1, the `repos.txt`/search poll an adds-only backstop, and the two are merged and deduplicated by (repo, PR) before acting. Only the notifier's `needs-ruling` queue remains on paper; `repos.txt` is the registry only on the triage box; and the Status block now stamps the crew ref the file was last reconciled against (#149). +- REVIEWER.md now carries the review mechanics every box had been re-deriving from an incident: the queue comes from the API and not the search index, every write is one-shot per (reviewer, PR, head), heads are reviewed in throwaway checkouts, a pinned consumer's config is verified at its pin, and a verdict names the checks its box could not run (#145). +- The `docs/CONSUMERS.md` labels-caller stub lists the same `issues:` types + as ceremony's own caller — `edited` and `reopened` included — so a consumer + adopting the stub wakes when an issue body's `Blocked by #N` declaration is + edited, and when a closed issue re-enters the queue wearing labels derived + at close. The two lists drifted apart inside PR #32; a parity test now pins + them together, red if either file drops a type or the lists diverge. + Adopting the widened list is a stub edit riding the pin bump to the first + tag carrying this change (#144). +- `labels-reconcile` — a queue-cancelled duplicate check is discarded when its context holds a real verdict, so a sibling PR's eviction no longer reds a green PR; an all-cancelled context still blocks (#139). +- `blocker:unrequested` now clears the moment the panel is asked: the labels + caller (and the `docs/CONSUMERS.md` stub) listens on `review_requested` and + `review_request_removed`, so the one event that falsifies the label — or + makes it true again — wakes the reconcile sweep instead of waiting for an + unrelated push or the advisory cron. The `scope` job skips both events: + they change no paths, and running the labeler on them widens the #130 + clobber window. Adopting the new triggers is a stub edit riding the pin + bump to the first tag carrying this change (#137). +- `drills/README.md` no longer tells the builder to delete the scratch repo — + a step no fleet identity can perform, because `delete_repo` is deliberately + absent from bot tokens. The builder's end state is **archive** + (`archived: true`, inside the `repo` scope); the delete is the operator's, + and cleanup gates nothing — not ready-for-review, not the panel, not the + merge. The drill record now names the scratch repo by `owner/name` and + states the disposal its author actually observed, never one that has not + happened: both 0.2.0 drills hit the missing-scope wall independently, one + stalling a release draft on an impossible 403, the other shipping a record + asserting a delete that never ran (#135). +- `lib/facts.sh` — a repository's first push to `main` (a root commit with no first parent) now reads `base_ver=(none)` and lets decide's table govern, instead of dying at exit 128 before establishing a fact; the no-base path skips the base fetch and `git show`, and an unresolvable head still fails loudly (#134). +- The changelog rule now explains why release PRs write no fragment and how entry-worthy changes land instead (#131). +- `actions/labels-scope` replaces `actions/labeler@v5` in the labels workflow's scope job: labeler wrote the whole label set (`PUT`) even under `sync-labels: false`, silently removing any label applied while it ran — #128 lost its `release` that way — so the scope job now derives from the same `.github/labeler.yml` mapping (the `changed-files`/`any-glob-to-any-file` shape, block or flow; anything else refuses loudly) and its only write is an additive `POST`. The reconcile sweep also warns — never sets — when a non-draft PR is release-shaped (bare version differing from its base) but carries no `release` label (#130). + ## 0.2.0 — 2026-07-24 - `test/changelog-assembled.test.sh` — keep the trio interaction aligned with fragment mode: a dropped entry makes armed red too, while a hand-edited section leaves assembled as the sole red (#126). diff --git a/changelog.d/130.md b/changelog.d/130.md deleted file mode 100644 index a2d35aa..0000000 --- a/changelog.d/130.md +++ /dev/null @@ -1 +0,0 @@ -- `actions/labels-scope` replaces `actions/labeler@v5` in the labels workflow's scope job: labeler wrote the whole label set (`PUT`) even under `sync-labels: false`, silently removing any label applied while it ran — #128 lost its `release` that way — so the scope job now derives from the same `.github/labeler.yml` mapping (the `changed-files`/`any-glob-to-any-file` shape, block or flow; anything else refuses loudly) and its only write is an additive `POST`. The reconcile sweep also warns — never sets — when a non-draft PR is release-shaped (bare version differing from its base) but carries no `release` label (#130). diff --git a/changelog.d/131.md b/changelog.d/131.md deleted file mode 100644 index 3e42d87..0000000 --- a/changelog.d/131.md +++ /dev/null @@ -1 +0,0 @@ -- The changelog rule now explains why release PRs write no fragment and how entry-worthy changes land instead (#131). diff --git a/changelog.d/134.md b/changelog.d/134.md deleted file mode 100644 index d9d334c..0000000 --- a/changelog.d/134.md +++ /dev/null @@ -1 +0,0 @@ -- `lib/facts.sh` — a repository's first push to `main` (a root commit with no first parent) now reads `base_ver=(none)` and lets decide's table govern, instead of dying at exit 128 before establishing a fact; the no-base path skips the base fetch and `git show`, and an unresolvable head still fails loudly (#134). diff --git a/changelog.d/135.md b/changelog.d/135.md deleted file mode 100644 index 2e39625..0000000 --- a/changelog.d/135.md +++ /dev/null @@ -1,10 +0,0 @@ -- `drills/README.md` no longer tells the builder to delete the scratch repo — - a step no fleet identity can perform, because `delete_repo` is deliberately - absent from bot tokens. The builder's end state is **archive** - (`archived: true`, inside the `repo` scope); the delete is the operator's, - and cleanup gates nothing — not ready-for-review, not the panel, not the - merge. The drill record now names the scratch repo by `owner/name` and - states the disposal its author actually observed, never one that has not - happened: both 0.2.0 drills hit the missing-scope wall independently, one - stalling a release draft on an impossible 403, the other shipping a record - asserting a delete that never ran (#135). diff --git a/changelog.d/137.md b/changelog.d/137.md deleted file mode 100644 index b8df157..0000000 --- a/changelog.d/137.md +++ /dev/null @@ -1,8 +0,0 @@ -- `blocker:unrequested` now clears the moment the panel is asked: the labels - caller (and the `docs/CONSUMERS.md` stub) listens on `review_requested` and - `review_request_removed`, so the one event that falsifies the label — or - makes it true again — wakes the reconcile sweep instead of waiting for an - unrelated push or the advisory cron. The `scope` job skips both events: - they change no paths, and running the labeler on them widens the #130 - clobber window. Adopting the new triggers is a stub edit riding the pin - bump to the first tag carrying this change (#137). diff --git a/changelog.d/139.md b/changelog.d/139.md deleted file mode 100644 index 16d9533..0000000 --- a/changelog.d/139.md +++ /dev/null @@ -1 +0,0 @@ -- `labels-reconcile` — a queue-cancelled duplicate check is discarded when its context holds a real verdict, so a sibling PR's eviction no longer reds a green PR; an all-cancelled context still blocks (#139). diff --git a/changelog.d/144.md b/changelog.d/144.md deleted file mode 100644 index 5dca276..0000000 --- a/changelog.d/144.md +++ /dev/null @@ -1,8 +0,0 @@ -- The `docs/CONSUMERS.md` labels-caller stub lists the same `issues:` types - as ceremony's own caller — `edited` and `reopened` included — so a consumer - adopting the stub wakes when an issue body's `Blocked by #N` declaration is - edited, and when a closed issue re-enters the queue wearing labels derived - at close. The two lists drifted apart inside PR #32; a parity test now pins - them together, red if either file drops a type or the lists diverge. - Adopting the widened list is a stub edit riding the pin bump to the first - tag carrying this change (#144). diff --git a/changelog.d/145.md b/changelog.d/145.md deleted file mode 100644 index 05fc6e7..0000000 --- a/changelog.d/145.md +++ /dev/null @@ -1 +0,0 @@ -- REVIEWER.md now carries the review mechanics every box had been re-deriving from an incident: the queue comes from the API and not the search index, every write is one-shot per (reviewer, PR, head), heads are reviewed in throwaway checkouts, a pinned consumer's config is verified at its pin, and a verdict names the checks its box could not run (#145). diff --git a/changelog.d/149.md b/changelog.d/149.md deleted file mode 100644 index a9874e6..0000000 --- a/changelog.d/149.md +++ /dev/null @@ -1 +0,0 @@ -- FLEET.md — the Reviewers wake describes the deployed sweep, not the `gh search` trigger the bench replaced: the pulls-API `requested_reviewers` sweep across the org plus the named bot forks is source 1, the `repos.txt`/search poll an adds-only backstop, and the two are merged and deduplicated by (repo, PR) before acting. Only the notifier's `needs-ruling` queue remains on paper; `repos.txt` is the registry only on the triage box; and the Status block now stamps the crew ref the file was last reconciled against (#149). diff --git a/changelog.d/151.md b/changelog.d/151.md deleted file mode 100644 index 84352e1..0000000 --- a/changelog.d/151.md +++ /dev/null @@ -1,9 +0,0 @@ -- Doctrine names the second `Closes #N` exception: a same-repo PR whose - authorizing issue marks an acceptance criterion post-merge uses `Refs #N`, - and triage closes the issue by hand on the evidence — merging #143 - auto-closed #137 with exactly such a criterion unmet, and no role had been - told otherwise. TRIAGE.md now requires a post-merge criterion to carry its - own mechanism (post-merge, triage closes, `Refs #N`), REVIEWER.md lists - `Refs #N` beside `Closes #N` and `Part of /#N` and stops - treating the reference-only PR as a defect, and CONTRIBUTING.md points at - BUILDER.md as the rule's one home (#151). diff --git a/changelog.d/154.md b/changelog.d/154.md deleted file mode 100644 index db3bede..0000000 --- a/changelog.d/154.md +++ /dev/null @@ -1 +0,0 @@ -- A directive hold now has a written ending, not just a beginning: BUILDER.md's shape 5 says the hold ends where it began — on the labels — with the hold owner's most recent queue-label event governing over any stale prose, the timeline read (`gh api .../issues/{n}/timeline`) named as the move before standing down or up on a hold, a claim against stale prose required to cite the events it read, and a refused claim given its two exits. TRIAGE.md now requires re-reading label events before asserting label-borne state in prose, and makes correcting a lifted hold's stale body header triage's move in the same tick. On 2026-07-24 the unranked signals split two builders reading one board (#149, #151); both acted defensibly — the doctrine, not the builders, lacked the rule (#154). diff --git a/changelog.d/159.md b/changelog.d/159.md deleted file mode 100644 index 2212ff8..0000000 --- a/changelog.d/159.md +++ /dev/null @@ -1 +0,0 @@ -- Make `changelog-armed` reject fragment shape drift on the PR that introduces it. -- 2.45.2 From 5f0686b3950d6adc699e750ef5858a20eb084f6f Mon Sep 17 00:00:00 2001 From: claude-bot-andresmgsl Date: Fri, 24 Jul 2026 17:07:49 +0000 Subject: [PATCH 3/4] =?UTF-8?q?release:=200.3.0=20=E2=80=94=20stamp=20CERE?= =?UTF-8?q?MONY=5FSELF=5FREF=20in=20both=20carriers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit release.yml and labels.yml both pin the ref a consumer's run fetches ceremony at; self-ref-check green against the bumped VERSION. Refs #160 --- .github/workflows/labels.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml index 28fdde1..04a4adb 100644 --- a/.github/workflows/labels.yml +++ b/.github/workflows/labels.yml @@ -25,7 +25,7 @@ on: env: # A called workflow arrives without its repository. Keep this literal pin # aligned with the ceremony release consumed by callers (issue #9 D3). - CEREMONY_SELF_REF: "0.2.0" + CEREMONY_SELF_REF: "0.3.0" jobs: scope: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4456c63..fa44030 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -129,7 +129,7 @@ env: # `ref:` accepts ${{ env }}; `uses:` strings do not — which is why the # shared logic arrives as script files via checkout, not as inner `uses:` # references. - CEREMONY_SELF_REF: "0.2.0" + CEREMONY_SELF_REF: "0.3.0" VERSION_SOURCE: ${{ inputs.version-source }} jobs: -- 2.45.2 From 30b49c4ade4cdb64d3440566fa526284a6461fa8 Mon Sep 17 00:00:00 2001 From: claude-bot-andresmgsl Date: Fri, 24 Jul 2026 17:17:02 +0000 Subject: [PATCH 4/4] =?UTF-8?q?release:=200.3.0=20=E2=80=94=20record=20the?= =?UTF-8?q?=20drill?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both doors rehearsed live on a disposable private repo, caller pinned to the fork scaffold carrying the candidate tree with CEREMONY_SELF_REF rewritten to the candidate SHA; all six probes as specified, every refusal creating nothing. Scratch repo archived, delete is the operator's (#135). Refs #160 --- drills/0.3.0.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 drills/0.3.0.md diff --git a/drills/0.3.0.md b/drills/0.3.0.md new file mode 100644 index 0000000..7af25b6 --- /dev/null +++ b/drills/0.3.0.md @@ -0,0 +1,53 @@ +# 0.3.0 — drill record + +Run 2026-07-24 by `claude-bot-andresmgsl` against the release candidate at +PR #165 head `5f0686b3950d6adc699e750ef5858a20eb084f6f`. + +Where: disposable private repo +`claude-bot-andresmgsl/ceremony-drill-0.3.0`, carrying the +`docs/CONSUMERS.md` release caller and a fragment-mode fixture armed at +`0.3.0-dev`. The fixture had `changelog.d/README.md`, one release fragment, +and a non-blank drill record. The repository is archived (observed +`archived: true` after the run), pending the operator's delete. + +## Candidate-ref deviation + +The pure consumer path still cannot resolve `CEREMONY_SELF_REF: "0.3.0"` +before the candidate creates that tag. No `0.3.0` branch was created in +`heavy-duty/ceremony` — `git ls-remote --heads origin 0.3.0` was empty +before and after the drill. The scratch caller instead used +`claude-bot-andresmgsl/ceremony@drill/0.3.0`, whose parent is the candidate +tree itself and whose only additional commit (`64af424`) rewrites both +`CEREMONY_SELF_REF` carriers to candidate SHA +`5f0686b3950d6adc699e750ef5858a20eb084f6f`. All runtime machinery was +therefore fetched from the 0.3.0 candidate tree. + +## Probes + +| # | probe | run | result | +|---|---|---|---| +| 1 | merge-door ceremony | 30112209127 (attempt 1) | ✅ one `0.3.0` release; tag equals merge commit; main re-armed to `0.3.1-dev` with only `changelog.d/README.md` | +| 2 | mislabeled ordinary PR | 30112073479 | ✅ green NOTICE no-op; no tag or release | +| 3 | bare-version PR without `release` | 30112112006 | ✅ refused at decide ("no merged, release-labeled PR is behind this commit"); no tag or release | +| 4 | re-run completed ceremony | 30112209127 (attempt 2) | ✅ refused because tag `0.3.0` already existed; release count stayed one | +| 5 | manual matching tag | 30112294804 | ✅ `0.4.0` published with its changelog section from a side-branch tree; main untouched at `0.3.1-dev` | +| 6 | mismatched tag | 30112327723 | ✅ refused ("tag '9.9.9' does not match the tree's version '0.4.0'"); no `9.9.9` release | + +The merge-door `0.3.0` tag and PR #3 merge commit were both +`78586bce3b7a40872fa844173d5b60a213917b3b`. Its release body was exactly +the two fragments the fixture held at the cut — probe 2's ordinary PR had +banked one more fragment before the ceremony, so the section assembled two: + +```text +- A harmless doc touch for probe 2 (mislabeled ordinary PR). +- Fragment mode is exercised by the 0.3.0 drill. +``` + +## Failures and setup corrections + +None. Two shapes from the 0.2.0 record were designed out rather than +re-hit: the fixture's first push carried the armed root commit plus a +baseline commit in one push, so fact gathering always had a parent to read +a base version from (discussion #132); and probe 3's refused merge was +reverted before probe 1, the revert landing as a green "still a dev tree" +no-op, restoring the armed fixture the ceremony then consumed. -- 2.45.2