From ff00a9cbcd35059e5265ef620fbb15fc338a06c2 Mon Sep 17 00:00:00 2001 From: claude-bot-andresmgsl Date: Wed, 22 Jul 2026 23:27:56 +0000 Subject: [PATCH 1/2] release: 0.1.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ceremony PR — two edits, per the amended #11: VERSION 0.1.0-dev -> 0.1.0, and the changelog stamp with the re-arm in the same edit (## Unreleased -> ## 0.1.0 — 2026-07-22, an empty ## Unreleased put back on top — box#108). No third stamp: both CEREMONY_SELF_REF carriers already read "0.1.0", and self-ref-check's bare-tree rule wants exactly that. drills/0.1.0.md follows once the rehearsal runs. Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 2 ++ VERSION | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08cdae3..02c415e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ so entries say what changed, cite the issue, and stop. ## Unreleased +## 0.1.0 — 2026-07-22 + - `lib/version.sh` — one version abstraction, `file` and `package-json` backends (#3). - `lib/changelog.sh` + `bin/changelog-section` — the one canonical changelog-section extractor (#4). - `actions/changelog-armed` — the version-keyed arming guard (#5). diff --git a/VERSION b/VERSION index 0d4d124..6e8bf73 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.0-dev +0.1.0 From af485819736844322e18029ee0a141217686b3a8 Mon Sep 17 00:00:00 2001 From: claude-bot-andresmgsl Date: Wed, 22 Jul 2026 23:40:38 +0000 Subject: [PATCH 2/2] drill: the 0.1.0 record, and the first-release caveat in the doctrine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drills/0.1.0.md — six probes plus (g), run on the disposable scratch repo against the candidate SHA, every refusal checked for droppings; the pin deviation (fork ref, CEREMONY_SELF_REF -> candidate SHA in both carriers) recorded under its own heading per triage's ruling on #11. drills/README.md gains the first-release caveat that ruling asked for: the first drill can never take the pure pinned consumer path, and must not fix that by putting a tag-shaped branch in the canonical ref namespace. Co-Authored-By: Claude Fable 5 --- drills/0.1.0.md | 103 +++++++++++++++++++++++++++++++++++++++++++++++ drills/README.md | 11 +++++ 2 files changed, 114 insertions(+) create mode 100644 drills/0.1.0.md diff --git a/drills/0.1.0.md b/drills/0.1.0.md new file mode 100644 index 0000000..dbf6be0 --- /dev/null +++ b/drills/0.1.0.md @@ -0,0 +1,103 @@ +# 0.1.0 — drill record + +Run 2026-07-22, by `claude-bot-andresmgsl`, against the release candidate +`heavy-duty/ceremony@dbf857a94a7c4b068962efbccc996b41c5e4ab89` (main at the +time — the ceremony PR adds only `VERSION`, the changelog stamp, this record, +and a doctrine caveat; no machinery differs between the drilled tree and the +released one). + +Where: scratch private repo `claude-bot-andresmgsl/ceremony-drill-0.1.0`, +carrying the `docs/CONSUMERS.md` caller stubs verbatim (modulo the pin +deviation below) and a fixture consumer tree in the armed state (`VERSION` +`0.1.0-dev`, `## Unreleased` on top, `drills/`). Deleted after this record +was written, per `drills/README.md`: the repo is the evidence's scaffolding, +this file is the evidence. Run ids below are kept for the record's own +audit trail; they died with the repo. + +## The deviation: the first release cannot take the pure consumer path + +`CEREMONY_SELF_REF` is `"0.1.0"` — the ref this drill exists to rehearse +creating. Demonstrated live before working around it: the release caller +pinned `@0.1.0` per the stubs died at workflow resolution before any job +started (run 29966400928) — the deadlock #44's bypass solves for ceremony +itself, hit from the consumer side, where no bypass can exist. + +Ruled on #11 by triage: **no `0.1.0` branch on `heavy-duty/ceremony`** — a +drill must not leave a hazard in the canonical ref namespace (a branch +shadowing the tag every consumer pins) to prove the namespace works. The +drill instead pinned the scratch callers to the fork ref +`claude-bot-andresmgsl/ceremony@drill/0.1.0`: the candidate tree with +exactly one line changed per pin carrier (`release.yml` and `labels.yml`, +both — `self-ref-check.sh` requires the carriers to agree), +`CEREMONY_SELF_REF: "0.1.0"` → `"dbf857a94a7c4b068962efbccc996b41c5e4ab89"`. +Every `.ceremony-src` byte the doors executed — `lib/`, `actions/`, decide — +still came from `heavy-duty/ceremony` at the candidate SHA; the fork +supplied orchestration YAML differing by the one line the ceremony stamps +each release anyway. From `0.2.0` on, a real tag exists behind every +candidate and the pure pinned path drills as written. + +## The probes + +| # | probe | run | result | +|---|---|---|---| +| a | merge-door ceremony | 29966647167 (attempt 1) | ✅ exactly one release | +| b | mislabeled ordinary PR | 29966530098 | ✅ green NOTICE no-op | +| c | bare-version PR, no label | 29966562846 | ✅ refused, red, created nothing | +| d | re-run of the completed ceremony | 29966647167 (attempt 2) | ✅ refused, red, created nothing | +| e | tag door, manual matching tag | 29966718335 | ✅ published, no bump | +| f | tag door, mismatched tag | 29966744675 | ✅ refused, red, created nothing | +| g | labels bootstrap from nothing | 29966488038 | ✅ taxonomy created | + +**(a) The ceremony.** PR `release: 0.1.0` — hand-set `release` label, +`VERSION` `0.1.0-dev` → `0.1.0`, changelog stamped `## 0.1.0 — 2026-07-22` +with an empty `## Unreleased` re-armed above it. Merged. The one run: +facts `ver='0.1.0' base_ver='0.1.0-dev' labeled='yes'` → `ceremony=yes` → +tag `0.1.0` created on the merge commit (verified equal to the PR's merge +SHA), release `0.1.0` published with the fixture changelog section — +verbatim — as its body, and main re-armed to `0.1.1-dev` by the run itself. +The GITHUB_TOKEN tag create and bump push fired **no** second run +(anti-recursion held: the run list gained nothing after the merge run). + +**(b) Mislabeled ordinary PR.** README-only PR wearing the `release` label. +Green: `NOTICE: the version '0.1.0-dev' is -dev and unchanged by this PR — +release-flow work under the release label, not a ceremony. Nothing to +publish.` No tag, no release. + +**(c) Bare-version PR without the label.** The ceremony's two edits, label +deliberately absent. Red at decide: `the version transitioned ('0.1.0-dev' +-> '0.1.0') but no merged, release-labeled PR is behind this commit — a +release is a labeled ceremony PR, not a bare push — creating nothing.` No +tag, no release; main reverted to the armed state afterwards (the revert +push itself ran green as a no-op, as it should). + +**(d) Re-run of the completed ceremony.** Re-ran (a)'s run. Red at the +nothing-may-exist assert: `tag '0.1.0' already exists — this release +already happened, or a manual tag won the race; refusing to re-release, +creating nothing.` Release count still exactly one. + +**(e) Tag door.** Branch with `VERSION` `0.2.0` and its stamped section; +manual `0.2.0` tag pushed at its head (never merged to main). The tag door +published release `0.2.0` with that section as its body; the merge door +correctly skipped. Main untouched: `VERSION` stayed `0.1.1-dev` — the +fallback does not rewrite main. + +**(f) Mismatched tag.** Tag `9.9.9` pushed at main (tree version +`0.1.1-dev`). Red: `tag '9.9.9' does not match the tree's version +'0.1.1-dev' — creating nothing.` No release, and the operator-facing +remediation text printed as designed. + +**(g) Labels bootstrap from nothing** (moved into the drill by triage on +#11 — ceremony's own taxonomy already exists, so the scratch repo is the +only honest place left to exercise the path every fresh consumer hits +first). `workflow_dispatch` of the scratch labels caller: the reconcile job +took the consumer path (`.ceremony-src` fetched at the candidate SHA), +`bootstrap=yes`, and created the full taxonomy — state, blocker, +work-queue, `release` — plus the consumer-owned `scope:fixture` row from +`labels.conf`, on a repo that had only GitHub's defaults. Subsequent +PR-event runs reconciled without re-upserting, as documented. + +## Failures + +None. Six probes plus (g) behaved exactly as specified, and every refusal +path was checked for droppings — no tag and no release exists that a +refusal created. diff --git a/drills/README.md b/drills/README.md index 6382139..cbbe0d0 100644 --- a/drills/README.md +++ b/drills/README.md @@ -15,6 +15,17 @@ drill is where they run live *before* a version rests on them. 2. Install the docs/CONSUMERS.md caller stubs, pinned to the release candidate ref. A branch ref works: refs are static identifiers — the family's own drill doctrine. + + **Except for the first release** (learned drilling 0.1.0, #11): the + stubs' consumer path fetches ceremony at `CEREMONY_SELF_REF` — the very + ref the first drill exists to rehearse creating — so the pure pinned + path cannot run before some `X.Y.Z` ref exists, and a branch named like + the tag must NOT be created on the canonical repo to paper over it (it + would shadow the tag for every consumer until someone remembers to + delete it). The first drill instead pins the callers to a fork ref + carrying the candidate tree with `CEREMONY_SELF_REF` rewritten to the + candidate SHA in every pin carrier, and records that one-line deviation + in its record. From the second release on, this paragraph is moot. 3. Give it a fixture `VERSION` / `CHANGELOG.md` / `drills/` in the armed state (`X.Y.Z-dev`, `## Unreleased` on top). 4. Exercise both doors, one probe at a time: