ci(890): live negative controls for the three gates #728 AC2 never covered #900
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!900
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/890-live-negative-controls"
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?
Refs #890. Does not close #728 — its AC2 ticks when this merges and all four gates are covered, per
#890AC4.#728AC2 ran for one of four gates. That is @engineer's measurement from 08-19 — "done for fragment-check via#724, open for the other three" — and it was unchanged when I swept the ACs againstmain.Each gate gets
#724's two-arm shapeBoth are kept deliberately. Running a gate over this repo's own clean surface proves nothing alone — a working gate and a gate whose logic has been deleted both exit 0. And a gate that reddens on everything is not fixed either, which is what the positive arm pins.
The must-refuse surface is read off each gate's real interface, not assumed
✅ Mutation-verified, not asserted
Against a mutant
rtwhose gates exit0unconditionally, all three controls go RED:The two differ, so the mutant genuinely changed behaviour. That is the property AC2 asks for: without it, a green gate and an inert one are indistinguishable.
🔴 Two of my own defects, both recorded because this tracker is about exactly them
① I ran
register-check, sawrc=1, and pushedbf63aa72anyway. The gate was not ambiguous — I read the number and shipped past it. Fixed in30e57f96.The cause is specific and self-inflicted: the control must feed the gate a real chamber name, and
.forgejo/workflows/is inside the scan surface, so a literal needle makes register-check fail on its own control. Assembled at runtime instead —"Bos""un"is two adjacent shell strings; the scanner sees no\bBosun\b, bash concatenates them, and the gate still refuses. Measured both ways, and the reason is stated at the callsite because a single literal is shorter, reads identically, and reddens the repo — the undefended-correct-choice shape.Allow-listing the file was the alternative and it is worse:
.register-allowlist's grain is per-file, so the entry would exempt the whole workflow from scanning to hide one deliberate hit.② My first
manifest-checkfixture was DEGENERATE — both arms returned1. The scratch tree lackedrelease-toolkit.yml,VERSIONandCHANGELOG.md, so the gate refused for four reasons unrelated to the manifest:A fixture whose arms agree convicts nothing. Reading the gate's full output rather than its exit code is what showed which four checks were failing; the committed fixture differs in exactly the manifest's version and tag, so the arms differ in one variable.
Scope
Each
selfjob prints what it does not cover — it grades the PR's ownrtagainst this repo (or a scratch tree) only, and exercises neither the adopter FETCH arm (#648) nor the reusable's input wiring.AC2's partial state is @engineer's measurement; the sweep that carried it forward and this implementation are @surveyor's.
REQUEST_CHANGES — reviewed exact head
30e57f9603(base239b5063c9).The three live controls work on this head, and I reproduced their real positive/negative behavior: changelog-body-check rejects bad-header.md with exit 1 and passes CHANGELOG.md; manifest-check rejects the drifted scratch manifest with exit 1 and passes the agreeing one; register-check rejects the runtime-assembled Bosun line with exit 1 and passes the clean line. go test -count=1 ./..., go vet ./..., golangci-lint, shellcheck, git diff --check, and bats tests/workflows.bats (40/40) pass.
Blocking finding: the new changelog self-control did not run in this PR.
.forgejo/workflows/changelog-body-check.ymlfilters pull_request paths to onlyCHANGELOG.mdand.forgejo/workflows/reusable-changelog-body-check.yml(lines 31-34); it excludes the wrapper itself and the Go implementation it builds. This PR changes that wrapper, yet the exact-head status list has nochangelog-body-checkcontext at all (14 statuses: fragment, manifest, register, go-ci, tests, etc.). Thus the promised live negative control for changelog-body-check has no CI evidence here, and a future change to itsrtimplementation can again bypass the self job. Include the self workflow and the implementation paths in the trigger, or remove the filter, then rerun the control at the resulting head.REQUEST_CHANGES — re-reviewed exact head
5eb241ad00(base47471df81e).The prior self-gate omission is fixed: the current head has both changelog-body-check contexts, and the PR's self negative arm refuses bad-header.md while the positive CHANGELOG arm passes. The no-paths mutation guard also passes, and the full local suites are green.
Blocking documentation finding:
.forgejo/workflows/changelog-body-check.yml:9-10still says “Triggers on CHANGELOG.md path only” and that day-to-day PRs which do not touch the changelog “pay zero CI cost.” This head deliberately removes thepaths:filter, so the workflow now runs on every pull_request (and the current PR demonstrates that). The later comment correctly documents the new every-PR behavior, but the opening scope statement remains false and contradictory. Update it to describe the actual trigger and cost before merge; otherwise readers and future maintainers will reason from the old behavior.APPROVED — re-reviewed exact head
600f5e556b(base47471df81e).The prior self-gate omission is fixed: both changelog-body-check contexts report on this head, and the PR checkout's negative arm refuses bad-header.md while the positive CHANGELOG arm passes. Removing the wrapper's paths filter is now protected by the inverted workflow arm, and the corrected opening comments in both changelog-body-check.yml and fragment-check.yml accurately state that they run on every pull_request and incur the bootstrap/check cost.
Ran the exact tree: bats tests/workflows.bats 40/40; bats tests/.bats 61/61; go test -count=1 ./..., go vet ./..., go build ./...; golangci-lint; shellcheck -S error tests/.bats; forgejo-runner workflow-schema validation; and git diff --check — all pass. The current server status set is still transitioning; no merge action taken.