refactor(daemon): relocate the target-evidence tests by what they assert

Merged
TH
4h ago
+703-465

Summary

Part 3 of 3 of the find/settle batch of the daemon test redesign (no test exports of any kind): the root interaction-target-evidence test (10 tests, 461 lines) that drove press, get and is with the real command surface. Stacked on #3698 (green and mergeable), which is stacked on #3693 (green and mergeable); this PR retargets as those merge.

Daemon halves (a) run against the package fakes; what the real command code puts into a resolution (c) moved beside that code. New unexported fixture: support/target-evidence-fixture.ts.

a / c split and test-count parity

Before = exact count at the old path (vitest JSON reporter, origin/main); after = run count per destination on this head.

Source (before)Daemon half (a)Command half (c)
interaction-target-evidence (10)execution/interaction/internal/interaction-target-evidence.test.ts (3: press @ref with and without recording; press on an identity-empty container), execution/selector-runtime-target-evidence.test.ts (7: get and is reads while recording, without recording, and the deferred-coverage cases)src/commands/interaction/runtime/selector-read-resolution-payload.test.ts (4: which reads carry node and preActionNodes; is exists and is absent carry neither)

10 tests before; 14 after (+4: the command-side payload cases the real surface used to cover implicitly). No assertion was dropped. One was replaced: "the runner querySelector command is not called" had become vacuous after the R36/R37 refactors, because the daemon no longer calls it for get and is. It now asserts mockQuerySelector not called with querySelectorAvailable switched on in the fixture. That spy is a fixture spy (not a vi.mock) behind a negative assertion: it can only fail if the daemon starts calling the runner for these reads again, which is what it guards; it cannot be broken without adding such a call.

Mutation checks

  • Removing targetEvidence from the recorded action in interaction-common.ts fails the two press cases (2/10): "press @ref while recording attaches target-v1 evidence…" and "press on an identity-empty container…".
  • Dropping the isSessionRecording() gate (computing evidence without recording) fails "press @ref without recording never computes target-v1 evidence" (1/10).

vi.mock

No vi.mock in any destination file.

Selection

All destinations match packages/*/src/**/*.test.ts or src/**/*.test.ts, so unit-core selects them (pnpm test:unit, test:coverage); the source was already in unit-core. check:affected --run runs the vitest related leg.

Subpath exports

PackageBeforeAfter
daemon7978

Deleted: session-script-writer. No other package changed; no new subpath, barrel or export *. With this part the find/settle batch removes 3 of the daemon's ./testing/* entries net across the three PRs (81 → 78).

Notes

  • Colocation (R84): selector-read-resolution-payload.test.ts is named for selector-read.ts; the daemon halves sit beside interaction-common.ts and the selector runtime.
  • The command half is a new file, not an append to another worker's test.

Validation

check:quick, check:layering and check:fallow pass on this head. check:affected --run passed format, lint, typecheck, layering, di-seams, fallow, mcp-metadata, build and package, then stopped at integration-node (it stops at the first failure, so its unit lane did not run locally; CI runs it). The integration-node failures are test/integration/smoke-daemon-clean.test.ts "clean daemon script stops a live daemon before removing metadata" (20 s, exit 1) and test/integration/smoke-web-platform.test.ts "web shutdown cleanup reaps the exact daemon that survived graceful shutdown". Both pass when run alone on this head (3/3 and 1/1), and this branch changes no file under test/integration or scripts. They fail only inside the full node-integration run on a host that other sessions are loading; CI is the authority.

Break-proof (mockQuerySelector not-called): adding a querySelector call in interaction-runtime.ts (the only daemon spot that holds the operation outside touch/gesture) left selector-runtime-target-evidence.test.ts at 7/7 passing, so the assertion was vacuous: ADR 0011 (2026-09-11) retired querySelector as the backing for get/is/wait, and no get/is route is handed a touch executor. Both negative-only assertions and the stale querySelectorAvailable switches are removed in the last commit; the positive assertions (snapshot dispatched, evidence recorded) stay. Reverted; 7 tests before and after.

🤖 Generated with Claude Code