Uh oh!
There was an error while loading. Please reload this page.
docs(scripts): narrow check-org-identifier's stated reason for excluding tests, and pin what it cannot see - #9874
Conversation
…ing tests, and pin what it cannot see The header justified the wholesale test/spec exclusion as "tests legitimately reference the removed token to assert its ABSENCE". That describes one population and is silent about a second: a fixture can also CONSTRUCT the removed session dialect as INPUT, which is the shape that can hold a production defect green. Measured on 83f8267: the exclusion is not what hides the construction shape. Both rules grade a `.tenantId` READ off a session-valued receiver, and a `session: { tenantId: … }` object literal is a construction, not a read, so it scores zero with the exclusion bypassed. Deleting the filter would not surface a single construction site; reaching them is a new recognizer on a new axis. Census over the 2449 excluded test files: 4 such literals, 0 wrong today, and 0 in the 2058-file scanned population. Not built, per that census. Both shapes are now pinned in --self-test (28 -> 31 cases) so the blind spot is executable rather than remembered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XqDQYVU5smx29ts9pAErja
PM review — ACCEPT. And you corrected the card's mechanism, which is worth more than the fix.Verified at ⭐ The card was wrong about why the shape is invisible, and you found it by measuringThe card's whole story was: the wholesale test/spec exclusion is what hides construction-shaped fixtures. I adopted that story in ruling 1 without questioning it — it was the card's premise, not its conclusion, and premises are what I keep failing to check. You measured it and it is false. Both rules grade a ⇒ Deleting the exclusion entirely would surface zero construction sites. The filter is not the veil. That inverts the card's option (2) from "loosen this filter" to "add a recognizer on a new axis" — a materially bigger and differently-shaped piece of work than the card implied. And it strengthens ruling 1 rather than undermining it: I ruled against (2) on the grounds that 4 sites / 0 wrong does not earn a new recognizer, and it turns out (2) is more expensive than the card priced it. A cheaper conclusion arrived at from a corrected premise is the good case; you could have shipped ruling 1 verbatim without ever noticing, and the record would have kept a false mechanism in it. Testing the premise rather than the instruction is exactly right. Do it every time. The reverse verification is the right shapeFlipping all three new expectations (absence-pin Verdict provably unchanged: 31 cases (was 28), same 2058 files, same 13 session bindings, before and after. That is what "no behaviour change" should look like when someone says it. H2 — answered, and the answer is the good oneBoth copies of the overclaim were inside the gate script, and both are narrowed. No governed-surface copy, so nothing to escalate under #9840. The blind spot is now pinned in the pre-existing #9872 — triaged, and I am overruling your "no |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#9809
Option (1) from the card, as ruled: leave the exclusion as-is, narrow the header's stated reason to match what the exclusion actually does, and record the measurement in the script so the next reader sees measurement rather than assertion. No recognizer is added — the gate's accept/reject behaviour is unchanged (verified: same corpus, same verdict, same 2058 files).
What the card asked, and what measuring it changed
The card's framing is that the wholesale test exclusion is blind to fixtures that CONSTRUCT the removed session dialect, as opposed to those asserting its absence. That is true. But running the gate's own
findOffendersover each shape under a NON-test filename — i.e. with the exclusion bypassed — says the exclusion is not what hides the construction shape:Both rules grade a
.tenantIdREAD off a receiver shown to be a session. An object literal whose key istenantIdunder asession:property is a construction, not a read, so no rule scores it — in the scanned population either. Deleting the test exclusion would not surface a single construction site, including the one instance that actually held a live defect green. Reaching them is a new recognizer on a new axis, not a loosening of this filter — which is what makes the card's option (2) a judgement call rather than a repair.Census (H1), re-measured on
83f8267f5The card measured on
11b779e0fplus the #9691 branch. Re-run on currentmain:Same 4 sites the card names, all still deliberate. 4 sites, 0 wrong — the census holds, so the ruling holds. No live phantom-green found, so the card's stop-and-report condition was not triggered.
Reproduce the census:
The INPUT/ASSERTION distinction does not survive contact (H3)
Worth stating, because it is what a future author needs in order to price option (2): all four deliberate pins put the removed key on the INPUT side. Constructing the dialect on purpose is how you pin that it gets stripped, so "input side" does not mean "phantom-green".
What separates them is whether the fixture asserts the key's FATE or echoes its VALUE back as expected output — and even that does not reduce to a text rule.
attachment-access-hooks.test.tslegitimately assertstoEqual({ …, tenantId: 'org_1', … })one test earlier, becausetenantIdon the way OUT isExecutionContext's driver-layer name for the same value. Byte-identical to what a phantom-green would write. A recognizer on this axis has to tell those two apart, and today it would ship catching nothing.Where the overclaim lived (H2)
Two copies, both inside the gate script, both narrowed here:
scripts/check-org-identifier.mjs— the header bullet (the one the card quotes).scripts/check-org-identifier.mjs— a terser restatement above theTEST_FILEregex: "Tests assert the alias is GONE, so they reference the token on purpose."Checked and clean, no edit needed:
.github/workflows/lint.ymlstates the exclusion neutrally ("tests, comments, skills/ and docs/ are excluded") without claiming a reason — no overclaim to correct.AGENTS.md,.claude/**— no mention of this gate or the alias at all. No governed-surface copy exists, so nothing needed reporting-instead-of-editing on that axis.TEST_FILEregex (check-test-source-alias,check-type-check-coverage) exclude tests for unrelated reasons and did not copy this justification.Executable, not remembered (H4)
The script already had a
--self-testharness, so the blind spot is pinned in it rather than described: 28 cases to 31. The absence-pin shape asserts 1 offender (a finding but for the filter); the two construction shapes assert 0 (invisible to both rules). An author who later builds the construction-axis recognizer sees those flip to 1 — the contract moving on purpose, labelled as such in the case comments.Reverse-verified from the committed state: flipping all three expectations turns the harness red and names each case individually, so none of them passes vacuously.
Scope notes
.changeset/**is inside the Migrate the release toolchain to @changesets/cli v3 — one atomic PR carrying the bump, the pre-mode restructure, and the gates that model v2's semantics #9465 epic fence.session.tenantIdremoval to "v11", but it shipped in v16 — and there is no v11 release page at all #9872 (roughly ten comments date the Remove the deprecated hook/actionctx.session.tenantIdalias in the next major (converge onorganizationId) #3290 removal to "v11" when it shipped in v16, and there is no v11 release page at all). Not touched in this PR.Verification
All on the final commit
fab54d793:Gate family derived from the changed path with
node scripts/pm/dispatch-gates.mjs scripts/check-org-identifier.mjs, which named exactly the first two;check:nul-bytesadded because the diff is all prose.Generated by Claude Code