You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[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
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.
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 bothany and unknown as erased, pinned deliberately in the self-test (TSO-U5 / TSO-U6). So predicate 4 also refuses an any → unknown 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
Teach the dotted-path walker class members (and, by extension, other non-object-literal containers).
Allow a line-anchored spelling (engine.ts:14710#findOne) so a repeated name can be disambiguated positionally.
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**.
Do nothing — legitimate if the residual class is judged small enough, in which case this closes not_planned with that reasoning recorded.
Filed by the
domain:engineexecution 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-onlyreference is a bare identifier resolved to the FIRST same-named definition in the file」 — was fixed and closedcompletedby PR #15724 (21476d747, 2026-09-05), which added +411 lines toscripts/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):findOneandupdate.engine.ts#findOneObjectQL.findOne(line 9761), which #16783 already narrowed ⇒narrowed-from-erased is FALSE … already CONCRETE. A true sentence about a member this diff never touches.#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-onlyis 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 usedno-migration-prescription— the category sibling PR #16783 used for the same family — recording the failed measurement inside the marker.**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-onlycategory. Adjacent, none a duplicate:type-surface-onlyreference is a bare identifier resolved to the FIRST same-named definition in the file, so a nested SDK member with a common name (oauth.applications.get) cannot be named — PR #15445 had to leave its fourth narrowed member out of its marker #15627 (closedcompleted, fixed by feat(devx): accept a dotted member path in ADR-0087 type-surface-only references #15724) — the bare-identifier limb. This card is the residual its fix left.check-adr-0087-registration'stype-surface-onlycategory is unclaimable by the class it was built for: TWO predicates refuse it whenever the narrowed declaration lives inpackages/spec/src/contracts/**#16787 (OPEN,pm:queue,domain:devx, p3) — 「unclaimable by the class it was built for: TWO predicates refuse it whenever the narrowed declaration lives inpackages/spec/src/contracts/**」. Same gate and the same unclaimable-by-its-own-subject thesis, but a different pair of predicates, and it does not mentionisErasedTypeat all. Nearest neighbour; triage may reasonably decide to fold this into it.**BREAKING**token instead #13080 (closed) — the erosion this shape pushes toward.type-surface-onlydescribes "the only thing that moved is a type annotation", so it has no word for a narrowing whose diff ALSO changes the body — which is the only way some erased returns can be bound at all #15674, check-adr-0087-registration: readDeclaredTypeSurface does not return a declared type for interface/class/enum (it returns the symbol name) or for multi-line type aliases (truncated at the first semicolon) #15489, check-adr-0087-registration has no verifiable disposition for a published runtime-interface change that was concrete at base and ships a code prescription — every category refuses #13079's changeset #14502, [finding]check-adr-0087-registration.mjs's own header lists FIVE disposition markers and omitstype-surface-only— a third copy that the file's both-directions pin cannot see #15915, [finding] An accept-set narrowing owes a**BREAKING**banner incorebut not inplatform-objects— and the ADR-0087 classifier reads the banner #16421 — same gate, other limbs.An adjacent limitation, measured in the same round, recorded not filed
isErasedTypecounts bothanyandunknownas erased, pinned deliberately in the self-test (TSO-U5 / TSO-U6). So predicate 4 also refuses anany→unknownnarrowing, even though that genuinely breaks TS consumers —unknownrefuses property readsanyallowed, 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
engine.ts:14710#findOne) so a repeated name can be disambiguated positionally.type-surface-onlynarrowings must ship underno-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**.not_plannedwith that reasoning recorded.Generated by Claude Code