What
Found while implementing round 16's fix for #2632 (PR #2612, docs/plans/issue-2088.md).
introducesShadowedBinding's switch_body case (src/extractors/javascript.ts, the arm handling an unbraced case/default clause) checks each statement for lexical_declaration (via declarationDeclaresName) and, by name field, function_declaration/generator_function_declaration/class_declaration — the identical enumeration its statement_block case uses, and the identical enumeration that (pre-round-16) was missing using_declaration in both places. Round 16 closed the gap for condition 4's resolution question (findResolvingScopeNode) by adding a using_declaration disjunct scoped specifically to a statement_block ancestor — matching exactly what #2632 itself described (a block-scoped using shadow) and nothing more.
The switch_body case carries the identical enumeration gap: an unbraced case/default clause's own using run = mk(); is invisible to introducesShadowedBinding's switch_body arm for the identical reason statement_block's was, and — by the same reasoning #2632 itself gives for why this is a genuine (not merely conservative) gap for condition 4's resolution question specifically — a same-named module-level decoy shadowed only by such a case-level using declaration would resolve to the decoy with full confidence via findResolvingScopeNode, rather than failing safe.
This is not covered by round 16's own fix: that fix's new disjunct in findResolvingScopeNode is gated on current.type === 'statement_block' specifically, matching #2632's own repro shape exactly — it does not check a switch_body ancestor at all.
Direction
Per the exclusion ledger's now-explicit direction labels (see docs/plans/issue-2088.md's Success Criteria section, round 16): this is UNDER-escape if it manifests for condition 4's resolution question, the identical direction #2632 itself is — live code would be reported dead, not a recall trade-off. Per the standing rule the same round establishes, this may not be filed as an accepted limitation once confirmed; it must be fixed. This issue exists to track investigation and closure, not to document it as permanent scope.
Suggested next step
Confirm the switch_body case actually reaches this code path for an unbraced case/default clause containing a using declaration (verify against tree-sitter-javascript@0.25.0's grammar the same way #2632 did for statement_block), then close it the same way round 16 closed #2632: a matching disjunct in findResolvingScopeNode (not a widening of introducesShadowedBinding, for the same reason #2632's own round-16 fix avoided that), mirrored in the Rust engine, with its own escape-fallback fixture.
Where
What
Found while implementing round 16's fix for #2632 (PR #2612, docs/plans/issue-2088.md).
introducesShadowedBinding's switch_body case (src/extractors/javascript.ts, the arm handling an unbraced case/default clause) checks each statement for lexical_declaration (via declarationDeclaresName) and, by name field, function_declaration/generator_function_declaration/class_declaration — the identical enumeration its statement_block case uses, and the identical enumeration that (pre-round-16) was missing using_declaration in both places. Round 16 closed the gap for condition 4's resolution question (findResolvingScopeNode) by adding a using_declaration disjunct scoped specifically to a statement_block ancestor — matching exactly what #2632 itself described (a block-scoped using shadow) and nothing more.
The switch_body case carries the identical enumeration gap: an unbraced case/default clause's own using run = mk(); is invisible to introducesShadowedBinding's switch_body arm for the identical reason statement_block's was, and — by the same reasoning #2632 itself gives for why this is a genuine (not merely conservative) gap for condition 4's resolution question specifically — a same-named module-level decoy shadowed only by such a case-level using declaration would resolve to the decoy with full confidence via findResolvingScopeNode, rather than failing safe.
This is not covered by round 16's own fix: that fix's new disjunct in findResolvingScopeNode is gated on current.type === 'statement_block' specifically, matching #2632's own repro shape exactly — it does not check a switch_body ancestor at all.
Direction
Per the exclusion ledger's now-explicit direction labels (see docs/plans/issue-2088.md's Success Criteria section, round 16): this is UNDER-escape if it manifests for condition 4's resolution question, the identical direction #2632 itself is — live code would be reported dead, not a recall trade-off. Per the standing rule the same round establishes, this may not be filed as an accepted limitation once confirmed; it must be fixed. This issue exists to track investigation and closure, not to document it as permanent scope.
Suggested next step
Confirm the switch_body case actually reaches this code path for an unbraced case/default clause containing a using declaration (verify against tree-sitter-javascript@0.25.0's grammar the same way #2632 did for statement_block), then close it the same way round 16 closed #2632: a matching disjunct in findResolvingScopeNode (not a widening of introducesShadowedBinding, for the same reason #2632's own round-16 fix avoided that), mirrored in the Rust engine, with its own escape-fallback fixture.
Where