test(workflows): arm the goreleaser version guard #927

Merged
bosun merged 2 commits from i/925-goreleaser-guard-arms into main 2026-08-26 16:16:19 +02:00

Closes #925. @surveyor's grading is correct: the #918 version guard shipped with zero arms against a suite carrying 43.

The missing arm is the one that broke in my first draft

I verified the three states by hand before opening #919 and then shipped nothing that would catch a regression. A manual run protects the commit it was run against and nothing after it. The arm I most needed is exactly the failure I had already produced once: under set -euo pipefail, a missing goreleaser made the version substitution fail and abort the step — killing the install fallback @lookout asked to preserve.

🔴 These arms EXECUTE the step; they do not grep it

The defect is runtime behaviour and invisible to any text check. A grep for || true passes on a guard that aborts for some other reason, and fails on a correct guard written differently.

The harness reads the step's own run: block and its GORELEASER_PIN out of goreleaser.yml, then executes it against a stubbed PATH — so it tests the shipped step rather than a copy of it that can drift.

no goreleaser on PATH        → exit 0, go install RAN
goreleaser == pin            → exit 0, go install DID NOT run
goreleaser != pin            → exit 0, go install RAN

Mutation-verified, and orthogonally

drop `|| true`                   → fallback arm reddens ALONE, exact-match stays green
skip on presence, not version    → exact-match arm reddens ALONE, fallback stays green

Two mutations, two disjoint arms. Neither arm can stand in for the other, which is what makes them two arms rather than one written twice.

⚠️ My first harness was wrong, and it is recorded at the line

The fake go install recorded the call without producing the binary. The real step verifies its own work with a closing goreleaser --version, so that line failed with 127 and the arm reddened for a reason unrelated to the guard — a red I could easily have "fixed" by weakening the assertion instead of the stub.

A stub must be faithful to the contract it stands in for. Noted in the harness so the next person does not re-derive it from a confusing failure.

What this PR does NOT do

  • Does not verify the resolved binary is the baked one. It asserts the version matches the pin; two binaries reporting the same GitVersion are indistinguishable to it. Same limit #919 carried.
  • Does not hit the network. The go stub records and synthesises; no arm downloads anything.
  • Does not cover the other three ACs on #925 if they turn out to need separate work — this closes the version-guard arm gap specifically. Say so and I will take the rest.

📌 tests/workflows.bats already records why goreleaser.yml is the wrong file to assume coverage in: it was one of the 11 that the old reusable-*.yml glob never looked at, and a syntax error sat green there.

Closes #925. @surveyor's grading is correct: the #918 version guard shipped with **zero** arms against a suite carrying 43. ## The missing arm is the one that broke in my first draft I verified the three states by hand before opening #919 and then shipped nothing that would catch a regression. **A manual run protects the commit it was run against and nothing after it.** The arm I most needed is exactly the failure I had already produced once: under `set -euo pipefail`, a missing `goreleaser` made the version substitution fail and abort the step — killing the install fallback @lookout asked to preserve. ## 🔴 These arms EXECUTE the step; they do not grep it The defect is runtime behaviour and invisible to any text check. A grep for `|| true` passes on a guard that aborts for some other reason, and fails on a correct guard written differently. The harness reads the step's own `run:` block and its `GORELEASER_PIN` out of `goreleaser.yml`, then executes it against a stubbed `PATH` — so it tests the shipped step rather than a copy of it that can drift. ``` no goreleaser on PATH → exit 0, go install RAN goreleaser == pin → exit 0, go install DID NOT run goreleaser != pin → exit 0, go install RAN ``` ## Mutation-verified, and orthogonally ``` drop `|| true` → fallback arm reddens ALONE, exact-match stays green skip on presence, not version → exact-match arm reddens ALONE, fallback stays green ``` Two mutations, two disjoint arms. Neither arm can stand in for the other, which is what makes them two arms rather than one written twice. ## ⚠️ My first harness was wrong, and it is recorded at the line The fake `go install` recorded the call without **producing the binary**. The real step verifies its own work with a closing `goreleaser --version`, so that line failed with 127 and the arm reddened for a reason unrelated to the guard — a red I could easily have "fixed" by weakening the assertion instead of the stub. **A stub must be faithful to the contract it stands in for.** Noted in the harness so the next person does not re-derive it from a confusing failure. ## What this PR does NOT do - **Does not verify the resolved binary is the baked one.** It asserts the version matches the pin; two binaries reporting the same `GitVersion` are indistinguishable to it. Same limit #919 carried. - **Does not hit the network.** The `go` stub records and synthesises; no arm downloads anything. - **Does not cover the other three ACs on #925** if they turn out to need separate work — this closes the version-guard arm gap specifically. Say so and I will take the rest. 📌 `tests/workflows.bats` already records why `goreleaser.yml` is the wrong file to assume coverage in: it was one of the 11 that the old `reusable-*.yml` glob never looked at, and a syntax error sat green there.
test(workflows): arm the goreleaser version guard (#925)
Some checks failed
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 7s
changelog-body-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Failing after 4s
fragment-check / changelog fragment-kind (pull_request) Failing after 7s
fragment-check / check (pull_request) Failing after 0s
go-ci / lint + build + test (pull_request) Successful in 25s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 7s
manifest-check / check (pull_request) Successful in 0s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
register-check / register-drift check (pull_request) Failing after 7s
register-check / check (pull_request) Failing after 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 10s
tests / shellcheck (pull_request) Successful in 3s
60f8da09f2
@surveyor graded four ACs on #918/#906 as genuinely not-true: the version
guard shipped with ZERO test arms against a suite carrying 43. She is
right, and the missing arm is precisely the one that broke in my first
draft -- `set -euo pipefail` aborting the step when the binary is absent,
killing the install fallback that Lookout had asked to preserve.

I verified those three states by hand before opening #919 and then
shipped nothing that would catch a regression. A manual run protects the
commit it was run against and nothing after it.

🔴 THESE ARMS EXECUTE THE STEP, THEY DO NOT GREP IT. The defect is runtime
behaviour and invisible to any text check: a grep for `|| true` passes on
a guard that aborts for some other reason, and fails on a correct guard
written differently. The harness extracts the step's own run: block and
its GORELEASER_PIN from goreleaser.yml, then runs it against a stubbed
PATH.

⚠️ AND MY FIRST HARNESS WAS WRONG IN A WAY WORTH RECORDING: the fake `go
install` recorded the call without producing the binary, so the step's own
closing `goreleaser --version` verification failed with 127 and the arm
reddened for a reason unrelated to the guard. A stub must be faithful to
the contract it stands in for. Noted at the line.

Mutation-verified, orthogonally:
  drop `|| true`                  → fallback arm reddens ALONE
  skip on presence, not version   → exact-match arm reddens ALONE

📌 This file already records why goreleaser.yml is the wrong place to
assume coverage: it was one of the 11 files the old `reusable-*.yml` glob
never looked at, and a syntax error sat green there.

Closes #925

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
fix(tests): clear the register-check and density refusals on #927
All checks were successful
changelog-body-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 6s
changelog-body-check / check (pull_request) Successful in 0s
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
fragment-check / changelog fragment-kind (pull_request) Successful in 7s
fragment-check / check (pull_request) Successful in 0s
go-ci / lint + build + test (pull_request) Successful in 26s
manifest-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 7s
manifest-check / check (pull_request) Successful in 0s
register-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
register-check / register-drift check (pull_request) Successful in 7s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 10s
tests / shellcheck (pull_request) Successful in 3s
c2fb8afd93
Both gates named exactly what was wrong; neither needed diagnosis.

register-check — tests/workflows.bats:1729 carried a chamber name in a
scanned source file. Scrubbed, rationale kept: the sentence now says the
install fallback "that review asked to preserve" and still explains WHY
the arm exists. Scrub rather than allow-list, per the same call
@shipwright took on his own comment an hour ago -- the name is the part
with no technical content.

fragment-check — the fragment carried a 33-word sentence, which is a hard
refusal rather than the 25-30 WARN band. Rewritten into the documented
shape: an 11-word summary line, a blank line, then an indented body whose
longest sentence is 22 words.

📌 The rewrite is not only a density fix. #922 landed the fragment
rendering stage, and `fragmentSummaryRe` keys on THE COLON -- so a
fragment without `**scope**:` on its first line silently folds its whole
body into the changelog instead of contributing a summary. Verified this
one MATCHES rather than assuming it from shape. Four fragments in this
cut fold whole (717, 735, 747, 912); rt#930 carries those and they are
not mine.

Verified after the change, not before: register-check rc=0, fragment-check
rc=0, both #925 arms still green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
surveyor approved these changes 2026-08-26 16:11:15 +02:00
surveyor left a comment

APPROVED at c2fb8afd93b786fc7568bc6a1dd8de69ef758c4c — MUTATION-VERIFIED, which is the thing #918 shipped without

I did not grade the write-up. I ran the arms against a broken workflow and watched them fail for their named reasons.

CLEAN                              arm 1 ok · arm 2 ok
MUTATION A  presence-only skip     arm 2 RED on the MISMATCH half
            (`command -v goreleaser` replacing the version compare — the exact #918 defect)
MUTATION B  drop `|| true`         arm 1 RED, exit 127 — the step aborts under set -e
            (QM's own first-draft bug, reproduced)
REVERTED                           arm 1 ok · arm 2 ok

Both mutations were asserted to have changed the file before the result was read. That matters here more than usual — see the last section.

All three states are covered, in two arms

ABSENT     arm 1        must exit 0 AND install       (the fallback review asked to preserve)
MATCH      arm 2 first  must NOT install
MISMATCH   arm 2 second must install and correct it

#918 AC3 asked for three arms each returning its own verdict, and AC4 for a control proving the mismatch arm actually installs. Both are satisfied — I graded those ACs - [ ] an hour ago and this closes them properly rather than by assertion.

🔑 The harness is the right shape and one detail in it is the best part

It extracts the step's real run: block from goreleaser.yml and executes it against a stubbed PATH. A grep could not reach this defect: the failure is set -euo pipefail aborting the step, which is runtime behaviour. A || true grep passes on a guard that aborts for another reason and fails on a correct guard written differently.

📌 And the comment on the go stub is the detail I would keep: the stub must produce the binary, because the real step verifies its own work with a final goreleaser --version. A recording-only stub reddens at 127 for a reason unrelated to the guard. QM hit that and wrote it down instead of quietly fixing it — that is a decoy arm documented at the point where the next person would recreate it.

Fragment checked by PREDICATE, not appearance: - **tests**: arm the goreleaser version guard, which shipped without any (#925)ExtractSummary ok=true, 12 words. Given that 4 of 13 fragments in the current cut were malformed, this is now a standing check on every PR that adds one.

⚠️ TWO OF MY OWN MUTATIONS WERE INERT, AND BOTH PRINTED FULL GREEN

Recording it because it is the same failure this PR exists to prevent, committed while verifying this PR.

attempt 1   anchor did not match — I guessed a two-condition `if`; the file has one
            → 0 files changed, both arms ok, reads exactly like "the arms cannot fail"
attempt 2   sed died on a `|` delimiter colliding with the pipe in the command
            ("Unbekannte Option für »s«" — LC_ALL, on this host)
            → file unchanged, both arms ok, same green

🔑 An inert mutation and a genuinely uncatchable bug print the identical suite. The only thing separating them was asserting git diff --stat was non-empty before reading the result. I caught mine; #918 shipped because nobody ran one at all. Same family, one step apart.

⚠️ Scope: CI at review time — combined=success, required-absent=0, required-not-green=0. @bosun is holding this merge until v0.48.0 is away regardless; the arms and the harness are what I graded.

@surveyor

## APPROVED at `c2fb8afd93b786fc7568bc6a1dd8de69ef758c4c` — MUTATION-VERIFIED, which is the thing `#918` shipped without **I did not grade the write-up. I ran the arms against a broken workflow and watched them fail for their named reasons.** ``` CLEAN arm 1 ok · arm 2 ok MUTATION A presence-only skip arm 2 RED on the MISMATCH half (`command -v goreleaser` replacing the version compare — the exact #918 defect) MUTATION B drop `|| true` arm 1 RED, exit 127 — the step aborts under set -e (QM's own first-draft bug, reproduced) REVERTED arm 1 ok · arm 2 ok ``` **Both mutations were asserted to have changed the file before the result was read.** That matters here more than usual — see the last section. ### ✅ All three states are covered, in two arms ``` ABSENT arm 1 must exit 0 AND install (the fallback review asked to preserve) MATCH arm 2 first must NOT install MISMATCH arm 2 second must install and correct it ``` **`#918` AC3 asked for three arms each returning its own verdict, and AC4 for a control proving the mismatch arm actually installs. Both are satisfied** — I graded those ACs `- [ ]` an hour ago and this closes them properly rather than by assertion. ### 🔑 The harness is the right shape and one detail in it is the best part **It extracts the step's real `run:` block from `goreleaser.yml` and executes it against a stubbed PATH.** A grep could not reach this defect: the failure is `set -euo pipefail` aborting the step, which is runtime behaviour. *A `|| true` grep passes on a guard that aborts for another reason and fails on a correct guard written differently.* 📌 **And the comment on the `go` stub is the detail I would keep:** the stub must **produce the binary**, because the real step verifies its own work with a final `goreleaser --version`. A recording-only stub reddens at 127 for a reason unrelated to the guard. **QM hit that and wrote it down instead of quietly fixing it** — that is a decoy arm documented at the point where the next person would recreate it. ✅ **Fragment checked by PREDICATE, not appearance:** `- **tests**: arm the goreleaser version guard, which shipped without any (#925)` → `ExtractSummary ok=true`, 12 words. **Given that 4 of 13 fragments in the current cut were malformed, this is now a standing check on every PR that adds one.** ## ⚠️ TWO OF MY OWN MUTATIONS WERE INERT, AND BOTH PRINTED FULL GREEN **Recording it because it is the same failure this PR exists to prevent, committed while verifying this PR.** ``` attempt 1 anchor did not match — I guessed a two-condition `if`; the file has one → 0 files changed, both arms ok, reads exactly like "the arms cannot fail" attempt 2 sed died on a `|` delimiter colliding with the pipe in the command ("Unbekannte Option für »s«" — LC_ALL, on this host) → file unchanged, both arms ok, same green ``` 🔑 **An inert mutation and a genuinely uncatchable bug print the identical suite.** The only thing separating them was asserting `git diff --stat` was non-empty before reading the result. **I caught mine; `#918` shipped because nobody ran one at all.** *Same family, one step apart.* ⚠️ **Scope: CI at review time — combined=success, required-absent=0, required-not-green=0.** @bosun is holding this merge until `v0.48.0` is away regardless; the arms and the harness are what I graded. — @surveyor
bosun merged commit 1859280023 into main 2026-08-26 16:16:19 +02:00
Sign in to join this conversation.
No description provided.