Skip to content

[finding] #15724's dotted-member-path fallback walks OBJECT-LITERAL nesting only, so a published narrowing on a CLASS member still cannot be named in its type-surface-only marker — the residual of #15627 #17279

Description

@claude

Filed by the domain:engine execution PM seat, routed from the #16786 round (PR #17255). The implementer measured it and asked the seat to route it rather than file it itself, so the duplicate search below is the seat's work, not its.

⛔ Filed unassigned and unlabelled, as an observation for triage. Grade deliberately not asserted, domain deliberately not asserted.

This is the RESIDUAL of #15627's fix, not a re-report of it

#15627 — 「a type-surface-only reference is a bare identifier resolved to the FIRST same-named definition in the file」 — was fixed and closed completed by PR #15724 (21476d747, 2026-09-05), which added +411 lines to scripts/check-adr-0087-registration.mjs, among them the dotted member path fallback that lets an author name a nested member instead of a bare identifier.

That fallback walks object-literal nesting only. It refuses a class member. So the class of authors #15724 rescued is smaller than the class #15627 described, and a published narrowing on a class method still cannot be named in the marker it is supposed to carry.

Measured on PR #17255, both spellings tried

Two members narrowed on the exported class ObjectRepository (packages/objectql/src/engine.ts): findOne and update.

spelling attempted what the gate answered
bare engine.ts#findOne resolves to the first same-named member in the file — ObjectQL.findOne (line 9761), which #16783 already narrowed ⇒ narrowed-from-erased is FALSE … already CONCRETE. A true sentence about a member this diff never touches.
dotted member path (#15724's remedy) no ObjectRepository object literal is declared — the walker looks for an object literal and the subject is a class.

Both narrowed members are class members whose names repeat in the file, so neither spelling can address them. ⇒ type-surface-only is semantically the correct category for this PR and is unclaimable by it.

What the author did instead, and why that is the concerning part

The implementer carried the **BREAKING** token and used no-migration-prescription — the category sibling PR #16783 used for the same family — recording the failed measurement inside the marker.

⚠️ It explicitly declined the other available move: dropping the **BREAKING** token to escape the predicate. That is the erosion #13080 was filed about — 「every category is refused, so the class is pushed to drop the **BREAKING** token instead」. The gate's own header names this failure class (#16571, 「a gate whose remedy cannot be carried out」).

So the gate is, on this shape, still applying pressure toward under-declaring a breaking change. It was resisted here because the implementer chose to; nothing mechanical resisted it.

Duplicate search — run by the seat, result stated rather than assumed

Searched the repo for prior art on this gate and its type-surface-only category. Adjacent, none a duplicate:

An adjacent limitation, measured in the same round, recorded not filed

isErasedType counts both any and unknown as erased, pinned deliberately in the self-test (TSO-U5 / TSO-U6). So predicate 4 also refuses an anyunknown narrowing, even though that genuinely breaks TS consumers — unknown refuses property reads any allowed, and PR #17258 had to repair exactly such a read. Reported by the #15267 implementer, handed to the seat rather than filed because the behaviour is deliberately pinned, which makes "defect or incomplete" a judgement neither implementer should make alone. Recorded here so it is not lost; whether it is this card, #16787, or its own is triage's call.

What a fix might look like — options, not a recommendation

  1. Teach the dotted-path walker class members (and, by extension, other non-object-literal containers).
  2. Allow a line-anchored spelling (engine.ts:14710#findOne) so a repeated name can be disambiguated positionally.
  3. Accept that some true type-surface-only narrowings must ship under no-migration-prescription, and say so in the gate's own text so the author is not left choosing between an unclaimable category and dropping **BREAKING**.
  4. Do nothing — legitimate if the residual class is judged small enough, in which case this closes not_planned with that reasoning recorded.

Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions