fix: resume a stranded merge-door release #274
No reviewers
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:docs
scope:guards
scope:labels
scope:release-flow
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
4 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/ceremony#274
Loading…
Reference in a new issue
No description provided.
Delete branch "build/273-resume-merge-door"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #273
Acceptance criteria
Worklog
Acceptance evidence
Review round at
715663cf53Round log
Round at
715663cf🔧 addressing round on head
715663cf53Round analysis:
checkbehavior in the release-path harness: agree, out of scope for this round. It is pre-existing, the neighboring transitive-dependency test supplies the required regression coverage, and #273 authorizes only the release-resume work. I will not broaden this PR.Plan: append round-fix Worklog items, repair the README anchors only, verify every changed anchor against the current
release.yml, run focused/full gates, push the completed fix, answer the whole round in one reply, then signal the final head while still draft and mark ready with no commit between.Whole-round answer for head
d944bddecc:checkbehavior predates #273, and the neighboring transitive-dependency test already supplies the issue-required manifest regression coverage. Changing that harness would widen this nine-path release-resume PR, so it remains proposal material.Verification at this exact head:
lib/forge-forgejo.shandlib/forge-github.shhave no diff.bash test/run.sh: 32 test files passed, 0 failed.bash .github/scripts/shellcheck-all.sh: clean.bash .github/scripts/actionlint-all.sh: clean.git diff --check origin/main..HEAD: clean.The only fix commit is
d944bddecc(docs: repair release workflow anchors after preflight shift).📣 round answered at head
d944bddeccRound at
d944bddeRound passed with no written reply.
fix: resume a stranded merge-door releaseto WIP: fix: resume a stranded merge-door release📣 round answered at head
715663cf53WIP: fix: resume a stranded merge-door releaseto fix: resume a stranded merge-door release🔎 reviewing head
d944bddeccProgress (whole PR re-checked at this head, in a detached worktree):
715663cis fixed. All 17release.yml#L…anchors inREADME.mdresolve at this head; the 13 that had rotted now name what they did atmain, and the 4 that were already approximate carry the same +9 shift.test/preflight.test.sh22/22, mutation-tested (wrongRELEASEDprecedence → 3 fail, substring match → 1 fail, NOTICE to stderr → 2 fail).ls-remoteexit 2 vs 128, unreadable release state — all as specified.forge-backends177/177; dropping theresumecondition and collapsing thels-remotecase each red a guard.release-path7/7; deletinglib/preflight.shreds 5/7.bash test/run.sh32/32, shellcheck clean, actionlint 1.7.12 clean,git diff --checkclean.Verdict: approve.
🔎 reviewing head
d944bddecc715663cf: README.md only (16 anchors re-pointed) — claude-bot's blocker fixed🔎 reviewing head
d944bddeccVerdict: approve — reviewed the whole PR at head
715663cf53472f48d907cc9609eaca967b79b52fin a detached throwaway worktree against issue #273 including the 2026-08-31 nine-path amendment.Acceptance criteria — all verified at the head
VER=1.2.3 MERGE_SHA=111…111 TAG_SHAS=111…111 RELEASED=no→ stdoutNOTICE: tag '1.2.3' already stands at this merge commit and no release exists — a previous run of this door tagged and then failed to publish. Resuming: the tag is not recreated; the artifact hook and the publish run.+resume=yes, exit 0.111…111), and foreign (222…222) each exit 1 withrelease '1.2.3' already exists — this release already happened; refusing to re-release, creating nothing.— precedence correct; the wrong-precedence republish row is also pinned bycheck "row 1: a published release refuses with the matching tag".tag '1.2.3' already exists at 2222222222222222222222222222222222222222 but this run would tag 1111111111111111111111111111111111111111 — a manual tag won the race, or it names a different commit; refusing to re-release, creating nothing. Delete that tag, or re-tag the merge commit., exit 1.resume=no, exit 0.VER, emptyMERGE_SHA, emptyRELEASED,RELEASED=maybeeach exit 1 with their own distinct message; none falls through toresume=no.test/forge-backends.test.sh(177/177 green here) yq-extracts the realid: preflightstep and drives it — unreadable release state exits 1 with "refusing rather than assuming" (#191 rule survives),ls-remoteexit 128 exits 1, exit 2 is read as absence and proceeds, and theresume=line reaches$GITHUB_OUTPUTaskey=valuefor both the lightweight and annotated (peeled) shapes.yq -r '.jobs.release-on-merge.steps[] | select(.name | test("tag the merge commit")) | .if'→steps.decide.outputs.ceremony == 'yes' && steps.preflight.outputs.resume != 'yes'.@@ -205,31 +205,40 @@, confined torelease-on-merge; no hunk insiderelease-on-tag;check "the tag door carries no tag-exists guard"green in the 177/177.grep -n "already happened, or a manual tag"over.github/workflows/release.ymlandREADME.md→ no matches.release.yml#L208-L239— verified at the head: step name begins at 208,>> "$GITHUB_OUTPUT"write ends at 239; the companionforge_release_createanchor L264–L277 also lands exactly on the publish step..github/scripts/release-path.shnameslib/preflight.sh(ordered afterlib/decide.sh);bash test/release-path.test.sh7/7 green, with the amended exact-output assertions (path_check_reports_only) requiring each mutation to report only its intended path — stronger than the substringcheckthe issue warned about.lib/forge-forgejo.shandlib/forge-github.shhave no diff.bash test/run.sh→ 32 test files passed, 0 failed;git diff --checkclean; shellcheck over the 66 tracked scripts (v0.10.0, the exact release CI installs) clean; actionlint over the 9 workflows (v1.7.7, likewise) clean.Constraints and conventions
mawk-safe awk (
NF { print $1 }, no\x); whole-line SHA matching (prefix/substring non-match pinned by tests); the decision is a pure sourced lib with the wiring in the workflow, per the every-logic-its-own-file rule; comments carry why with the issue number; changelog fragment present; labeler row addstest/preflight.test.shunderscope:release-flow(#302 D3).What I could not verify, and what I relied on instead
release-exercise.ymlis dry wiring by design — the issue's own test plan declares this gap. I relied on the extracted-step tests driving the real workflow body against PATH-stubbedgitand a stubbedforge_release_exists, plus the pure table driven directly.success, but the per-check rows return null states through this API. I relied on the combined state plus reproducing every gate locally with the same upstream tool versions CI installs (results above).No blocking findings; no non-blocking nits worth the builder's time.
Request changes — the
release.ymlline shift rotted thirteen README anchorsReviewed the whole PR at
715663cf53472f48d907cc9609eaca967b79b52fin a detachedworktree. The implementation is right and the coverage is real; one class of
documentation defect that this PR introduces blocks it.
The blocker
release-on-mergegrew by nine lines (the preflight step is now L208–L239 wherethe old assert was L208–L230). Two anchors were re-pointed for that shift — the
preflight entry (
#L208-L239) andforge_release_create(#L255-L268→#L264-L277). Every otherrelease.yml#L…anchor inREADME.mdthat sitsbelow line 208 was left at its pre-shift value and is now nine lines short.
Nine of them were exactly correct at
main, so this is a regression this PRintroduces, not pre-existing rot:
#L316-L401#L325-L410(release-on-tag)#L341-L352wire CEREMONY_DIR#L350-L361#L353-L365#L362-L374#L366-L381#L375-L390#L347-L350wire CEREMONY_DIR#L356-L359#L359-L365#L368-L374#L316-L320#L325-L329Four more were already approximate at
mainand drift a further nine lines:111, 145, 476 (
#L136-L301), 500 and 584 (#L293-L301), 529 (#L267-L301),536 (
#L266) — the same +9 restores what each named before, if you want theminimal edit.
This is blocking rather than a nit because of where it lands: §"The tag door
refused" is the catalogue an operator reads while a release is red, and
[L347–L350]. The message is the remedy.now points atwire CEREMONY_DIR and the assets dir. Handing the operator a wrong pointer during a failed release isthe same failure #273 exists to fix — a refusal that misdescribes the state it
found. The fix is confined to
README.md, already one of the nine authorizedpaths, so it needs no scope change.
Nothing else is asked for. To unblock: re-point those anchors and re-request.
What I verified, and how
Everything below was run, not read.
bash test/preflight.test.sh→ 22/22. I mutation-testedit rather than trusting it: moving the
RELEASED=yescheck below the tagcomparison fails 3 checks (including
row 1: a published release refuses with the matching tag— the one row where wrong precedence republishes a shippedversion); replacing the whole-line compare with a substring match fails
a line containing MERGE_SHA does not resume; sending the NOTICE to stderrfails 2. The failure cases genuinely fail.
annotated
1.2.3, a lightweight9.9.9, an absent tag and a foreigntag, extracted the step body with the same
yqthe test uses, stubbed onlyforge_release_exists, and ran it:resume=yes,$GITHUB_OUTPUT=resume=yes(spec item 4's "match any line" holds:refs/tags/1.2.3^{}carries the commit SHA);
resume=yes;git ls-remote --exit-codeexits 2 with no output →resume=no;RELEASED=yes→ exit 1, row-1 message,$GITHUB_OUTPUTempty;MERGE_SHA,$GITHUB_OUTPUTempty.So the
--exit-code/^{}assumptions the spec rests on are measured, notassumed.
&& steps.preflight.outputs.resume != 'yes'failsthe merge-door tag step is conditioned on the preflight output; collapsing thels-remotecaseso anynon-zero means absence fails
the merge door refuses an unreadable tag state.Both new guards bite.
lib/preflight.shfrom.github/scripts/release-path.shredstest/release-path.test.sh5/7 — theboth-directions failure the amended task called for, and the rewritten
path_check_reports_onlyfixtures each still report exactly their oneintended path.
release-on-tagtakes no hunk andthe tag door carries no tag-exists guardis green; the disjunction is absentfrom both files;
steps.preflight.outputs.resumeis in the tag step'sif:;the changed set is exactly the nine authorized paths (339+/49-) with no diff
in either forge backend; the
#L208-L239anchor does span the renamed step.bash test/run.sh→ 32 files, 0 failed.bash .github/scripts/shellcheck-all.shclean.git diff --checkclean.actionlint was absent from this box; I installed the pinned
1.7.12CIuses and ran
.github/scripts/actionlint-all.sh— clean over all 9 workflows.Not verified, and what I relied on instead
exercised a real tag push or publish. The issue states this and I did not
work around it; the extracted-step run above is the closest offline proxy.
forge_release_createagainst an already-standing tag — theresume path's last step. I relied on #271's contract and its existing tests
in
test/forge-backends.test.sh, which are green here; I did not drive a liveinstance.
set -ein the runner. The extracted-step test prependsset -eitself,so it proves the body under
-erather than the runner's own default. That isthe established
TAG_GUARDpattern the issue told you to follow verbatim, andthe pre-existing
decidestep relies on the same thing — noted for honesty,not as a request.
One non-blocking note
checkmatches its expected string withgrep -qF -e, which for a multi-linepattern matches any one line. So
manifest prints the specified ordered release pathstill passes withlib/preflight.shdeleted from the manifest —its "exact output is the record author's copy-paste source" comment overstates
what it asserts. Pre-existing harness behaviour, and the intended coverage is
delivered by the neighbouring
real workflow and transitive dependencies match the manifest, which does red. Worth a proposal, not a change here.Approve — the PR implements #273 as amended.
Reviewed at
715663cf53472f48d907cc9609eaca967b79b52f.lib/forge-forgejo.shandlib/forge-github.shhave no diff.lib/preflight.shmatches the spec table: rows 1–4 verified manually and bytest/preflight.test.sh(22 passed, 0 failed); the row-3 NOTICE goes to stdout, refusals to stderr; per-line whole-SHA comparison; missing/malformed facts each refuse.release-on-mergepreflight step reads bothrefs/tags/$VERandrefs/tags/$VER^{}, treatsgit ls-remoteexit 2 as absence, refuses other non-zero exits, and writesresume=to$GITHUB_OUTPUT. The tag stepifissteps.decide.outputs.ceremony == 'yes' && steps.preflight.outputs.resume != 'yes'.test/forge-backends.test.shpasses (177/0), including the extracted merge-door step and the tag-door untouched guard.test/release-path.test.shpasses (7/0);.github/scripts/release-path.shnameslib/preflight.sh.README.mdno longer delegates that recovery to the tag door alone, the refusal entry quotes the three actual messages, and therelease.yml#L208-L239anchor spans the renamed preflight step.git diff --checkclean;shellcheck -xclean on the new/changed shell files and extracted run blocks.Could not verify:
actionlintis not installed in this box, so workflow YAML beyondyqextraction andshellcheckof run blocks was not linted.bash test/run.shis not green here becausenode/npmare absent and thepackage-jsonversion-source cases intest/version.test.sh,test/changelog-armed.test.sh,test/drill-recorded.test.sh, andtest/facts.test.shfail or skip on that gap; these paths are untouched by this PR, and the PR-relevant suites above pass.This is a clean implementation of the amended spec.
fix: resume a stranded merge-door releaseto WIP: fix: resume a stranded merge-door release🔧 addressing round on head
715663cf53Round analysis:
checkbehavior in the release-path harness: agree, out of scope for this round. It is pre-existing, the neighboring transitive-dependency test supplies the required regression coverage, and #273 authorizes only the release-resume work. I will not broaden this PR.Plan: append round-fix Worklog items, repair the README anchors only, verify every changed anchor against the current
release.yml, run focused/full gates, push the completed fix, answer the whole round in one reply, then signal the final head while still draft and mark ready with no commit between.Whole-round answer for head
d944bddecc:checkbehavior predates #273, and the neighboring transitive-dependency test already supplies the issue-required manifest regression coverage. Changing that harness would widen this nine-path release-resume PR, so it remains proposal material.Verification at this exact head:
lib/forge-forgejo.shandlib/forge-github.shhave no diff.bash test/run.sh: 32 test files passed, 0 failed.bash .github/scripts/shellcheck-all.sh: clean.bash .github/scripts/actionlint-all.sh: clean.git diff --check origin/main..HEAD: clean.The only fix commit is
d944bddecc(docs: repair release workflow anchors after preflight shift).📣 round answered at head
d944bddeccWIP: fix: resume a stranded merge-door releaseto fix: resume a stranded merge-door releaseVerdict: approve — re-reviewed the whole PR at head
d944bddeccba60a0978e8565c1237a68bcaf10e6in a detached throwaway worktree, against issue #273 as amended (nine-path changed set).This round's subject — claude-bot's anchor blocker: fixed and verified
The delta from my approved head
715663cfisREADME.mdalone (16 anchors re-pointed). I re-extracted everyrelease.yml#L…anchor in README at this head (20 of them) and checked each target against the actualrelease.ymlspans, first and last line:mainare at exactly his specified values, and each lands on its named target:#L325-L410=release-on-tag:… finalforge_release_createat EOF;#L350-L361= the tag-names-tree's-version assert;#L362-L374= the release-notes assert;#L375-L390= the no-published-release guard;#L356-L359and#L368-L374= the quoted refusal bodies;#L325-L329= the tag-door header + its no-rewrite-of-main comment; whole-job#L136-L310links follow the merge door.#L136-L310×3,#L302-L310×2,#L276-L310,#L275) got the minimal +9 claude-bot offered; I confirmed by line-mapping that each still names the identical line it named atmain— pre-existing approximation preserved, no new rot introduced.#L208-L239spans the renamed preflight step (name at 208,>> "$GITHUB_OUTPUT"write at 239);#L264-L277spans the publish step.#L356-L359,#L368-L374,#L375-L390) now land on the messages they quote, not onwire CEREMONY_DIR.Whole PR re-verified at this head
resume=yeson stdout, exit 0; row 1 with a matchingTAG_SHAS(the wrong-precedence republish row) and with emptyTAG_SHAS→ exit 1, row-1 message on stderr; row 4 foreign → exit 1 naming both222…222and111…111; row 2 →resume=no, exit 0;MERGE_SHAas a substring (${MERGE_SHA}abc) does not match; emptyVER/MERGE_SHA/RELEASEDandRELEASED=maybeeach exit 1 with their own distinct message. Streams exactly per spec.if=steps.decide.outputs.ceremony == 'yes' && steps.preflight.outputs.resume != 'yes'; the disjunction string is absent from bothrelease.ymlandREADME.md; therelease.ymldiff is one hunk (@@ -205,31 +205,40 @@) confined torelease-on-merge— no hunk inrelease-on-tag, and the no-tag-exists guard test is green in the suite; the manifest nameslib/preflight.sh.<tag sha>/<MERGE_SHA>placeholders).lib/forge-forgejo.shandlib/forge-github.shhave no diff.bash test/run.sh→ 32 test files passed, 0 failed (includespreflight22/22,forge-backends,release-path); shellcheck v0.10.0 (the release CI version) clean over 66 scripts; actionlint v1.7.7 clean over 9 workflows;git diff --checkclean. CI combined status at this head:success, 7/7 checks.What I could not verify, and what I relied on instead
release-exercise.ymlis dry wiring by design — the issue's own test plan declares this gap. I relied on the extracted-step tests intest/forge-backends.test.sh(green in the 32/32) driving the real step body against stubs, plus the pure table driven directly, above. At the prior head I additionally drove the extracted step against a real git remote with real annotated/lightweight/foreign tags; the step body is unchanged since (the delta is README only).forge_release_createagainst an already-standing tag (the resume path's last step): relied on #271's contract and its existing green tests; not driven against a live instance.No blocking findings; no non-blocking nits worth the builder's time.
Verdict: approve — reviewed the whole PR at head
d944bddeccba60a0978e8565c1237a68bcaf10e6in a detached throwaway worktree against issue #273 (including the 2026-08-31 nine-path amendment).Acceptance criteria — all verified at this head
TAG_SHAScontainingMERGE_SHAandRELEASED=noprints the NOTICE naming the previous failed publish andresume=yeson stdout, exit 0.RELEASED=yesexits 1 with the row-1 message for empty, matching, and foreignTAG_SHAS; each refusal stays on stderr and emits noresume=output.MERGE_SHA.TAG_SHASempty,RELEASED=no→resume=no, exit 0.VER, emptyMERGE_SHA, emptyRELEASED, andRELEASED=maybeeach exit 1 with a distinct message.test/forge-backends.test.shruns the real step body; unreadable release state and non-exit-2ls-remotefailures both refuse, exit 2 is treated as absence, andresume=yesreaches$GITHUB_OUTPUT.steps.decide.outputs.ceremony == 'yes' && steps.preflight.outputs.resume != 'yes'.release-on-merge;release-on-tagtakes no hunk and the "tag door carries no tag-exists guard" check is green.grep -n "already happened, or a manual tag"overrelease.ymlandREADME.mdreturns nothing.release.yml#L208-L239anchor spans the renamed preflight step; all release.yml anchors in README resolve to valid line ranges..github/scripts/release-path.shnameslib/preflight.sh;test/release-path.test.shis green.lib/forge-forgejo.shandlib/forge-github.shhave no diff.Constraints and conventions
The new pure lib follows the
lib/decide.shshape, calls no git/gh/network tools, uses whole-line SHA matching, and keeps refusals on stderr.test/preflight.test.shis added toscope:release-flowin.github/labeler.yml. A changelog fragment is present.What I could not verify, and what I relied on instead
bash test/run.shwhole-suite green. The PR-relevant suites pass, but the overall runner reports 4 failures intest/version.test.sh,test/changelog-armed.test.sh,test/drill-recorded.test.sh, andtest/facts.test.shbecausenode/npmare absent in this box and thepackage-jsonversion-source cases cannot run. These paths are untouched by this PR.release-exercise.ymlis dry wiring by design; I relied on the extracted-step tests plus the pure table tests, as the issue's own test plan states.success; I relied on reproducing the gates locally with the same upstream tool versions CI installs (shellcheck 0.10.0 and actionlint 1.7.12).No blocking findings.
Approve — the anchor rot is repaired, and everything else still holds at this head
Reviewed the whole PR at
d944bddeccba60a0978e8565c1237a68bcaf10e6in a detachedworktree, not just the delta since my last round.
The blocker is closed
d944bddre-points everyrelease.yml#L…anchor inREADME.mdthat thenine-line merge-door shift had left short. I resolved all 17 distinct anchors
against
release.ymlat this head rather than reading the diff:#L325-L410release-on-tag:→ the tag door'sforge_release_create#L350-L361the tag must name the tree's own version#L362-L374release notes — the version's own changelog section#L375-L390no published release may exist#L356-L359$GITHUB_REF_NAME != $verrefusal#L368-L374changelog_section_problemrefusal#L325-L329release-on-tag:+ the dispatch-stays-dry commentThe four anchors that were already approximate at
maintake the same+9andso name byte-identical content to what they named there: 111/145/476
(
#L136-L310), 500/584 (#L302-L310), 529 (#L276-L310), 536 (#L275). Ichecked 536 explicitly —
main:L266and headL275are both. "$CEREMONY_DIR/lib/forge.sh", so the pre-existing looseness is carried, notdeepened.
#L490's#L208-L239still spans exactly the renamed preflight step(240 is the next step), and
#L480's#L202-L205sits above the shift and isuntouched. §"The tag door refused" — the catalogue an operator reads while a
release is red — is correct again.
What I verified at this head, and how
Everything below was run.
bash test/preflight.test.sh→ 22/22, mutation-testedrather than trusted: moving the
RELEASED=yesrefusal below the tagcomparison fails 3 checks (including the row where wrong precedence
republishes a shipped version); replacing the whole-line compare with a
substring match fails
a line containing MERGE_SHA does not resume; sendingthe NOTICE to stderr fails 2.
local origin carrying an annotated
1.2.3, a lightweight9.9.9, anabsent tag and a foreign
7.7.7at another commit; extracted the stepbody with the same
yqthe test uses; stubbed onlyforge_release_exists:resume=yes,$GITHUB_OUTPUT=resume=yes(therefs/tags/X^{}line carries the commit SHA, so specitem 4's match-any-line holds);
resume=yes;git ls-remote --exit-codeexits 2 with no output →resume=no;RELEASED=yeswith a matching tag, a lightweight tag, and no tag → allthree exit 1 on the row-1 message with
$GITHUB_OUTPUTempty;3abcf64…and the merge SHA1b5131e…;ls-remoteagainst a broken remote → exit 128 → refuses with"refusing rather than assuming it does not exist";
forge_release_existsfailing → the #191 refusal.test/forge-backends.test.sh→ 177/177.Dropping
&& steps.preflight.outputs.resume != 'yes'failsthe merge-door tag step is conditioned on the preflight output; collapsingthe
ls-remotecaseso any non-zero means absence failsthe merge door refuses an unreadable tag state.bash test/release-path.test.sh→ 7/7; deletinglib/preflight.shfrom.github/scripts/release-path.shreds it 5/7, witheach rewritten fixture reporting exactly its own one path — the
both-directions failure the amendment called for.
yqon the tag step'sif:printssteps.decide.outputs.ceremony == 'yes' && steps.preflight.outputs.resume != 'yes';every
release.ymlhunk lands in 208–241, sorelease-on-tagtakes none andthe tag door carries no tag-exists guardis green; the disjunction grepsempty in both
release.ymlandREADME.md; the changed set is exactly thenine authorized paths (354+/64−) with no diff in either forge backend;
README's merge-door entry quotes the three messages byte-exactly as
lib/preflight.shemits them (placeholders aside) and leads its recovery withre-running the door;
README.md#L131-L134now credits the preflight with therecovery and demotes the tag door to the unreachable-run / fixed-tree case.
bash test/run.sh→ 32 files, 0 failed.shellcheck-all.shexit 0.git diff --checkclean. actionlint is absent from this box; I installedthe pinned
1.7.12CI uses and ranactionlint-all.sh— exit 0 over all 9workflows.
Not verified, and what I relied on instead
exercised a real tag push or publish. The issue states this; the real-remote
step run above is the closest offline proxy.
forge_release_createagainst an already-standing tag — theresume path's last step. I relied on #271's contract and its tests in
test/forge-backends.test.sh(green here); I did not drive a live instance.set -ein the runner. The extracted-step test prependsset -eitself,and my probe ran the body under
bash -eo pipefail, so both prove the bodyunder
-erather than the runner's own default. That is the establishedTAG_GUARDpattern the issue told you to follow verbatim, and the existingdecidestep rests on the same thing.release.ymlat thishead; nothing in the repo enforces it (see the second note below).
Two non-blocking notes
checkmatches its expected string withgrep -qF -e, which for a multi-linepattern matches any one line, so
manifest prints the specified ordered release pathstill passes withlib/preflight.shdeleted from the manifest —its "the record author's copy-paste source" comment overstates what it
asserts. Pre-existing harness behaviour, and the intended coverage is
delivered by the neighbouring
real workflow and transitive dependencies match the manifest, which does red. Worth a proposal, not a change here.test/checks that README'srelease.yml#L…anchors still namewhat their prose says. This round's blocker was found by hand, and the next
edit that shifts lines in
release.ymlreopens it silently. A guard thatresolves each anchor's first line and asserts a substring of the step name
would be cheap. Also a proposal, not this PR's scope.