ceremony/drills/0.4.1.md
cluade-reviewer-andresmgsl 9d816293ee Merge main into release/0.4.1 — carry #191's doors and #194's drill record
The section is re-assembled: main's merge base now carries two fragments
(188.md and 191.md), so 0.4.1 publishes with the door port it actually
ships, and neither fragment survives its own release.

drills/0.4.1.md takes main's two-run record, with run 1's disclosures
restored — the scratch repo it used, its candidate ref, and the ~8 minutes
it spent public to read job logs. A later success does not retire a
disclosed deviation.
2026-08-04 16:00:42 +00:00

125 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 0.4.1 — drill record
Two runs. The first, 2026-08-04 against release PR !190 head `9a229ee`,
**failed**: both doors were inoperable and the release could not publish at
all. The second, after #191 landed as `fda5657`, **passed**. Both are
recorded, because the first is why the second exists.
## Run 2 — against merged `main` `fda5657` (the one that counts)
Where: disposable private repo `heavy-duty/ceremony-drill-0.4.1-final`,
armed at `0.4.1-dev`, carrying the `docs/CONSUMERS.md` release caller, a
fragment-mode fixture, and — unlike run 1 — an **artifact hook** dropping two
deliberately awkward filenames, `drill asset.tgz` and `a&b.tgz`. Archived at
the end; the operator's delete is pending, and cleanup gates nothing.
Candidate ref: `cluade-reviewer-andresmgsl/ceremony@drill-main`, parent
`fda5657`, whose only extra commit rewrites both `CEREMONY_SELF_REF`
carriers to that SHA — `release.yml`'s self-checkout is hardcoded to
`heavy-duty/ceremony`, so only a SHA that resolves there can stand in for a
tag that does not exist yet. No `0.4.1` branch was created on
`heavy-duty/ceremony`.
| # | probe | run | result |
|---|---|---|---|
| 1 | merge-door ceremony | 637 | ✅ exactly one release `0.4.1`; body is the version's own changelog section; tag and release on merge commit `4a83fa1b`; **main re-armed to `0.4.2-dev`**; both assets uploaded |
| 2 | mislabeled ordinary PR | 652 | ✅ green no-op in **7s** on merge commit `e71df4e3` — release count stayed **2**, no tag created |
| 3 | bare version, no `release` label | 638 | ✅ refused at `b091aff2` — release count stayed **1** |
| 4 | re-run of the completed ceremony | 654 | ✅ refused in **8s** on merge commit `82e7d11b` — release count stayed **2**, and tag `0.4.1` **stayed on `4a83fa1b`**, the original merge commit |
| 5 | tag door, matching tag | 639 | ✅ `0.5.0` published with its own section and both assets; **main VERSION untouched** |
| 6 | mismatched tag | 640 | ✅ `9.9.9` refused — release count stayed **2**; the tag exists, the release does not |
Probes 2 and 4 were run last, at 15:2315:28Z, on the same consumer: it was
un-archived for them and archived again at the end. Nothing else about the
run changed — same candidate ref, same caller pin.
**Probe 4 diverges in mechanism, not in what it proves.** The 0.3.0 and 0.4.0
siblings re-ran the completed ceremony's workflow run (GitHub's "attempt 2").
Forgejo 8.0.3 exposes no run-rerun API — there are no `actions/runs/{id}`
routes in its swagger at all — so the ceremony was re-run by reproducing its
input instead: main re-armed to `0.4.1-dev` (setup run 653), then a second
`release`-labeled PR stamping bare `0.4.1` merged on top. That is the same
state the door refuses on, reached by a push rather than a re-trigger, and it
is stricter than the sibling shape in one way — it re-enters through
`facts``decide` rather than replaying a decided run.
Which refusal fired is measurable even without run logs. Replaying the
door's own inputs against the live consumer at `82e7d11b`:
```
facts: ver='0.4.1' base_ver='0.4.1-dev' released='' labeled='yes'
decide: ceremony=yes
```
So `decide` said **go** — a labeled bare transition is row 6 — and the stop
came from the merge door's own pre-publish assert, `release.yml:216-219`,
whose comment names this exact probe ("what makes a re-run of a completed
ceremony refuse instead of clobber"): the tag existed, so it refused before
`forge_tag_create` ever ran. The second net behind it is #191's own verb,
and it reads this consumer correctly:
```
forge_release_exists 0.4.1 -> yes 0.5.0 -> yes 9.9.9 -> no
```
`9.9.9` is the probe-6 receipt in the same breath: the tag exists, the
release does not.
Evidence for every probe here is the run conclusion plus the repository
state before and after — this instance serves no run logs (the API 404s on
every log route), so no probe's result is quoted from a log line.
End state, as observed when this was written: releases `0.4.1` and `0.5.0`
and nothing else; tags `0.4.1` on `4a83fa1b`, `0.5.0` and `9.9.9` on
`b091aff2`; the consumer's `main` left at bare `0.4.1` where probe 4 stopped
it, private and archived.
**The asset names survived intact**: `a&b.tgz` and `drill asset.tgz` both
appear under those exact names on both releases. Before #191's fix the space
made curl reject the URL outright and the `&` split the query — the failure
landing *after* the tag exists, mid-publish, which is the worst place this
door has.
## Run 1 — against `9a229ee`, before the fix (FAILED)
Recorded because the failure is the reason #191 exists — including its
deviations, which no later success retires.
Where: disposable private repo `heavy-duty/ceremony-drill-0.4.1` — a
different consumer from run 2's, archived at the end with the operator's
delete pending. Candidate ref
`cluade-reviewer-andresmgsl/ceremony@drill-0.4.1` (`f148255`), parent
`9a229ee`, its only extra commit rewriting both `CEREMONY_SELF_REF` carriers
to that SHA.
**Deviation, disclosed and not retired by run 2:** run 1's scratch repo was
flipped **public for roughly 8 minutes** to read job logs — Forgejo's web log
route 404s for a token-authenticated private repo and the `/api/v1` log
routes 404 outright — then restored to private and archived. That is a real
departure from `drills/README.md`'s "scratch **private** repo", and it stays
in the record. Run 2 did not repeat it: it read no logs at all, which is why
every run-2 row is a repository-state measurement.
| # | probe | run | result |
|---|---|---|---|
| 1 | merge-door ceremony | 12 (and 7, at `0.4.1`) | ❌ **FAILED**`decide` refused; no tag, no release, main left bare |
| 2 | `-dev` push no-op | 9, and the fixture push | ✅ green no-op, nothing created |
| 3 | bare version, no `release` label | — | ⚠️ not run independently; probe 1 refused through exactly this path, because the label fact read `no` |
| 4 | re-run of a completed ceremony | — | ⚠️ **not reachable** — no ceremony ever completed to re-run |
| 5 | tag door | 14 | ❌ **FAILED**`gh: command not found` at *publish the release*; no release |
| 6 | mismatched tag | 16 | ✅ `tag '9.9.9' does not match the tree's version '0.4.2' — creating nothing` |
Root cause, both doors: `lib/facts.sh` and `release.yml` spoke `gh`, which
the runner image does not ship. `facts.sh` read *any* failure as a definite
`no`, so a missing binary silently demoted a release ceremony to "a bare
push". Release count across the whole of run 1: **0**.
## What changed between them
#191, merged as `fda5657`: both doors onto `lib/forge.sh`; a read that did
not complete refuses instead of fabricating a `no`; `forgejo_api_base`
refuses an empty `REPO` so `repos//…` cannot be addressed; release asset
names percent-encoded.
Every refusal path, in both runs, created nothing. That property never
broke — what broke was the doors' ability to say yes.