fix(gate): quoting a config key erased it before the disarm regex ran (BACKLOG #1069) - #634
Merged
Merged
Conversation
…t (BACKLOG #1069) Get-ScannableSegments builds each segment's Scan through Remove-QuotedSpans, which blanks every closed quoted span, and rule 3c matched the danger key against Scan. Quoting the key therefore erased it before the disarm regex ran -- and quoting an argument is ordinary, so this needed no unusual spelling. It disarmed the ledger, claim and leak commit gates for every worktree at once. Reproduced with the UNQUOTED spelling as a known-answer control, which denied in both arms. All five spellings the row lists allowed before and deny now. MY FIRST PROBE REPORTED THE CONTROL ITSELF AS ALLOW, which would have read as a far larger finding. It was a broken probe, and only the known-answer case separated "the gate is blind" from "my harness never reached a governed repo". THE FIX IS A BARE-WORD UNMASK, NOT A RAW-TEXT MATCH. Matching raw text would refuse a commit message quoting the rule's own name, and this workstream writes those constantly. The discriminator is WHITESPACE: prose has it and stays masked, a config key does not and becomes visible. Three such prose messages are pinned as ALLOW. THE LENGTH-PRESERVING MASK THE ROW PRESCRIBES IS DELIBERATELY NOT BUILT. Its stated rationale is that "the same offsets read paths back out of the raw text afterwards" -- and no rule does that: every path site re-runs [regex]::Match($seg.Raw, ...) and computes offsets inside Raw from scratch. Length-preserving masking would change what every other rule sees for zero benefit here. Widening scope past the defect is exactly how the earlier attempt acquired five new fail-opens, which is why that patch carries a do-not-ship order. It remains unshipped and untouched. ONE SPELLING STAYS OPEN BY DESIGN: a quoted multi-word alias value. Its value contains a space, so the carve-out cannot reach it without re-admitting the prose false deny. Pinned as an ALLOW test whose docstring says it is an open hole rather than a passing property, and says a later tokeniser should make it FAIL and be inverted alongside the banner rather than deleted. Regression: 631 passed, 0 failed across all eight worktree-gate suites. Mutation: disabling the unmask reds exactly the five deny rows and leaves the control, the three prose rows and the by-design gap green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…(BACKLOG #1069)
PR 634 is RED on three required legs with one deterministic cause:
tests/test_tooling_partition.py::test_every_non_engine_test_is_classified
"unclassified: ['test_worktree_gate_quoted_key.py']"
The branch adds a test file that imports no engine module and never lists it. The assertion names both
remedies itself; this is the manifest one, not _STAYS_WITHOUT_IMPORTING, because the test drives the
hook as a subprocess and does not read engine source.
NOT A FLAKE, AND NOT RE-RUNNABLE. The lander playbook records that tooling_partition is never a flake
and that a re-run past one lands a defect on purpose. Three legs red on one cause is the signature.
INSERTED IN THE FILE'S OWN ORDER, NEVER SORTED. tests/tooling_manifest.txt is NOT plain lexicographic --
test_worktree_gate.py sits AFTER its underscore-suffixed siblings -- so a sort() rewrites unrelated
lines. A previous session did exactly that and moved 22 lines it did not intend to touch. Anchored on
the following entry instead.
Measured, interpreter borrowed from a sibling worktree because this one has no venv, and VERIFIED to
read THIS tree rather than the lender's (messagefoundry.__file__ resolves under wt1069, since cwd wins
over an editable install -- a borrowed interpreter testing the wrong tree is silent):
red-first: reverting only this line reds test_every_non_engine_test_is_classified and nothing else
(1 failed / 8 passed); restoring it returns 9 passed
git diff --numstat reads 1/0 -- a re-sort would have shown roughly 22 on both sides
rebased onto a490993 first; the rebase was clean
Rebase note for whoever pushes: this branch was 24 behind and is now ahead 1 of a490993, so the PR
head moves and needs a force-update with a lease.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
wshallwshall
force-pushed
the
claude/builder-1-1069-quote-mask
branch
from
August 27, 2026 23:30
071d28c to
3956f94
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Built by Builder 1. Landed by the Lander. Three files,
+137/-1.A live fail-open in the gate that governs every worktree
Rule 3c matched the danger key against
$seg.Scan, andRemove-QuotedSpansblanks every closed quoted span. So quoting the key erased it before the disarm regex ever ran. Quoting an argument is ordinary.All five spellings the row lists were ALLOWED before and DENY now:
Remove-QuotedSpansnow unmasks a quoted span holding a single bare word -- no whitespace, quote,$, bracket, brace, semicolon, ampersand, pipe or backtick. Prose keeps its spaces and stays masked; a config key has none and becomes visible.The number that matters here is the regression count
631 passed, 0 failed across all eight worktree-gate suites. An earlier attempt at this item acquired five new fail-opens and carries a standing do-not-ship order; that patch is untouched and unshipped.
Mutation-tested, and the discrimination is the point: disabling the unmask reds exactly the five deny rows and leaves the control, the three prose rows and the by-design gap green. A mutation that redded everything would have meant the test file was coupled to something broader than the fix.
Three things a reviewer should know, all from the author
Their first probe reported the UNQUOTED control as ALLOW -- which would have read as a far bigger finding than the real one. It was a broken harness, and only the known-answer case separated "the gate is blind" from "my probe never reached a governed repo". The control is now the first test in the file (
test_the_unquoted_key_is_denied, line 50, ahead of the five deny rows).They deliberately did NOT build the length-preserving mask the row prescribes, and the reason is a measurement rather than a preference. Its stated rationale is "the same offsets read paths back out of the raw text afterwards" -- and no rule does that. Every path site re-runs
[regex]::Match($seg.Raw, ...)and computes offsets insideRawfrom scratch. It would change what every other rule sees for zero benefit, and widening scope past the defect is exactly how the previous attempt got its five fail-opens.One spelling stays open by design -- a quoted multi-word alias value, whose space puts it out of reach of a bare-word carve-out without re-admitting the prose false-deny. It is pinned as an ALLOW test whose docstring says it is an open hole rather than a passing property, and says a later tokeniser should make it FAIL and be inverted alongside the banner rather than deleted.
Lander verification
## 1069already exists onmain, so this adds a body stamp rather than a heading -- my+## 1069check correctly returns 0 and that is not a missing ledger row.Before the push,
git branch -r --contains 071d28ca6named only the private rescue ref. Sixth branch tonight where a count-based check would have read "already pushed".Not armed
Required approvals are 0, and this is a security gate.
Generated with Claude Code