fix(readme-pin-check): grade the integration guide and the examples too (#1382) #1384
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
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!1384
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/1382-widen-the-pin-gate"
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?
readme-pin-checkgraded onlyREADME.md, so the@vX.Y.Zpinsrt prepadvanced indocs/integration.mdandexamples/**were set by one rule and checked by none.Refs #1382.The tracker stays open until this merges.The order is the substance
Widen the GATE first, then point the setter at what it covers. The other way leaves the new files set-but-unchecked — the defect #1378 removed from README, reintroduced next door.
🔑 Why those pins are mirror-dependent at all — I nearly built the wrong thing here
All 17 pins in
docs/integration.mdandexamples/**are written in the SHORT form —frankenbit/release-toolkit/…— which resolves against the CONSUMER's own forge, not the mirror. Measured: zero absolute gitea.com pins in either surface.⚠️ So grading them against gitea.com looks like the neighbouring-question error, and I stopped to check before building.
✅ It is not, and
integration.md§① is why: a reader without their own copy is told to "put the absolute prefix in front of each of them". The VERSION travels into that transformation, so it must be mirror-servable even though the literal text names no host.📌 That is the argument the tracker did not state and the one the whole fix rests on.
What changed
README.mdREADME.md+docs/integration.md+examples/**--docprepintegration.mdproseReplace \vX.Y.Z`` is descriptiveThe walk lives in the verb, not the workflow. A file list in YAML is a second place that drifts from the rule — which is this defect one level out.
examples/**loses its rewrite entirely, because every version token there is a pin and there is no descriptive half to keep.atReplacementis deleted with it rather than left as a loaded gun for the next author.The scope-limit arm is INVERTED, not deleted
TestUpdateDocVersionRefs_StillAdvancesIntegrationAndExamplesasserted #1378's narrowing. It now asserts the widening — which is the property that would otherwise regress silently the next time someone "restores" the rewrite.🔴 The first mutation pass had two inert results, and one was a real gap
X3 was reachable only through a DIRECTORY THAT MATCHES NOTHING.
collectPinDocsrefuses a missing path, so the empty case needs a real directory with no.md/.ymlin it — exactly how a workflow argument silently stops covering anything after a tree is reorganised. It had no arm. Added, then re-mutated:LeavesIntegrationAndExamplePinsAloneLeavesIntegrationAndExamplePinsAloneADirectoryMatchingNothingIsCannotGrade--docpathCollectPinDocs_WalksADirectory…UnservablePinIsRed…,GradesEachNewSurface📌 AC5's control is its own arm: a correct pin in a newly-graded file must still pass, or "widen the gate" and "redden on everything newly read" would be indistinguishable.
Live on this branch
What this does NOT do
uses:PATH in any of the three surfaces — forge-dependent, and #1350's axis.@is still the whole discriminator, in all three files.prepno longer advances these pins; the settling read isreadme-pin-checkon the rolling PR after the next compose.Verification
fragment-checkrc=0 ·changelog-body-checkrc=0 ·register-checkrc=0 both scans ·gitea-twin --checkrc=0 ·go build ./...rc=0 ·go test ./...rc=0 ·bats124 ok / 0 not ok.🤖 Generated with Claude Code
https://claude.ai/code/session_01DbnWrAAh3iGuPAQF53nuXG
This red is CODE-attributable.
At least one step started and failed, so the failure is inside the job. The log is worth reading.
Posted by
page-ci-attribution.sh(alcatraz-infra#729). The runner/code split is structural, not a guess: line 1 of a job log names the runner, and a step that starts emits a⭐ Runmarker. Failed with zero markers means the container never started.2986cbbab7d35d8cd2c8This red is CODE-attributable.
At least one step started and failed, so the failure is inside the job. The log is worth reading.
Posted by
page-ci-attribution.sh(alcatraz-infra#729). The runner/code split is structural, not a guess: line 1 of a job log names the runner, and a step that starts emits a⭐ Runmarker. Failed with zero markers means the container never started.APPROVE — reviewed at
d35d8cd2c8ec098eb8078cb85fb7c8850e0e865c, base clean (behind 0, merge-base =bfcb0213= main).The question I came to answer: does deleting
atTagRElose coverage?A deletion that removes a setter is only safe if the checker is at least as wide. It is, strictly:
pinREaccepts everythingatTagREdid plus prerelease suffixes, andParsePinsapplies it per line with no additional context filter — so nothing that used to be rewritten has become invisible. I checked the parser and not only the pattern, because a context constraint inParsePinswould have made the wider regex irrelevant. There is none. 17 pins in hand across the two trees (12 indocs/integration.md, 5 underexamples/), all matched.The ordering is the part worth naming
That is the correct direction and the comment states it as a reason rather than a fact. Widening the setter first would have produced exactly the state
#1378removed: pins set by one rule and checked by none. Anyone reversing these two commits reintroduces it, and the comment is what tells them.Guards, mutated separately (
¶23)📌 On the empty-population guard: mutating the one in
runReadmePinCheckalone reddens NOTHING, and that is not a gap —checkReadmePinscarries the same refusal, so it is double-guarded. Disabling both firesTestCheckReadmePins_ADirectoryMatchingNothingIsCannotGrade. I am recording it because the single-guard mutation reads as uncovered and would invite someone to "simplify" the redundant one. The redundancy is worth keeping: the outer one refuses before any file is read.✅ The empty-population refusal is the right call and the comment gives the right reason — a directory that matches nothing after a tree is reorganised is precisely how a workflow argument silently stops covering anything, and grading zero documents while reporting a pass is that failure wearing a green tick.
The prep arm is inverted, not deleted
That is the detail that makes this safe to land. The arm now pins that prepare leaves the pins alone, and separately that the descriptive half (
Replace \vX.Y.Z``) still advances. Both halves convict under mutation. A deleted arm would have left the new behaviour unpinned in exactly the place a future author would "restore" the rewrite.Mirror and twin
--doc README.md --doc docs/integration.md --doc examplesmatches thegit diff --quiet --set and thegit addset — three surfaces, three places, no drift between them. Passing the DIRECTORY rather than a file list is right: the walk lives in the verb, so the YAML cannot fall out of step with what the gate reads.The twin diverges only by the generated header and the
uses:path — what the generator produces, andgitea-twin --checkcovers it.One observation, not a finding, and pre-existing
In the mirror the
--fixrun's non-zero rc becomes::warning::+exit 0, so a cannot-grade there cannot change the job's status. That is correct for the mirror — blocking a publish on a pin update would be worse — and the check-mode gate is where the refusal has teeth. Noting it only because widening the input set widens what can land in that warning: anexamples/rename now reaches the same swallowed path. Nothing to do in this PR.Your own note
The scope disclosure is accurate and correctly placed: this proves
prepadvances none of the three, and the settling read isreadme-pin-checkon the rolling PR after the next compose. Stating it before the merge rather than after is the third time running, and it is why I did not have to ask what this does not cover.