Skip to content

[finding] check-error-code-casing's ||/?? fallback recognizer anchors on the STAMP SITE only, so our authored default in a const code = … initializer is still seen by no gate #10897

Description

@os-zhuang

Found while executing #10762 (documenting the delegation map after the #10658 / PR #10760 widening). Filed rather than absorbed: it is a different gate, a behaviour question rather than a comment one, and #10762 is comment-only by construction.

The shape

PR #10760 added a fifth recognizer to scripts/check-error-code-casing.mjs for the OUR-DEFAULT slot of a ||/?? chain. Its anchor is the position token:

re: /(?:\bcode\s*\??\s*:|\.code\s*=(?!=))\s*(?['"`])[\w$.?!()[\]|&\s]{0,80}?(?:\|\||\?\?)\s*'([a-z][a-z0-9_]*)'/g

So it reaches the chain when the chain sits at the stamp site{ code: parsed?.code || 'lit' }, err.code = e?.code ?? 'lit'. It does not reach the identical chain one indirection earlier, in a local's initializer:

constcode=parsed?.code||'lower_thing';// ← our authored default, same as aboveconsterr=newError(msg);err.code=code;throwerr;

const code = is neither code:/code?: nor .code =, so no pattern matches. A typed local does not help either: const code: string = … puts an = in the gap class, which the class refuses.

Measured, with a live positive control on both sides

Driving both gates' own exported entry points (findViolations, deriveSites) on origin/main at 9faa9bc51d:

shapecheck:dispatcher-error-vocabularycheck:error-code-casing
stamp-site { code: p?.code || 'stamp_lower_failed' }no site1 (fallback)
stamp-site err.code = p?.code || 'stamp_lower_failed'no site1 (fallback)
local-init const code = p?.code || 'local_lower_failed'no site, no unresolved0
local-init const code = p?.code || 'LOCAL_UPPER_FAILED'no site, no unresolved0 (out of its value space)
control: local-init const code = flag ? 'TERN_A' : 'TERN_B'2 sites (assignconst)n/a

The last row is the control that makes the zeros readable: the dispatcher gate does reduce and report a local initializer when every limb is a literal (#9568), so its silence on row 3 is the deliberate ALL-OR-NOTHING bound, not a broken probe. The casing-gate rows 1–2 are the matching control on the other side.

Row 3 is therefore reported by neither gate — the same "two gates, each assuming the other" configuration that check-dispatcher-error-vocabulary's own header records for owd_widening_forbidden.

Why it is arguably the casing gate's, not the dispatcher gate's

The dispatcher gate's silence is correct and should not change: under #9568 a chain with one runtime limb reduces to nothing, because harvesting the literal half would report a code the program may never stamp while staying silent about the limb it cannot see.

But that is exactly the epistemic position PR #10760 already ruled on for the stamp site, and ruled the other way, in its own words: the pattern "still only ever captures a STRING LITERAL, and a literal in our source is by construction ours … it reaches only the default WE author, which is exactly the operand ADR-0112 D1 governs." const code = parsed?.code || 'lower_thing' is our authored default by that same reasoning. The asymmetry between the two positions is an artifact of where the recognizer anchors, not a decision anyone took.

Extent today: 0

Swept 1885 non-test .ts/.tsx files under packages/ (comments masked with the gates' own maskComments) for a code-named local whose initializer is a runtime-limbed ||/?? chain with a lowercase literal default: 0 hits. Like #10762, the drift understates coverage and has no live victim today — recorded so the next reader does not have to re-derive it.

Refs

#10762 (the delegation map, where this boundary is now written down) · #10658 / PR #10760 (the widening) · #9568 (the ALL-OR-NOTHING reduction) · ADR-0112 D1

Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions