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 <noreply@anthropic.com>
5.7 KiB
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.