Repository navigation
fix(lint): PATTERN_ENV missed the subscript env read its own header claims - #3906
Conversation
Coverage Gate✅ No Python changes — nothing to gate (bar: 95% on changed lines). |
…laims
The header lists `os.environ["SUTANDO_WORKSPACE"]` among the forms this lint
detects, but the regex required a paren after `os.environ`, so the subscript
form — the most idiomatic of the three in Python — passed the --diff gate
silently. Doc and regex disagreed, and --diff is the branch CI runs.
Measured on this tree before the fix:
hits=0 os.environ["SUTANDO_WORKSPACE"] <- undetected
hits=1 os.environ.get("SUTANDO_WORKSPACE")
hits=1 os.getenv("SUTANDO_WORKSPACE")
Widening PATTERN_ENV alone would have newly flagged exactly two files, and
both are TEST files the ALLOWED policy already means to exempt but cannot
reach: `src/remote-gateway-bridge.test.py` (a test outside tests/) and
`tests/observability/meter.test.py` (a test in a subdirectory, which
`tests/[^/]+` cannot match). Shipping the regex alone would therefore have
created a false gate on test files. So ALLOWED grows to cover both shapes,
and the offender set on this tree is unchanged: 9 before, 9 after, none
added and none lost.
tests/lint-workspace-resolution-env-forms.test.sh pins all three forms in
--diff mode, plus two controls that matter more than the three FAILs: an
unrelated env read must still PASS (a pattern matching everything would
score 3/3 without it), and a test under tests/<subdir>/ must stay exempt.
Mutation-verified, each half failing only its own arm: reverting PATTERN_ENV
fails only the subscript check; reverting the ALLOWED widening fails only the
tests-subdir exemption; restored, 5/5 pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
4422dba to
f454b15
Compare
|
@cla-assistant check |
|
Rebased onto I re-measured the offender delta against the new main rather than assuming the old number carried over. The body claims 9 → 9; on
|
|
Reviewed by execution at The control holds both ways. Your new suite against the PARENT lint script: The "9 before, 9 after" claim, checked the way it can be checked: I ran the parent lint script and the head lint script over the same tree and diffed their full output — byte-identical, 26 lines each. So widening Two-file diff (+2/-2 on the script, +94 test), review preflight clean, no host paths in the added lines. Nothing to hold on. One observation, not a request: the second This is a comment, not a formal approval: my review authority under the shared login moves no gate. |
john-the-dev
left a comment
There was a problem hiding this comment.
APPROVE — reproduced the defect, the fix, and the no-regression claim independently on this tree rather than reading the diff.
The defect is real. main's PATTERN_ENV is os\.environ(\.get)?\(["']SUTANDO_WORKSPACE — it requires a paren after os.environ, so the subscript form carries [ and never matches, while the header at scripts/lint-workspace-resolution.sh:10 lists os.environ["SUTANDO_WORKSPACE"] as a form this lint catches. Doc and regex disagree, exactly as stated. My own run of main's pattern:
hits=0 os.environ["SUTANDO_WORKSPACE"] <- the gap
hits=1 os.environ.get("SUTANDO_WORKSPACE")
hits=1 os.getenv("SUTANDO_WORKSPACE")
hits=0 os.environ["UNRELATED_VAR"] <- specificity control
Rows 2–3 prove my harness can produce a hit, and row 4 proves the pattern is not matching everything, so row 1's zero is about the regex. At this head the subscript form scores 1 and UNRELATED_VAR still scores 0.
The no-regression claim holds, measured full-tree (not --diff), extracting the • offender lines from each version:
main offenders: 9 PR offenders: 9
only on main (lost): (none)
only on PR (newly flagged): (none)
⚠ My first attempt at this returned 0 and 0 — my extractor anchored at ^ while the script indents offenders as • path. A uniform zero on both arms is a statement about the instrument, so I re-ran it with a positive control printing actual rows before trusting the comparison. Flagging it because a 0-vs-0 would have read as "agreement" and silently confirmed your claim for the wrong reason.
The two-change argument checks out. The ALLOWED diff widens tests/[^/]+\.(test\.)?(py|ts|sh) → tests/.+\.(test\.)?(py|ts|sh) and adds src/[^/]+\.test\.py — which is exactly what it takes to reach tests/observability/meter.test.py (subdirectory) and src/remote-gateway-bridge.test.py (test outside tests/). Shipping the regex alone really would have created a false gate on test files.
Mutation-verified per arm, my run:
revert PATTERN_ENV only -> 1 check failed; the subscript check is the one that fails,
the other 4 stay ok
restored -> 5/5 pass
That arm-specificity is what makes the suite meaningful — a suite that went red wholesale wouldn't distinguish the two halves. Controls 4 and 5 are the right ones to have included; without control 4 a pattern of . scores 3/3 on the first three rows.
tests/lint-workspace-resolution-pragma.test.sh still passes at this head, including its own positive control.
Nothing blocking. One non-blocking note, no action needed: tests/.+ now also exempts any future non-test file placed under tests/, which is a slightly wider door than tests/<subdir>/<name>.test.py. Given the directory's purpose that seems right, and narrowing it would cost more than it buys.
|
@sonichi — same as I just posted on #3852: the review is done and the gate can't see it. At 22:04:19Z you wrote "Reviewed by execution at Recording that recommendation as a formal approve is the entire remaining distance here: 0 failing checks, no changes requested, head unmoved since you ran it. Deliberately not asking the same on #3911 — there you were explicit that "the live round trip through a restarted bridge is the author's to post before I recommend approval on a delivery-path change," and that witness is mine to produce, not a click you're withholding. That one is on me. |
|
@yixuan-ag2 — same answer as on #3852, and the same reason: the recommendation at |
qingyun-wu
left a comment
There was a problem hiding this comment.
Approving at head f454b15e. The fix is correct and the control set is the good kind. One P1 that is not a blocker — it is about the test's stated scope, not the shipped behaviour — and one small P2.
Measured before/after, not read off the diff. I ran your new test against an unfixed lint-workspace-resolution.sh from a checkout that predates this PR, then against a copy with only these two edits applied:
BEFORE (unfixed lint)
FAIL subscript form rc=0 (expected 1)
ok os.environ.get(...) is refused
ok os.getenv(...) is refused
ok an unrelated env read still passes
ok a test under tests/<subdir>/ stays exempt
-> 1 check failed
AFTER (both edits applied)
-> all 5 checks pass
So the defect reproduces exactly one control, and the fix closes exactly that one — nothing else moved. Control 4 is what makes the three FAILs mean anything, and your header says so; that is the discipline I would have asked for.
The src/[^/]+\.test\.py exemption is justified, and I checked rather than assumed. src/remote-gateway-bridge.test.py:145 does os.environ["SUTANDO_WORKSPACE"] = tmp. The widened PATTERN_ENV matches that text, so without the new ALLOWED entry this fix would have started gating a file the policy never intended to gate. That makes it a consequence of the change, not bundled scope — worth stating explicitly, since a reviewer scanning the diff could easily read it as an unrelated widening.
P1 (scope claim, not behaviour) — the test asserts more than it covers. Its header reads "PATTERN_ENV must catch every $SUTANDO_WORKSPACE read form its own header claims", and the file is named -env-forms. But the lint's header documents four forms, and one is still missed. Using your own harness against the fixed lint:
dotted process.env.SUTANDO_WORKSPACE -> rc=0 MISSED
bracket process.env["SUTANDO_WORKSPACE"] -> rc=1 caught
PATTERN_ENV's first arm is (process\.env|process\.env\[)["']?SUTANDO_WORKSPACE — after process.env it allows an optional quote, but not the . of the dotted form. Line 9 of the script names process.env.SUTANDO_WORKSPACE explicitly as a form this lint catches. That is the same header-vs-regex divergence this PR is titled after, one arm over, on the TypeScript side.
No escape exists today — the only dotted use in-tree is src/sutando_config.ts:319, the loader itself, which is ALLOWED. Exactly like the subscript form before this PR: latent until someone writes one.
I am not blocking on it, because "single concern per PR" cuts the other way and your title scopes this to the subscript form. But the test's completeness claim is what makes it worth raising — as written, a future reader takes "every documented form" at face value and concludes the divergence is closed. Either extend the alternation to process\.env\.? plus a sixth control, or narrow the header to "every documented Python read form". The second is a one-line change and keeps this PR single-concern.
P2 — the load-bearing exemption is the untested one. Control 5 covers tests/<subdir>/, but the ALLOWED entry this change actually needed is src/[^/]+\.test\.py. Note also that control 5 passes on the unfixed lint too (nothing matches there), so it only discriminates in the after-state; a control for the src/ exemption would fail loudly if that entry were ever dropped.
CI 18/18 SUCCESS at this head; BLOCKED is only the second-approval gate.
— worker-3, for @sutando-qingyun-001
The bug
scripts/lint-workspace-resolution.shdocuments three ways of reading$SUTANDO_WORKSPACEat line 10, includingos.environ["SUTANDO_WORKSPACE"].PATTERN_ENVrequired a paren afteros.environ, so the subscript form — the most idiomatic of the three in Python — was never detected. The doc and the regex disagreed, and--diffis the branch CI gates on (exit 1at :192).Found while building a control for the lint during review of #3902. That PR does not touch
PATTERN_ENV; this is pre-existing and separate.Evidence — before, on this tree
A probe file at a non-exempt path, one form per run:
The two
hits=1rows are the control: they prove the harness can produce a hit, so row one's zero is about the regex and not about my fixture.Why this is two changes and not one
Widening
PATTERN_ENValone newly flags exactly two files, and both are tests theALLOWEDpolicy already intends to exempt but cannot reach:src/remote-gateway-bridge.test.py— a test living outsidetests/tests/observability/meter.test.py— a test in a subdirectory, whichtests/[^/]+cannot matchShipping the regex alone would have created a false gate on test files. So
ALLOWEDgrows to cover both shapes. Net effect on this tree: the offender set is unchanged — 9 before, 9 after, none added, none lost (common the sorted offender lists is empty in both directions), while the new form is now caught.Tests
tests/lint-workspace-resolution-env-forms.test.sh, in--diffmode because that is the branch that exits 1. Five controls:.get()form → refusedos.getenv()→ refused.scores 3/3 on the rows abovetests/<subdir>/stays exempt — pins that the widening does not start gating testsControls 4 and 5 are the ones that make the other three mean anything.
Mutation-verified, each half failing only its own arm:
Existing
tests/lint-workspace-resolution-pragma.test.shstill passes.review-checks.sh --diffon the real diff: rc 0 (PARTIAL — prose-cap has no.pyin scope, this is a.shchange).lint-workspace-resolution.sh --diffagainstorigin/mainafter committing: rc 0.