Repository navigation
finding: two lint readers cannot move onto recordsOf — dropping a member renumbers the finding paths #15494 pins #15740
Description
Activity
Graded →
pm:awaiting-maintainer(decision),domain:devx— PM seatdomain:devx, session012zGPuVVX3deAx9LdjK8jCk.The collision is real and is two contracts answering two questions with one return value: #15494 pins finding paths to the author's file (
objects[1].highlightFields[1]), #15552 accepted renumbering forstack.objects. Which governs, and whetherpackages/lint/src/object-graph.tsgains an index-preserving companion, is a published-surface decision for the maintainer.option cost benefit A Accept renumbering everywhere; re-point the two readers, update the #15494 pins, state once that a positional index counts readable entries silently degrades every positional path a stack with a junk member produces cheapest, one predicate B Add entriesOf(each readable record with the index it occupied in the RAW list) besiderecordsOf; both pins holdchanges an exported surface the two contracts stop conflicting; #15728's positional readers get the same answer C Leave the two readers on the raw array and exempt positional readers from the one-copy rule keeps copies alive for a reason not in the predicate; #15728 half-closable honest, zero change Seat recommendation: B. Decides #15728's positional rows as well. Entered in seat post #6023's decision box; not nudged.
Generated by Claude Code
- added a commit that references this issue
on Sep 6, 2026 Input from #15728's landing (PM seat
domain:devx @ objectstack, sessionsession_01Vbw3RPgdtqesx4azk9SbW8, 2026-09-06T12:09Z) — no state change on this card.PR #16286 (Part of #15728) re-points four page-walk readers that emit positional
pages[N].sourcepaths ontocollectionEntries(packages/lint/src/collection-entries.ts:68, #6662) instead ofrecordsOf: it drops non-record members inside the reader and hands each survivor the path it actually sits at, so no positional path is renumbered. That is evidence bearing on this card's option 2 ("an index-preserving companion inobject-graph.ts"): a companion with that property already exists in the package and is the in-package idiom for finding-emitting walks. It does not decide this card — its two readers (validate-object-field-refs.ts,validate-list-view-field-refs.ts) pin anobjects[N]…shape and theirCOPY_LEDGERrows were deliberately left in place by #16286 because this card owns them. Whoever picks this up can cost option 2 againstcollectionEntriesbefore assuming a new reader is needed.
Generated by Claude Code
状态转换:
pm:awaiting-maintainer→pm:queue(2026-09-09)维护者回批逐字:「C 桶那 24 张的批量转
pm:queue同意」。判据:两个 lint 读取方迁不到
recordsOf,因为删掉一个成员会重编号 #15494 钉住的 finding 路径。⇒ 这是技术任务之间的顺序与依赖(先改 pin 还是先改读取方),SKILL.md〈升级与决策〉把它逐字列在具名不升级类里:「技术任务间的顺序与依赖」。⛔ 无产品语义、⛔ 无公开契约movement。tooling、domain:devx、finding留下。⚠️ 根因见 #17017。
Generated by Claude Code
- added a commit that references this issue
on Sep 9, 2026 Ruling recorded — 2, through the companion that already exists: the two readers re-point onto
collectionEntries, which preserves the author's index; the private copies go (director seat, decision batch #123 item 2, 2026-09-12)Maintainer, verbatim (live PM chat, 2026-09-12T07:1xZ), to decision batch #123 presented as
1B·2(2)·3D·4C·5(1): 「同意」.Derived first from the long-term axis: a diagnostic path always names the position in the author's file, and one shared implementation serves every reader. The triage speed-read priced option 2 as a new export; measured, the index-preserving companion already exists —
collectionEntries(packages/lint/src/collection-entries.ts:68, #6662), which PR #16286 (Part of #15728) already used for four page-walk readers that emit positionalpages[N].sourcepaths. So option 2 costs no public surface, and axis ④'s only objection dissolves. Option 1 would institutionalise a wrong position; option 3 keeps two private copies alive against the one-copy gate.What is ruled
validate-object-field-refs.tsandvalidate-list-view-field-refs.tsre-point ontocollectionEntries; their private coercion copies are deleted.- indexObjectGraph throws a TypeError on a null entry in stack.objects — every reference-integrity rule crashes on it #15494's pins (
objects[1].highlightFields[1],objects[1].listViews.all.columns[1]) stay green unchanged — that is the acceptance. COPY_LEDGERandUNGUARDED_ALLOWANCEincollection-coercion-single-copy.test.tsdrop these two entries.- finding: sixteen lint collection readers still hold a private copy of the
recordsOfcoercion #15728's remaining positional readers follow the same route; skills(pm-dispatch):pm:awaiting-maintainerhas a semantic contract and zero machine carrier — 49 of 55 cards in it are waiting for a JUDGEMENT, not for a hand, and nothing can tell the two apart #17017 (root cause) is unchanged by this ruling. Clause-②: no.
State
needs-user-decision→pm:queue;domain:devx/tooling/priority:p3kept.
Generated by Claude Code
Found while implementing #15636; filed as a finding only, not claimed.
#15636 re-pointed 20 lint collection readers onto the shared guarded
recordsOf. Two of the 23 it set out to re-point could NOT be re-pointed, and the reason is a contract collision worth settling once rather than rediscovering per reader.What collides
recordsOfDROPS a non-record member. Every reader that reports a positional path therefore renumbers: an author who writesis told about
objects[0]where their file says the object is the second item.#15552 already ruled that this is acceptable for
stack.objects—non-record-object-entry.test.tssays the index "is allowed to differ … That is a difference in the path, never in whether the object was judged." But #15494 ruled the OTHER way for the reference-integrity suite, and pinned it:packages/lint/src/reference-integrity-suite.test.tsassertsvalidateObjectFieldRefsreportsobjects[1].highlightFields[1]andvalidateListViewFieldRefsreportsobjects[1].listViews.all.columns[1], with the comment "the guard drops it from the GRAPH, while each member's own loop keeps walking the raw array, so reported positions stay stable against the author's file."So
validate-object-field-refs.tsandvalidate-list-view-field-refs.tskeep a private copy of the coercion not because anyone forgot them, but because the copy is what supplies the INDEX. Both already guard every member withisRecinside the loop, so neither has ever thrown; re-pointing them buys no crash fix and costs the pinned path. #15636 measured that directly: re-pointing them turned those two pins red and nothing else, and the change was reverted to byte-identical-to-main.They are carried in
COPY_LEDGERandUNGUARDED_ALLOWANCEinpackages/lint/src/collection-coercion-single-copy.test.ts, both dated and pointing here.The decision
Roughly three ways out, and this needs a maintainer to pick one before anybody re-points these two (or the sixteen in #15728, several of which build positional paths the same way):
object-graph.ts— something like anentriesOfreturning each readable record with the index it occupied in the RAW list. One predicate still, two readings of it, and every reader can then report the author's position while skipping what it cannot read. This is the only option that satisfies both pins at once, and it is a change to a shared module.Option 2 looks right from here — the two contracts are not actually in conflict, they are two different questions being answered by one return value — but it changes an exported surface, so it is not a developer's call.
Context
recordsOfcoercion #15728 owns the sixteen remaining copies that do not crash.recordsOfand thestack.objectshalf.Generated by Claude Code