release: record the 0.2.0 drill — six probes on a fragment-shaped scratch consumer
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
682b9cb892
commit
c0df9f436d
1 changed files with 119 additions and 0 deletions
119
drills/0.2.0.md
Normal file
119
drills/0.2.0.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
# 0.2.0 — drill record
|
||||
|
||||
Run 2026-07-24, by `claude-bot-andresmgsl`, against the release candidate
|
||||
`heavy-duty/ceremony@682b9cb8929aa8c50a3101b64ca57fee7b09fef1` (PR #129's
|
||||
head at drill time — the ceremony PR adds only `VERSION`, the assembled
|
||||
section with its fragment deletions, the self-ref stamps, and this record;
|
||||
no machinery differs between the drilled tree and the released one).
|
||||
|
||||
Where: scratch private repo `claude-bot-andresmgsl/ceremony-drill-0.2.0`,
|
||||
carrying the `docs/CONSUMERS.md` caller stubs (modulo the pin deviation
|
||||
below) and a fixture consumer tree in the **fragment shape** this release
|
||||
exists to ship: `VERSION` `0.5.0-dev`, `CHANGELOG.md` preamble plus a
|
||||
shipped `## 0.4.0` section, `changelog.d/` with its `README.md` marker and
|
||||
two fragments, `drills/`, and the five guard actions in CI at the drill
|
||||
ref. Archived after this record was written; deletion needs the
|
||||
`delete_repo` scope this box's token deliberately lacks, so the operator
|
||||
owns the final delete — the repo is the evidence's scaffolding, this file
|
||||
is the evidence. Run ids below are kept for the record's own audit trail.
|
||||
|
||||
## The deviation: the self-drill deadlock recurs past the first release
|
||||
|
||||
The spec (#118) expected the 0.1.0 record's fork deviation to be moot —
|
||||
"`0.1.0` exists, so the pinned path runs straight." It does not, for
|
||||
ceremony's *own* drill: the candidate tree pins
|
||||
`CEREMONY_SELF_REF: "0.2.0"` — the very stamp this PR makes — and the
|
||||
consumer path checks out `heavy-duty/ceremony` at exactly that ref, which
|
||||
cannot exist before the merge. What `0.1.0` existing does make moot is the
|
||||
*consumer-side* deadlock: a governed repo drilling its own release pins
|
||||
ceremony at a real tag and runs straight. Raised on #118 before drilling;
|
||||
proceeded per the deviation triage already ruled for #11, unchanged in
|
||||
shape: **no `0.2.0`-named ref on the canonical repo**; the scratch callers
|
||||
pin the fork ref `claude-bot-andresmgsl/ceremony@drill/0.2.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.2.0"` →
|
||||
`"682b9cb8929aa8c50a3101b64ca57fee7b09fef1"`. Every `.ceremony-src` byte
|
||||
the doors executed still came from `heavy-duty/ceremony` at the candidate
|
||||
SHA (reachable there via PR #129's pull ref); the fork supplied
|
||||
orchestration YAML differing by the one line the ceremony stamps each
|
||||
release anyway. Drilling against `0.1.0` instead would not have been a
|
||||
drill of the candidate: `lib/changelog.sh`, which both doors source for
|
||||
notes extraction, is +214 lines since `0.1.0` (fragment mode; #98).
|
||||
|
||||
## The probes
|
||||
|
||||
| # | probe | run | result |
|
||||
|---|---|---|---|
|
||||
| a | merge-door ceremony, fragment shape | 30089779736 (attempt 1) | ✅ exactly one release |
|
||||
| b | mislabeled ordinary PR | 30089842547 | ✅ green NOTICE no-op |
|
||||
| c | bare-version PR, no label | 30089908740 | ✅ refused, red, created nothing |
|
||||
| d | re-run of the completed ceremony | 30089779736 (attempt 2) | ✅ refused, red, created nothing |
|
||||
| e | tag door, manual matching tag | 30090053523 | ✅ published, no bump |
|
||||
| f | tag door, mismatched tag | 30090082676 | ✅ refused, red, created nothing |
|
||||
|
||||
**(a) The ceremony, in fragment shape.** PR `release: 0.5.0` — hand-set
|
||||
`release` label, `VERSION` `0.5.0-dev` → `0.5.0`, and the stamp made by
|
||||
the candidate's own `bin/changelog-assemble 0.5.0`: two fragments folded
|
||||
into `## 0.5.0 — 2026-07-24` (newest issue first), deleted in the same
|
||||
commit, `changelog.d/` left holding only its `README.md` marker — no
|
||||
re-arm edit, armed by existing. The five guard actions at the drill ref —
|
||||
`changelog-armed`, `changelog-monotonic`, `changelog-assembled`,
|
||||
`drill-recorded`, `runner-isolated` — all green on that PR (run
|
||||
30089703224): the assembled guard replayed the assembly from the merge
|
||||
base and matched it byte-for-byte, live, on the mechanism this release
|
||||
ships. Merged. The one run: facts
|
||||
`ver='0.5.0' base_ver='0.5.0-dev' labeled='yes'` → `ceremony=yes` → tag
|
||||
`0.5.0` on the merge commit (`9b9e58e`), release `0.5.0` published with
|
||||
the assembled section — verbatim, both bullets — as its body, and main
|
||||
re-armed to `0.5.1-dev` by the run itself. The GITHUB_TOKEN tag create
|
||||
and bump push fired **no** second run (anti-recursion held).
|
||||
|
||||
**(b) Mislabeled ordinary PR.** Docs-only PR wearing the `release` label.
|
||||
Green: `NOTICE: the version '0.5.1-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 edits —
|
||||
`0.5.1-dev` → `0.5.1`, a section assembled from a fragment — label
|
||||
deliberately absent. Red at decide:
|
||||
`the version transitioned ('0.5.1-dev' -> '0.5.1') 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, and the revert push itself ran
|
||||
green as a no-op (run 30090017774), as it should.
|
||||
|
||||
**(d) Re-run of the completed ceremony.** Re-ran (a)'s run. Red at the
|
||||
nothing-may-exist assert:
|
||||
`tag '0.5.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.6.0` and its section assembled
|
||||
from a fragment; manual `0.6.0` tag pushed at its head (never merged to
|
||||
main). The tag door published release `0.6.0` with that section as its
|
||||
body; the merge door correctly skipped. Main untouched: `VERSION` stayed
|
||||
`0.5.1-dev` — the fallback does not rewrite main.
|
||||
|
||||
**(f) Mismatched tag.** Tag `9.9.9` pushed at main (tree version
|
||||
`0.5.1-dev`). Red:
|
||||
`tag '9.9.9' does not match the tree's version '0.5.1-dev' — creating
|
||||
nothing.` No release, and the operator-facing remediation text printed as
|
||||
designed.
|
||||
|
||||
## Failures
|
||||
|
||||
None among the probes; every refusal path was checked for droppings — the
|
||||
only releases and workflow-created tags that exist are (a)'s and (e)'s.
|
||||
|
||||
One finding outside the probe set, written down plainly: the fixture's
|
||||
**initial push** — the very first commit of the scratch repo, caller
|
||||
included — ran the merge door red (run 30089682128): `lib/facts.sh`
|
||||
resolves the base as `MERGE_SHA^1` when `event.before` is all-zeros, and
|
||||
a repo's first commit has no parent, so `git rev-parse` fails loudly
|
||||
(exit 128) before deciding. Nothing was created, and every subsequent
|
||||
push behaved; but a greenfield consumer bootstrapping caller-first will
|
||||
meet one red run on its first push, which the doctrine's "every
|
||||
legitimate non-ceremony is a green NOTICE no-op" does not intend.
|
||||
`facts.sh` is unchanged since `0.1.0` — not a candidate regression, not a
|
||||
blocker for this release; escalated as a discussion, not fixed here.
|
||||
Loading…
Reference in a new issue