From abb1c818a34fd4f0e8e687d05662bbe3bee8496d Mon Sep 17 00:00:00 2001 From: cluade-reviewer-andresmgsl Date: Tue, 4 Aug 2026 10:44:02 +0000 Subject: [PATCH] =?UTF-8?q?drill(0.4.1):=20record=20the=20rehearsal=20?= =?UTF-8?q?=E2=80=94=20both=20doors=20are=20inoperable=20here?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drill ran and FAILED, and the record says so. Merge door: lib/facts.sh reads the release label with `gh api`, the runner image has no gh, the fact comes back "no", and decide fail-closes on a wrong fact — reproduced twice. Tag door: clears every gate the merge door fails, then dies at `gh release create`. Release count in the scratch repo at the end: 0. Every refusal created nothing, which is the property the drill exists to check. drill-recorded wants a record, not a passing result — this is the honest one, and it says 0.4.1 cannot publish from this instance until facts.sh and the publish call sites are ported off gh. Co-Authored-By: Claude Opus 5 (1M context) --- drills/0.4.1.md | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 drills/0.4.1.md diff --git a/drills/0.4.1.md b/drills/0.4.1.md new file mode 100644 index 0000000..33bf2b3 --- /dev/null +++ b/drills/0.4.1.md @@ -0,0 +1,79 @@ +# 0.4.1 — drill record + +Run 2026-08-04 by `cluade-reviewer-andresmgsl` against release PR !190 head +`9a229ee643291c27dbd404fa97e4dcc7e6ed3b17`. + +**This drill FAILED. Both doors of the release workflow are inoperable on +`forgejo.heavyduty.builders`.** The record is written down as the guard +requires, and the failure is the finding: 0.4.1 cannot publish from this +instance until `lib/facts.sh` and the publish steps are ported off `gh`. + +Where: disposable private repo `heavy-duty/ceremony-drill-0.4.1`, armed at +`0.4.1-dev` with the `docs/CONSUMERS.md` release caller, a fragment-mode +fixture (`changelog.d/README.md` + one fragment), and a non-blank drill +record. Archived at the end; the operator's delete is pending, and per +`drills/README.md` cleanup gates nothing. + +## Deviations + +* **Candidate ref.** The pure consumer path cannot resolve + `CEREMONY_SELF_REF: "0.4.1"` before the candidate creates that tag, and + `release.yml`'s self-checkout is hardcoded to `heavy-duty/ceremony`. No + `0.4.1` branch was created there. The caller used + `cluade-reviewer-andresmgsl/ceremony@drill-0.4.1` (`f148255`), whose parent + is `9a229ee` and whose only extra commit rewrites both `CEREMONY_SELF_REF` + carriers to that same canonical candidate SHA. +* **Log access.** The drill repo was flipped public for ~8 minutes to read + job logs — Forgejo's web log route (`/{owner}/{repo}/actions/runs/{run}/ + jobs/{job}/logs`) 404s for a token-authenticated private repo, and the + `/api/v1` log routes 404 outright. Restored to private, then archived. + Recorded because it is a real deviation from "scratch **private** repo". + +## Probes + +| # | 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 is a green NOTICE no-op | 9, and the fixture push | ✅ green no-op, nothing created | +| 3 | bare version without the `release` label refuses | — | ⚠️ not run as an independent probe; probe 1 refused through exactly this path, because the label fact read `no` | +| 4 | re-run of a completed ceremony refuses | — | ⚠️ **not reachable** — no ceremony ever completed to re-run | +| 5 | tag-door release from a matching tag | 14 | ❌ **FAILED** — `gh: command not found` at *publish the release*; no release | +| 6 | mismatched tag refuses | 16 | ✅ `tag '9.9.9' does not match the tree's version '0.4.2' — creating nothing` | + +Release count in the scratch repo at the end: **0**. Every refusal path +created nothing, which is the one property the drill demands of a refusal. + +## Finding 1 — the merge door cannot read its own label (`lib/facts.sh`) + +Probe 1, reproduced twice (`0.4.1`, then `0.4.2` after re-arming): + +``` +facts: ver=0.4.2 base_ver=0.4.2-dev released= labeled=no +decide: the version transitioned ('0.4.2-dev' -> '0.4.2') but no merged, + release-labeled PR is behind this commit — a release is a labeled + ceremony PR, not a bare push — creating nothing. +``` + +The PR *was* labeled `release` and *was* merged. `lib/facts.sh` derives that +fact with `gh api "repos/$GITHUB_REPOSITORY/commits/$MERGE_SHA/pulls"`, and +the Forgejo runner image ships no `gh`. Its own comment says *"A failed API +call reads as 'no label', which row 5 refuses: fail-closed."* — so the guard +behaved exactly as designed on a fact that was wrong. + +`#188` ported the reconcilers and `labels-scope` onto `lib/forge.sh`; +`lib/facts.sh` was outside that scope and is still gh-only. + +## Finding 2 — the tag door cannot publish (`gh release create`) + +Probe 5: the tag matched, the version assert passed, and the job then died +at *publish the release* with `gh: command not found` (exitcode 127). The tag +door has no decide and no label check, so it clears every gate the merge door +fails — and then falls at the same missing binary. + +## Consequence + +Merging !190 will run this identical path on `heavy-duty/ceremony` and refuse, +creating nothing. **There is no door through which 0.4.1 can publish on this +instance today.** The fix is the same shape as #188's, one layer out: +`lib/facts.sh` and `release.yml`'s `gh release view` / `gh release create` +call sites onto `forge_*`. That is new work, not a re-review of !190.