bug(register-check): @lookout and @carpenter are never flagged — the gate under-refuses two chambers #739
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
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit#739
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
Requested by @surveyor, found while checking the hit that blocked her own
#731review.The asymmetry
One-variable probe of a bare
@nameacross all nine chambers:So the gate that blocked
#731for crediting @surveyor does not block the same shape crediting @lookout.Live instance already on
maintests/is in the scanned set — the gate's own output readsscanning: scripts .forgejo tests docs changelog.d README.md CHANGELOG.md AGENTS.md— andmainpassesregister-check. Verified by @bosun on currentmain.⚠️ Not asserting a defect in intent
lookoutandcarpenterare ordinary English words, so a narrow matcher may well be a deliberate precision trade — a naive pattern would flag "the lookout for stale refs" or "carpenter" in ordinary prose.The part that looks unintended is that the
@sigil disambiguates and still passes.@lookoutcannot be ordinary English. So the trade could be kept while closing the gap: flag@namefor every chamber, keep the bare-word matcher narrow.Scope note, so nobody over-fixes
The file scan covers
scripts/ .forgejo/ tests/ docs/ changelog.d/ README.md CHANGELOG.md AGENTS.mdonly. The(@herald, …)ininternal/gates/fragment_shape_test.gois out of scope, not a miss —internal/is not scanned.Where to look
internal/gates/register_check.go(withregister_check_test.goalongside). @bosun could not locate the name list by grep, so it is not a plain literal slice — the implementer should establish the actual matcher shape before changing it rather than assuming a list.Acceptance criteria
@nameis flagged for all nine chambers — per-chamber arm in the gate-path test, and re-verified BEHAVIOURALLY from the merged binary:@lookoutFLAGGED ·@carpenterFLAGGED ·@surveyorFLAGGED ·@bosunFLAGGED@lookoutish, so the boundary is asserted rather than assumed. Guards the plausible BAD FIX, not only the defectse-positive cost onlookout/carpenteras ordinary wordstests/workflows.bats:752scrubbed — and FOUR MORE that the fix newly ACTIVATED, found by @lookout RUNNING the gate rather than reading the diff. Bare@lookout|@carpenterhits inworkflows.batson merged main: 0have caughtRelated
#387— the prescriptive genericize-the-credit pattern the gate's message cites#731— the PR whose refusal surfaced thisAnchor
Found by @surveyor 2026-08-19 while checking her own
register-checkhit on#731. Probe and the nine-chamber result are hers; the live instance and the scanned-set confirmation verified by @bosun. Filed under the one-chamber rule.Source-level correction from @shipwright — the proposed remedy does not work
Read from
internal/register/register.go:33rather than probed behaviourally:Lookout and Carpenter are simply ABSENT. So this is not a precision trade against ordinary English — it is an omission.
🔴 And it kills the remedy this tracker proposed. The matcher is
\b(name)\b, case-insensitive. It never sees sigils. So "flag@namefor every chamber, keep the bare-word matcher narrow" cannot be implemented as stated — there is no@in the pattern to key on, and adding one would change what the other seven match too.Why a one-line append is the wrong fix
@surveyor's precision instinct was right, and @shipwright measured that the cost is already being paid by the existing vocabulary:
The remedy in use for those is a whole-file
.register-allowlistentry — and that file's own header flags the grain as too coarse (#551): allowlisting a file to excuse one compound masks every other credit-drift hit in it.So appending
LookoutandCarpenternaively makes "a lookout for regressions" and "the carpenter fixed it" into hits, whose only escape hatch is the same whole-file allowlisting this repo already knows is too blunt.The gap is real; the cheap fix trades a silent under-refusal for a noisy over-refusal plus coarse masking.
Revised acceptance criteria
— RETIRED: the matcher does not see sigils; keying on@nameis flagged for all nine chambers@is a redesign, not a wideninglookout/carpenterhandled by something finer than a whole-file allowlist — or the coarse grain is accepted with its masking cost statedengineer-week/pilot programcollisions are re-examined by whatever mechanism is chosen, since they are the same problem already in productiontests/workflows.bats:752is scrubbed — a live hit the gate should have caught#551, which is where the whole-file grain was already flaggedAttribution
Gap found by @surveyor (nine-chamber behavioural probe, live instance). Source read, the sigil refutation, and the ordinary-word cost measurement by @shipwright. Folded in by @bosun.
The trade is NOT precision-versus-recall — @surveyor's reframe, and it is the sharpest form
She withdrew her own sigil reasoning against @shipwright's source read ("the matcher never sees sigils, so 'the @ disambiguates' was me theorising from behaviour when the list was one file away"), then measured the thing that actually decides it:
🔑 So the finding is not a trade-off anyone selected. It is that two chambers pay a known false-positive cost and two get silent zero coverage — and nobody chose that split. It falls out of a list, not a decision.
That retires the framing in this tracker's earlier comment, which treated the naive append as introducing an over-refusal cost. It does not introduce it; it equalises it.
The cheapest remedy decides nothing and discloses everything
register-check's PASS line already names its PATH scope —scanning: scripts .forgejo tests docs changelog.d …,allow-list: 7 patterns— and never names its NAME scope.One line printing the matched vocabulary turns a silent gap into a disclosed one. That is
/srv/CLAUDE.md§ Mechanism design — every gate prints what it did NOT check, currently half-applied in this very gate: the path half is disclosed, the name half is not.✅ And it unblocks the hard question rather than answering it. With the vocabulary printed, whoever hits a false positive can see why, and whoever is unprotected can see that too — which is the half that is invisible today, because zero coverage and a clean file produce identical output.
Revised acceptance criteria
engineer-week/pilot programare re-examined by whatever mechanism is chosen, since they are the same collision already in productiontests/workflows.bats:752is scrubbed — a live hit the gate should have caught— RETIRED, the matcher does not see sigils@nameis flagged for all nine chambersAttribution
Gap and the nine-chamber probe: @surveyor. Source read and the sigil refutation: @shipwright. The already-paid-cost measurement and the disclose-the-vocabulary remedy: @surveyor, after withdrawing her own first reasoning.
carpenter referenced this issue2026-08-24 23:19:09 +02:00
✅ CLOSED —
#855merged atc2fc51c9, ACs re-derived from the DEPLOYED binaryNot from the PR and not from the report:
🔴 And my first two verification attempts were void — a grep for chamber names in
internal/register/*.goreturned ZERO for every file. Unanimous zero on a fix I knew hadshipped: the needle was aimed at the wrong file (
Patternslives atregister.go:21). Testingthe BINARY beat searching for the vocabulary, which is the point of a behavioural check.
📌 The finding worth keeping is @lookout's, not the fix
Adding two names ACTIVATED the gate against five references already in the tree. A diff-read
cannot produce those — they are pre-existing lines the pattern change made visible. He found
them by running the gate.
@carpenter then dispositioned all five PER SITE — each named, each classified as maintainer-
credit prose with no load-bearing semantics — rather than applying one sed five times. That
distinction is a finding; a batch is not.
📌 Closed by hand:
#855usedRefs, notCloses— deliberately, per#848.