Outcome
Remove the root-only dependency obstacle identified by S1 (#1557) by giving shared snapshot and replay-target semantics honest existing package owners. This is the prerequisite only: do not create @agent-device/selectors, move src/selectors, or delete either replay selector adapter in this issue.
The governing measurement is the S1 dossier. Maintainer decision: direct selector relocation is NO-GO; this prerequisite is approved, followed by a fresh deletion-focused GO/NO-GO.
Scope
1. Extract shared snapshot semantics
Create a focused @agent-device/contracts/snapshot subpath and move only the dependency-light behavioral surface that src/selectors currently reaches through root modules:
- type/text normalization used by selectors (
normalizeType, extractNodeText, isFillableType);
- node indexing (
buildSnapshotNodeMap);
- scrollability predicates (
isScrollableType, isScrollableNodeLike);
- rectangle/viewport primitives currently in
src/utils/rect-visibility.ts;
- the selector-reached effective/on-screen visibility primitives from
mobile-snapshot-semantics.ts, including tap-point policy, effective viewport resolution, and nearest-scrollable-ancestor lookup.
Move implementations and their focused tests; repoint all existing consumers to the package subpath and delete the superseded root definitions. Do not move presentation, hidden-content summary, scroll-direction, or platform orchestration logic merely because it shares a source file today. Split mixed files at the domain boundary.
@agent-device/contracts/snapshot may depend only on @agent-device/kernel and sibling contracts internals. It must not import root src/, platforms, providers, daemon code, or selectors. Do not put these interaction/visibility policies in @agent-device/kernel; kernel remains foundational vocabulary rather than a home for dependency-light behavior.
2. Split replay target-node semantics by owner
Eliminate src/replay/target-identity-node.ts as a mixed root hub:
- Move annotation-local identity computation, shared-ID demotion, and structural-denotation comparison (
readNodeLocalIdentity, localIdentitiesEqual, idMatchCountInTree, demoteNonUniqueLocalIdentity, siblingOrdinal, readNodeStructuralDenotation, structuralDenotationsEqual, and their value types) beside the existing annotation identity/classification vocabulary in @agent-device/ad-script.
- Move daemon/command-neutral replay guard reason codes and shared guard/evidence types (
ReplayTargetGuardDenotation, REPLAY_TARGET_GUARD_MISMATCH_REASON, WAIT_LANDMARK_MISMATCH_REASON, WaitLandmarkMismatchEvidence) to @agent-device/contracts/replay.
- Repoint every production and test consumer through package façades, update exact-symbol façade pins, and delete the old root module. No compatibility re-export.
Keep package direction acyclic: kernel → contracts → ad-script; neither contracts nor ad-script may depend on ad-replay, selectors, daemon, commands, or platform implementations.
Required regression proof
- Existing selector parsing, matching, ranking, deepest-then-smallest-area selection, shared-ID demotion, replay binding, wait-landmark, and tap-point parity suites remain byte-for-byte behaviorally green.
- Add focused package tests for each extracted mixed-file boundary. For every moved rule, demonstrate a counterfactual deletion/change that makes the owning test fail.
- Preserve the TS/Swift tap-point golden-table parity; do not restate or fork the rule.
- Run
pnpm check because package exports, façade pins, and the workspace dependency graph change.
- Confirm packaged CLI output retains no unresolved
@agent-device/* runtime dependency and the packed manifest remains clean.
Remeasurement deliverable
After the extraction, post a compact measurement on this issue covering:
- remaining value imports from
src/selectors into root src;
- package dependency DAG and any cycles;
- remaining production consumers of
src/selectors;
- whether a subsequent atomic selectors cutover can delete:
src/selectors;
createDaemonReplaySelectorPort and its adapter module;
- the in-memory selector adapter;
- the dual-adapter contract/parity suite.
The selectors package receives GO only if all four deletions are possible without root imports, shims, or semantic duplication. Merely relocating the duplicate engine is NO-GO.
Stop conditions
- Any extracted package needs a root
src, platform, provider, or daemon import.
- The split creates a package cycle or requires a compatibility re-export.
- The proposed snapshot subpath becomes a general-purpose utility dump or absorbs presentation/platform policy outside the measured selector closure.
- Behavior or wire shape changes; this prerequisite is structural only.
- Tests require a second implementation of selector, visibility, identity, or tap-point semantics.
Sequencing
Base on current main. One worker, one branch, one PR. Do not start the selectors-package cutover in parallel; its authorization depends on this issue's merged result and remeasurement.
Outcome
Remove the root-only dependency obstacle identified by S1 (#1557) by giving shared snapshot and replay-target semantics honest existing package owners. This is the prerequisite only: do not create
@agent-device/selectors, movesrc/selectors, or delete either replay selector adapter in this issue.The governing measurement is the S1 dossier. Maintainer decision: direct selector relocation is NO-GO; this prerequisite is approved, followed by a fresh deletion-focused GO/NO-GO.
Scope
1. Extract shared snapshot semantics
Create a focused
@agent-device/contracts/snapshotsubpath and move only the dependency-light behavioral surface thatsrc/selectorscurrently reaches through root modules:normalizeType,extractNodeText,isFillableType);buildSnapshotNodeMap);isScrollableType,isScrollableNodeLike);src/utils/rect-visibility.ts;mobile-snapshot-semantics.ts, including tap-point policy, effective viewport resolution, and nearest-scrollable-ancestor lookup.Move implementations and their focused tests; repoint all existing consumers to the package subpath and delete the superseded root definitions. Do not move presentation, hidden-content summary, scroll-direction, or platform orchestration logic merely because it shares a source file today. Split mixed files at the domain boundary.
@agent-device/contracts/snapshotmay depend only on@agent-device/kerneland sibling contracts internals. It must not import rootsrc/, platforms, providers, daemon code, or selectors. Do not put these interaction/visibility policies in@agent-device/kernel; kernel remains foundational vocabulary rather than a home for dependency-light behavior.2. Split replay target-node semantics by owner
Eliminate
src/replay/target-identity-node.tsas a mixed root hub:readNodeLocalIdentity,localIdentitiesEqual,idMatchCountInTree,demoteNonUniqueLocalIdentity,siblingOrdinal,readNodeStructuralDenotation,structuralDenotationsEqual, and their value types) beside the existing annotation identity/classification vocabulary in@agent-device/ad-script.ReplayTargetGuardDenotation,REPLAY_TARGET_GUARD_MISMATCH_REASON,WAIT_LANDMARK_MISMATCH_REASON,WaitLandmarkMismatchEvidence) to@agent-device/contracts/replay.Keep package direction acyclic: kernel → contracts → ad-script; neither contracts nor ad-script may depend on ad-replay, selectors, daemon, commands, or platform implementations.
Required regression proof
pnpm checkbecause package exports, façade pins, and the workspace dependency graph change.@agent-device/*runtime dependency and the packed manifest remains clean.Remeasurement deliverable
After the extraction, post a compact measurement on this issue covering:
src/selectorsinto rootsrc;src/selectors;src/selectors;createDaemonReplaySelectorPortand its adapter module;The selectors package receives GO only if all four deletions are possible without root imports, shims, or semantic duplication. Merely relocating the duplicate engine is NO-GO.
Stop conditions
src, platform, provider, or daemon import.Sequencing
Base on current
main. One worker, one branch, one PR. Do not start the selectors-package cutover in parallel; its authorization depends on this issue's merged result and remeasurement.