forked from heavy-duty/ceremony
272 lines
13 KiB
Markdown
272 lines
13 KiB
Markdown
# 0.6.0 — drill record
|
|
|
|
Run 2026-08-05 by `cndgrr` against the 0.6.0 release PR (Refs #249),
|
|
candidate branch `build/249-release-0-6-0`, canonical candidate SHA
|
|
`fb8f8282a9e7b317d4d028f8e8da50501a882d14`. All six probes ran; every row in
|
|
the table below was written from its own run.
|
|
|
|
## Scope ruling — a full rehearsal is owed, and doors-unchanged is refused
|
|
|
|
This record's shape was measured, not chosen. `drills/README.md` allows the
|
|
doors-unchanged shape only when all three of its conditions hold at the
|
|
candidate head; the first one does not.
|
|
|
|
The baseline is the last **rehearsed** tag, never the previous tag:
|
|
`drills/0.4.1.md` and `drills/0.5.0.md` are both doors-unchanged records, so
|
|
the anchor is **`0.4.0`**, whose record is a full disposable-repo rehearsal,
|
|
whose release is published, and after which `main` was re-armed to
|
|
`0.4.1-dev` (`84bb1a4`). Condition 3 holds.
|
|
|
|
The release path is exactly the output of `.github/scripts/release-path.sh`
|
|
at this head — `.github/workflows/release.yml`, `bin/`, `lib/version.sh`,
|
|
`lib/decide.sh`, `lib/facts.sh`, `lib/changelog.sh`. Condition 2 holds.
|
|
|
|
Condition 1 fails. Measured at this candidate:
|
|
|
|
```console
|
|
$ git diff 0.4.0..HEAD -- $(.github/scripts/release-path.sh)
|
|
.github/workflows/release.yml | 2 +-
|
|
lib/changelog.sh | 83 ++++++++++++++++++++++++++++++++++++++---
|
|
```
|
|
|
|
`release.yml`'s two lines are the `CEREMONY_SELF_REF` pin, which the
|
|
condition exempts. **`lib/changelog.sh` is not exempt and is not empty**: it
|
|
carries `72fa3e0` (the terminal issue-citation rule joining the fragment
|
|
guard, #262) and `75a5b68` (one fragment, one diagnosis, #262). That file is
|
|
on the release path because the merge door sources it to assemble and read
|
|
the release section — this is a door byte, not a neighbouring library, and
|
|
the last-rehearsed anchor exists precisely so an accumulated change like
|
|
this forces a new rehearsal rather than chaining a third doors-unchanged
|
|
assertion off the second.
|
|
|
|
So this release owes the disposable-repo rehearsal, and this record is it.
|
|
|
|
## Where
|
|
|
|
Disposable **private** repo `cndgrr/ceremony-drill-0.6.0`, created
|
|
2026-08-05T00:02:58Z. It carries the `docs/CONSUMERS.md` release caller
|
|
verbatim (`version-source: file`) over a fragment-mode fixture armed at
|
|
`0.6.0-dev`: a preamble-only `CHANGELOG.md`, `changelog.d/README.md` plus
|
|
one fragment, and a non-blank `drills/0.6.0.md`. The `release` label was
|
|
created there before the first ceremony PR, per the guide's prerequisite.
|
|
|
|
**Disposal, as this record's author observed it**: the repository is
|
|
**archived** — `PATCH /repos/cndgrr/ceremony-drill-0.6.0` with
|
|
`archived: true` returned `true`, and a fresh read afterwards reported
|
|
`archived=true private=true`. It is **pending the operator's delete**, which
|
|
this builder cannot perform: `delete_repo` is absent from fleet tokens by
|
|
doctrine (#135). No delete was attempted and none is claimed. Cleanup gates
|
|
nothing — not this PR's ready-for-review, not the panel, not the merge.
|
|
|
|
## Candidate-ref deviation
|
|
|
|
The pure consumer path cannot resolve this candidate's
|
|
`CEREMONY_SELF_REF: "0.6.0"`: that tag is the one this release has not
|
|
created yet. No `0.6.0` branch was created on `heavy-duty/ceremony`.
|
|
|
|
The scratch caller instead pins `cndgrr/ceremony/.github/workflows/release.yml@drill/0.6.0`.
|
|
That fork ref's parent is the canonical candidate SHA
|
|
`fb8f8282a9e7b317d4d028f8e8da50501a882d14`, and its one additional commit
|
|
(`775b4d1f6485ebdde924979ac2dce536643c6071`) rewrites all three
|
|
`CEREMONY_SELF_REF` carriers — `release.yml`, `labels.yml`,
|
|
`labels-sweep.yml` — to that same SHA. All runtime machinery in every probe
|
|
below was therefore fetched from the 0.6.0 candidate tree.
|
|
|
|
Commits pushed to the candidate after `fb8f828` are this record only; the
|
|
release path (`.github/scripts/release-path.sh`) is byte-identical at the
|
|
canonical SHA and at the final head.
|
|
|
|
## Probes
|
|
|
|
One row per probe, written from its run. Runs are in
|
|
`cndgrr/ceremony-drill-0.6.0`.
|
|
|
|
| # | probe | run | result |
|
|
|---|---|---|---|
|
|
| 1 | merge-door ceremony | 30992108742 (attempt 1) | ✅ exactly one `0.6.0` release; tag equals the merge commit; main re-armed to `0.6.1-dev` |
|
|
| 2 | mislabeled ordinary PR | 30991634654 | ✅ green NOTICE no-op; no tag, no release |
|
|
| 3 | bare-version PR without `release` | 30991832001 | ✅ refused at decide; no tag, no release |
|
|
| 4 | re-run completed ceremony | 30992108742 (attempt 2) | ✅ refused at the nothing-exists assert; the release count stayed one |
|
|
| 5 | manual matching tag | 30992258952 | ✅ `0.6.1` published from its own changelog section; main untouched |
|
|
| 6 | mismatched tag | 30992310031 | ✅ refused before publication; no `9.9.9` release, and the probe tag was removed afterwards |
|
|
|
|
### Probe 5 — a manual tag matching its tree
|
|
|
|
Branch `probe5-tag` carried `VERSION` at `0.6.1` and a
|
|
`## 0.6.1 — 2026-08-05` section; tag `0.6.1` was pushed at that commit
|
|
(`dfd0cfeaca772cf45bcb63a1a639829185510c60`) with a personal token, so it
|
|
fired the door — the anti-recursion property probe 1 relies on is exactly
|
|
what makes a hand-pushed tag the only way to reach this door. The
|
|
`release-on-merge` job skipped and `release-on-tag` ran: the version assert
|
|
passed, notes were extracted, the release published.
|
|
|
|
The branch, not main, carried the tagged tree on purpose — the tag door
|
|
takes no bump step, and pointing it at a side branch proves that without a
|
|
bare version ever sitting on main. Observed afterwards: `0.6.1` published
|
|
with exactly its own section's bullet, and main still reading `0.6.1-dev`,
|
|
untouched by the publish. Two releases now exist, `0.6.0` and `0.6.1`,
|
|
neither a draft, neither carrying assets.
|
|
|
|
### Probe 6 — a mismatched tag
|
|
|
|
Tag `9.9.9` was pushed at the same `0.6.1` commit. The door refused at its
|
|
first assert, before notes and before publication:
|
|
|
|
```text
|
|
tag '9.9.9' does not match the tree's version '0.6.1' — creating nothing.
|
|
```
|
|
|
|
Notes, the artifact hook and publish all skipped. `GET /releases` still
|
|
returned exactly `0.6.1` and `0.6.0`. The `9.9.9` ref was deleted afterwards
|
|
(`DELETE /git/refs/tags/9.9.9`); `GET /git/refs/tags` then listed `0.6.0`
|
|
and `0.6.1` only. The probe tag was the operator's artefact, never the
|
|
workflow's — the door created nothing, which is the whole assertion.
|
|
|
|
### Probe 1 — the merge-door ceremony
|
|
|
|
PR #4 (`probe1-ceremony`) bumped `0.6.0-dev` to bare `0.6.0` and stamped
|
|
`## 0.6.0 — 2026-08-05`, assembled from the three fixture fragments by the
|
|
candidate's own `bin/changelog-assemble` and committed with the deletions
|
|
in one commit. The `release` label was applied and confirmed before the
|
|
merge. Facts and verdict:
|
|
|
|
```text
|
|
VER: 0.6.0
|
|
BASE_VER: 0.6.0-dev
|
|
RELEASED:
|
|
LABELED: yes
|
|
ceremony=yes
|
|
```
|
|
|
|
Observed after the run:
|
|
|
|
- **Exactly one** release: `GET /releases` returned `0.6.0` alone, not a
|
|
draft, not a pre-release, zero assets (no artifact hook in the fixture —
|
|
the hook step skipped).
|
|
- `GET /tags` returned `0.6.0` alone, pointing at
|
|
`64d02539f4a20286afc08b9997f0f8a7d1dbfccd`, which is PR #4's merge commit
|
|
— the tag names the tree that was reviewed.
|
|
- The release body was byte-for-byte the assembled section's bullets:
|
|
|
|
```text
|
|
- A second ordinary fragment, written by probe 2 of the 0.6.0 drill (#249).
|
|
- An ordinary behavior change, landing under the release label (#249).
|
|
- Fragment mode is exercised by the ceremony 0.6.0 drill (#249).
|
|
```
|
|
|
|
- Main re-armed itself: commit `2d0e19a` ("bump main to 0.6.1-dev — a dev
|
|
install must not impersonate 0.6.0"), pushed by the job's own token. Main
|
|
reads `0.6.1-dev` and `changelog.d/` holds only `README.md`.
|
|
- **The anti-recursion property held.** Neither the tag create nor the bump
|
|
push started a workflow run — the run list after the ceremony ends at
|
|
30992108742. That is what makes the merge door the release's only chance
|
|
to publish, and it is the reason probe 4 below is the door's own guard
|
|
rather than a second run's.
|
|
|
|
### Probe 4 — a re-run of the completed ceremony
|
|
|
|
Re-running 30992108742 as attempt 2 re-decided `ceremony=yes` — the facts
|
|
at that merge commit have not changed — and then died at the assert:
|
|
|
|
```text
|
|
tag '0.6.0' already exists — this release already happened, or a manual tag won the race; refusing to re-release, creating nothing.
|
|
```
|
|
|
|
Tag, publish and bump all skipped. `GET /releases` still returned exactly
|
|
one `0.6.0`. The refusal is loud (the job is red) and creates nothing, which
|
|
is the required shape: the assert is what covers a manual tag racing the
|
|
merge, not only an operator's stray re-run.
|
|
|
|
### Probe 3 — a bare-version PR without the `release` label
|
|
|
|
PR #3 (`probe3-bare`) bumped `VERSION` to bare `0.6.0` and carried no label;
|
|
the label list was read as empty before merging. The merge run refused at
|
|
decide, row 5 of the table:
|
|
|
|
```text
|
|
VER: 0.6.0
|
|
BASE_VER: 0.6.0-dev
|
|
RELEASED:
|
|
LABELED: no
|
|
the version transitioned ('0.6.0-dev' -> '0.6.0') but no merged, release-labeled PR is behind this commit — a release is a labeled ceremony PR, not a bare push — creating nothing.
|
|
```
|
|
|
|
Notes, the assert, tag, hook, publish and bump all skipped; tags and
|
|
releases were both still empty afterwards. The merge was then undone and
|
|
main re-armed to `0.6.0-dev` before the ceremony probe ran (see Setup).
|
|
|
|
### Probe 2 — a mislabeled ordinary PR
|
|
|
|
PR #2 (`probe2b-mislabeled`) added one changelog fragment and touched no
|
|
version. The `release` label was applied through
|
|
`POST /repos/{owner}/{repo}/issues/2/labels` and confirmed present before
|
|
the merge. The merge run decided row 1 of the table and published nothing:
|
|
|
|
```text
|
|
VER: 0.6.0-dev
|
|
BASE_VER: 0.6.0-dev
|
|
RELEASED:
|
|
LABELED:
|
|
NOTICE: the version '0.6.0-dev' is -dev and unchanged by this PR — release-flow work under the release label, not a ceremony. Nothing to publish.
|
|
ceremony=no
|
|
```
|
|
|
|
`RELEASED` and `LABELED` are empty on purpose — the `-dev` rows never
|
|
consult them, which is precisely why the label alone cannot ship anything.
|
|
Notes, the nothing-exists assert, tag, artifact hook, publish and bump all
|
|
skipped; `GET /tags` and `GET /releases` were both empty afterwards.
|
|
|
|
An earlier merge (PR #1, run 30991571096) was intended as this probe but
|
|
landed **unlabeled**: `gh pr edit --add-label` failed against this repo's
|
|
projects-classic GraphQL surface, and the merge went ahead before the
|
|
failure was read. That run is a green no-op too, but it is not evidence for
|
|
this probe — an unlabeled ordinary merge proves less than a labeled one —
|
|
so the probe was re-run as PR #2 with the label applied through the REST
|
|
endpoint and verified before merging. Recorded here because the run exists
|
|
in the repo's history and a reader will find it.
|
|
|
|
## Setup, and the runs that are not probes
|
|
|
|
The armed fixture was committed before the caller, so the first door run had
|
|
a real parent version to inspect: run **30962040469** is that green baseline
|
|
no-op. The probes then ran in the order 2, 3, 1, 4, 5, 6 — the refusals
|
|
first, against an armed tree, so the ceremony itself ran last against a
|
|
fixture the refusals had already proven intact.
|
|
|
|
Three non-probe runs are on the board and are accounted for here rather than
|
|
left for a reader to guess at:
|
|
|
|
- **30991571096** (green) — PR #1, the unlabeled first attempt at probe 2,
|
|
described above.
|
|
- **30991892212** (green) — restoring `VERSION` to `0.6.0-dev` after probe
|
|
3's refusal, so the ceremony probe met an armed tree. Row 2 of the table:
|
|
the version changed and still ends `-dev`.
|
|
- **30991958967** (red) — **a builder error, not a door finding.** An
|
|
uncommitted `VERSION` bump left over from staging the ceremony branch rode
|
|
along into a setup commit that was meant to touch only the fragments, and
|
|
pushed bare `0.6.0` straight to main. The door refused it exactly as it
|
|
refused probe 3, by the same row-5 path, and created nothing: tags and
|
|
releases were both still empty when the failure was read. Main was re-armed
|
|
to `0.6.0-dev` (green run **30992046247**) before the ceremony probe. It is
|
|
written down because a red run on a drill repo that the record does not
|
|
explain is indistinguishable from a door that failed.
|
|
|
|
The fixture's three fragments were also rewritten mid-setup to carry
|
|
terminal issue citations. The candidate's own `bin/changelog-assemble`
|
|
refused them without one — `fragment 'changelog.d/1.md' has an entry with no
|
|
issue citation` — which is #262's rule, one of the two commits on
|
|
`lib/changelog.sh` that make this release owe a rehearsal at all. The
|
|
fixture had been written before that rule existed. The refusal is the guard
|
|
working; the correction is recorded because the fragments the ceremony
|
|
consumed are not the fragments the repo was created with.
|
|
|
|
## What the rehearsal establishes
|
|
|
|
Both doors ran live against the 0.6.0 candidate's own machinery. The merge
|
|
door published exactly one release from a labeled ceremony PR, tagged the
|
|
reviewed merge commit, and re-armed main itself; it refused a bare push
|
|
without a label, refused a re-run of its own completed ceremony, and stayed
|
|
a green no-op under a label carried by ordinary work. The tag door published
|
|
from a matching manual tag without touching main, and refused a mismatched
|
|
one before creating anything. Every refusal created nothing — no tag, no
|
|
release, on any of the four refusal paths.
|