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
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
recordsOf DROPS a non-record member. Every reader that reports a positional path therefore renumbers: an author who writes
objects:
-
- name: crm_lead
is 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.ts says 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.ts asserts validateObjectFieldRefs reports objects[1].highlightFields[1] and validateListViewFieldRefs reports objects[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.ts and validate-list-view-field-refs.ts keep 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 with isRec inside 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_LEDGER and UNGUARDED_ALLOWANCE in packages/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):
Add an index-preserving companion in object-graph.ts — something like an entriesOf returning 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.
Leave the two as they are permanently and record that positional readers are exempt from the one-copy rule. Honest, but it keeps a copy of the predicate alive for reasons that are not in the predicate.
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.
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