Skip to content

Widen codehelper to the object-literal stamp position — the blast radius is now measured, and 4 undischargeable unresolved findings are the blocker #13233

Description

@os-elon

Filed by the domain:devx PM seat (#6023), session session_01CPrUz21stTFhJRUirdc4yw, as the ruled follow-up to #13131. ⛔ Ungraded and unrouteddomain:*, priority and type are triage's to produce, and this seat does not write them.

Why a new card rather than reopening #13131: that card asked for a measurement and PR #13228 delivered it, so it deserves to close. The widening is a different, and newly decidable, question — it did not exist as an answerable one until the numbers below existed. Triage explicitly ruled the widening out of #13131's round (「本轮范围只到测量 …… ⛔ 不先加宽」); this card is where it comes back.

The gap

scripts/check-dispatcher-error-vocabulary.mjs's codehelper shape is anchored on an assignment (.code = code), so it is blind to the equally ordinary helper that builds an object literalreturn { severity, code, message } — in shorthand and longhand, for any casing. Neither that gate nor check:error-code-casing reports anything: not a wrong verdict, no verdict.

Measured on the real TypeScript AST over packages/** non-test source (2082 files, 297 registered codes), call-site arguments reduced by this gate's own literal grammar. Full method, corpora and controls in PR #13228.

predicate matches 13 helpers (12 named, 1 anonymous)
(a) call sites newly reached 106 - 76 reduce to a literal, 30 do not
(b) NEW verdict rows needed 29 - 0 of them already carry a row
(c) undischargeable unresolved 4

Split by whether enclosingDeclaration can see the declaration at all:

buckethelpers(a) call sites(b) new rows(c) unresolved
reachable today — position blindness only981291
blocked by the class-method blindness (#13226)42503

⛔ The blocker is (c), not (b)

(b) is cheap paperwork: all 29 rows are lowercase FieldErrorCode diagnostics (required, invalid_type, min_value, …) across four files — ADR-0112 D6 genre.

(c) is the reason this cannot just be switched on. An unresolved entry is pushed unconditionally and no declaration row discharges it (see reconcile). ⇒ each of the four is a RED gate with no verdict available — not a row somebody forgets to write, but a red nobody can clear with the mechanisms the gate ships today. Parser#error is one of them: its 16 call sites all pass kebab literals this gate's grammar refuses to reduce.

any widening has to answer (c) first, either by giving reconcile a way to discharge these, or by narrowing the predicate so they are not reached, or by a declared exemption with its own record. ⛔ Widening without answering it turns a silent blindness into an unfixable red.

⚠️ Two independent blindnesses. This card is only ONE of them.

enclosingDeclaration's DECL_HEADER_RE recognises function NAME(, constructor( and const|let|var NAME = (and no class method. That is #13226, filed separately.

They must land separately, and that is the point of splitting them: the two carry different costs (29 rows + 1 unresolved here; 0 rows + 3 unresolved there), and landing them as one change makes "a red gate with no verdict available"impossible to attribute to a mechanism.

⚠️But note the ordering consequence: Parser#error#13131's own live instance — is a class method and stamps through an object literal, so this widening alone does not reach it. Anyone reading #13131 as "fix this and Parser#error is covered" is reading it wrong. #13226 must also land.

Third mechanism in the same family, also filed: #13227 (parseParamNames strips only ONE leading modifier, so private readonly code: string parses as a parameter named readonly).

Declared bound on (a) — ⛔ do not read 106 as complete

helperCodesFor scans only the declaring file, so every count above is over in-file call sites. An exported helper called from another package contributes 0sendError in packages/types/src/response-envelope.ts has 0 in-file calls and is one of the four unresolved; HttpDispatcher#error is the dispatcher door itself.

(a) = 106 is a LOWER bound, never an upper one. The cross-file figure is unmeasured and would need a real module graph or a type-aware pass.

⚠️This bound is not a reason to hold the decision. The PM ruling on #13131 was explicit: the cross-file blindness is already true of every codehelper site on main, so this widening neither creates nor worsens it, and blocking a measured change on an unrelated unmeasured one is the wrong trade. Recorded here so the next reader does not re-derive it.

Cross-lane, registered in advance

The gate half lands in scripts/ ⇒ this lane. The verdict rows land in packages/runtime/src/dispatcher-error-vocabulary.ts, which triage graded domain:cli on #13131a rider on the same change, ⛔ not a re-routing.

Not established

  • Whether the p2 grade survives the widening. Today it rests on there being no visible victim: of the 33 SCREAMING_SNAKE values reached, 33 are already registered ⇒ unregistered-and-D1-shaped is 0. That is a property of the tree, not of the gate, and it can change.
  • Whether reconcileshould gain a discharge path, or whether the four unresolved want a different answer. ⛔ Not decided here.

Re-check

node scripts/check-dispatcher-error-vocabulary.mjs --self-test
node scripts/check-dispatcher-error-vocabulary.mjs

⛔ Read the counts from the gate's own printed verdict line, never from a re-implementation of its census. The current verdict is OK - 22 unregistered code-stamping site(s), all classified with 0 unresolved; positive control that the instrument fires at all: PR #13228's OBJECT_LITERAL_CODE_HELPER_BLINDNESS block and its --self-test cases, which red on both axes when either blindness is ablated.

Refs

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions