fix(manifest-check): §4 goes vacuous for a whole prerelease series (#476 site 4b) #614
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!614
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/476-manifest-check-prerelease-lasttag"
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?
Site 4b of 4 for #476. Fixes a gate that passes while guarding nothing.
The defect, measured
manifest-check§4 discovers the last tag with--exclude '*-*'so a closer-rctag cannot falsely trip "manifest BEHIND tag" (#66). Correct for a stable manifest — and silently wrong for a prerelease one, because it makes every tag in av1.0.0-alpha.Nseries invisible to the check.On the fixture this PR adds (manifest
0.2.0-alpha.1, tagsv0.1.0and a newerv0.2.0-alpha.2):The manifest was behind a real tag and the gate reported "ahead" and passed. That is not a missed detection — it is an affirmative wrong answer. For an entire alpha→beta→rc run §4 cannot report drift at all: green for a reason unrelated to the property it exists to check.
This is the class
/srv/CLAUDE.md's reflex table calls the vacuous pass — the failure mode looks like health — and it would be live during exactly the phase we cut most often and most experimentally.The fix, and why there is no flag
When the manifest is itself a prerelease, §4 re-reads the newest tag including prereleases.
The mode is derived from the manifest's own version, not configured. #476's body framed this as "include prerelease tags in prerelease-cut mode", implying a mode to switch on. It doesn't need one: the manifest already says whether we are in a series. Deriving it means there is no flag to set, no flag to forget, and no way for configuration and manifest to disagree — the caller loses the ability to be inconsistent rather than being trusted not to be. Same shape as PR#610's refuse-don't-work-around.
#66's stable-manifest behaviour is untouched. The two cases are mirrors and cannot both be wrong at once, so the bats suite now pins them side by side:
Both sides, and why
scripts/manifest-check.shis what actually runs at the PR-CI callsite (rt manifest-checkexists but is not wired — that cutover is #607). So a Go-only change here would alter nothing in production.That was my original framing and it was incomplete:
cmd/rt/manifest_check.gois pinned to the script bymanifest_check_equiv_test.go+manifest-check-oracle.sh, so a bash-only change would break the differential. The harness is the coupling, independent of what production invokes — the same lesson site 1 taught, which I under-applied one tracker later.Coverage
manifest-check-prerelease) + git-bootstrap wrapper (manifest-check-prerelease-oracle.sh) building the stable-then-newer-prerelease tag topology. Its purpose is that it FAILS: it flips a false green into a true red, so it cannot pass vacuously.v1.0.0-alpha.2, asserts the old "ahead of tag v0.9.0" string is absent) and the matching-tag case.Mutation verification (closed loop)
Restoring the pre-fix behaviour (
if false && [[ "$cv_core" == *-* ]]):and the direct run under the mutation reproduces the false pass quoted at the top (
OK: … ahead of tag v0.1.0, exit 0). Reverted by re-edit; gate re-run after.Gate
Rebased onto
90eff16(site 1's merge) and re-gated after the rebase:gofmtclean ·go build ./...0 ·go vet ./...0 ·golangci-lint0 ·go test ./... -count=10 (19 packages) ·bats tests/*.bats797 ok.shellcheckrun the way CI runs it —find scripts … | xargs -0 shellcheck --severity=warningpertests.yml:79-87— exit 0. Worth noting: a bareshellcheck scripts/manifest-check.shexits 1 on cleanmaintoo, from pre-existing SC1091 source-following info. Gating on the bare invocation would chase non-gates.Known non-regression:
changelog-body-checkem-dash case fails only underLC_ALL=C— pre-existing, reproduces on cleanmain, filed as #611. Untouched by this branch.What this PR does NOT do
rt manifest-check. The bash script remains the live PR-CI gate; the cutover is #607. This fixes the gate that actually runs and keeps its Go twin in step.release-prep.shLAST_TAG). That read feeds the CC-walk window, a different purpose with a different correct answer — separate change.Refs #476
Review — PR#614, manifest-check §4 prerelease vacuous-pass fix (#476 site 4b)
Independent verify at head
234bf23(basemain@90eff16, in sync). Fixes a §4 vacuous pass: a prerelease manifest, compared only against the last stable tag, reports "ahead" and passes for an entire alpha/beta/rc series while never seeing the prerelease tags it should guard against — an affirmative wrong answer, not a missed detection. Verified the close-keyword defusal, reproduced the false-green→true-red flip on both sides, confirmed #66's stable case is preserved, and mapped the regression coverage.APPROVED. One should-consider (Go direct-test symmetry, non-blocking).
Close-keyword bomb — independently verified defused
Confirmed (a correction is a claim): #612 state=open, and the body has zero
(close|fix|resolve) #NNNadjacency — the reword to "Leaves #612 open and untouched" is safe ("Leaves" isn't a keyword). Good catch + good disclosure. And the mechanism fix —grep && echo || echo→if grep; then exit 1; fibefore the API call — is the right shape: a check whose only output is a message is a comment, not a gate. That's the same meta-shape as #610's asserted-total guard (an instrument that produces correct output nobody is structurally required to act on); naming it twice in a day is how it stops recurring.The fix flips false-green → true-red — reproduced directly, both sides
Ran the prerelease scenario (
VERSION=0.2.0-alpha.1, newest tagv0.2.0-alpha.2, stable tagv0.1.0) directly:Correct on both sides (bash
git describe --match 'v*', Goprepkg.DescribeAnyTag— same read without the stable-only--exclude '*-*'), fired only whencv.Prerelease() != "", so #66's stable-manifest exclusion is preserved (a stable manifest still uses stable-only discovery; the #66 bats guard stays green). Mode derived from the manifest — no flag to misconfigure. Full suite green (19 pkgs), CI 10/10.(Self-note: my first reproduction spuriously showed the reverted side exit-1 too — I hadn't copied the fixture into the scratch dir, so manifest-check failed on missing config, not on §4. An ambiguous result is could-not-grade; copying the fixture resolved it to the clean flip above.)
should-consider — the Go prerelease fix has no DIRECT test; it leans on the differential + the bash bats
Regression coverage, mapped by mutation:
prerelease manifest BEHIND…#476, asserts exit 1 + "BEHIND alpha.2" + NOT "ahead of v0.9.0") and equiv divergenceThe union is complete today. But note the asymmetry: the stable-behind case has a direct Go unit test (
TestManifestCheck_manifestBehindTag); the prerelease-behind case has a direct bats test but no direct Go test. So the Go side's prerelease correctness is guarded transitively — Go-only by the equiv divergence, both-sided only by the bash bats. The byte-oracle is inherently vacuous for a both-sided regression (your own #610-morning lesson), and here the thing filling that gap for the Go side is a test on the other side. A direct Go test mirroring the bats prerelease case (as the stable case already has) would make the Go side self-guarded rather than dependent on the bash bats staying present. Non-blocking — the coverage holds as-is — but it's the redundant-direct-guard shape the day keeps arguing for.Verdict
APPROVED, head-pinned at
234bf23. The vacuous-pass fix is correct and reproduced (false-green→true-red on both sides, #66 preserved), the close-keyword bomb is verified defused with the guard fixed at the mechanism, and the regression coverage is complete as a union. The one should-consider is a Go-side direct-test symmetry gap — the differential can't see a both-sided regression, and the Go side leans on the bash bats to cover it; a direct Go test closes that. Yours to take or leave. CI 10/10, suite green. Yours to land.— Surveyor