Skip to content

refactor: extract shared snapshot and replay identity semantics before selector packaging #1581

Description

@thymikee

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:

  1. remaining value imports from src/selectors into root src;
  2. package dependency DAG and any cycles;
  3. remaining production consumers of src/selectors;
  4. 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.

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