Skip to content

selectors: land resolveSelectorChainDomain + replay single-pass target resolution (split from #1690) #1978

Description

@thymikee

Split out of #1971 per review: #1690's scope and STOP conditions exclude selector-resolution and replay changes, but the find-index implementation produced a sound, independently valuable optimization there.

Ready on branch tier3/selector-replay-domain (commits from #1971's review cycle, adversarially reviewed):

  • New resolveSelectorChainDomain in packages/selectors/src/internal/resolve.ts: returns the matched-node set the deciding pass already collected — the winning alternative's when one resolves, else the first alternative with any match (exactly listSelectorChainMatches' selection rule, verified over a 112-combination semantic-parity fuzz vs merge-base including winner-in-later-alternative, empty trees, rectless nodes, requireRect/allowDisambiguation toggles).
  • resolveRecordedTarget (internal/replay.ts) drops its redundant second full-tree scan on both legs: resolved leg {iterated 2, filter 1→0}; unresolved leg {filter 1→0}.
  • observeTreeTraversals test helper widened to count the full array surface (flatMap/forEach/reduce/some) — the previous counter was blind to flatMap, hiding 4n uncounted scans per ambiguous candidate.
  • listSelectorChainMatches keeps its three other callers; published ./ast surface unchanged.

Red-first evidence and scan-count tables are in #1971's REVIEW.md/RESULT.md history.

Known adjacent defect, intentionally out of scope here: resolve-with-policy.ts:66-89 still double-scans for disambiguate/fail-closed rows (#1970) — folding it needs the first-alternative-vs-winner semantic decision documented there.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions