Parent: #2129
Blocked by: none. Wave 1; this is the smallest current-main slice and is intentionally independent of the other snapshot moves.
Scope — exact tracked files
Production:
src/utils/text-surface.ts
Tests:
src/utils/__tests__/text-surface.test.ts
Destination and importer edits
Move the production module to:
src/snapshot/snapshot-presentation/text-surface.ts
Move its test to:
src/snapshot/snapshot-presentation/text-surface.test.ts
Update exactly these production importers:
src/snapshot/snapshot-lines.ts
src/commands/interaction/runtime/selector-read-shared.ts
src/daemon/handlers/interaction-read.ts
Do not add a barrel, compatibility re-export, src/utils shim, or a new top-level shared zone. The destination is the existing host-side snapshot-presentation facet defined by ADR 0004.
Behavior invariants
Preserve the current readable-text/value precedence, identifier fallback, whitespace handling, preview limits, UTF-8-safe truncation behavior, and the exported TextSurfaceNode contract. The interaction-read and snapshot-lines callers must observe byte-for-byte equivalent text for the same node. This move must not change raw/regular snapshot policy, selector semantics, daemon response shape, error codes, or lazy loading.
The snapshot facet must remain free of imports from src/daemon/**; the existing snapshot-presentation boundary remains the owner of that rule.
Focused validation
Run the moved unit test plus the direct consumers:
pnpm vitest run src/snapshot/snapshot-presentation/text-surface.test.ts src/commands/interaction/runtime/selector-read.test.ts src/daemon/handlers/__tests__/interaction-read.test.ts
pnpm vitest run scripts/layering/snapshot-presentation-boundary.test.ts
If a listed consumer test path differs on current main, select the existing test that imports that consumer and record the exact substitution in the PR.
Planted-red proof
This slice adds no new structural rule. Use the existing boundary test's named positive control as the planted-red proof: its synthetic src/snapshot/** -> src/daemon/** edge must fail if the boundary matcher is weakened. Record that the positive-control test is observed red only in the temporary violation experiment and green again after removal; do not add a second rule.
Dependency order
This can land before the Android-helper, scroll/evidence, and surface-output children. The surface-output child may later extract snapshot cases from its mixed legacy output test, but it must not reintroduce this module or duplicate its tests.
Shrink target
Delete the two old src/utils files; do not duplicate their implementation. Destination production LOC, excluding the physical move, must be no greater than the old module and the change must have zero new public exports. The final diff must have no tracked src/utils/text-surface.ts or test path.
Parent: #2129
Blocked by: none. Wave 1; this is the smallest current-main slice and is intentionally independent of the other snapshot moves.
Scope — exact tracked files
Production:
src/utils/text-surface.tsTests:
src/utils/__tests__/text-surface.test.tsDestination and importer edits
Move the production module to:
src/snapshot/snapshot-presentation/text-surface.tsMove its test to:
src/snapshot/snapshot-presentation/text-surface.test.tsUpdate exactly these production importers:
src/snapshot/snapshot-lines.tssrc/commands/interaction/runtime/selector-read-shared.tssrc/daemon/handlers/interaction-read.tsDo not add a barrel, compatibility re-export,
src/utilsshim, or a new top-level shared zone. The destination is the existing host-side snapshot-presentation facet defined by ADR 0004.Behavior invariants
Preserve the current readable-text/value precedence, identifier fallback, whitespace handling, preview limits, UTF-8-safe truncation behavior, and the exported
TextSurfaceNodecontract. The interaction-read and snapshot-lines callers must observe byte-for-byte equivalent text for the same node. This move must not change raw/regular snapshot policy, selector semantics, daemon response shape, error codes, or lazy loading.The snapshot facet must remain free of imports from
src/daemon/**; the existing snapshot-presentation boundary remains the owner of that rule.Focused validation
Run the moved unit test plus the direct consumers:
pnpm vitest run src/snapshot/snapshot-presentation/text-surface.test.ts src/commands/interaction/runtime/selector-read.test.ts src/daemon/handlers/__tests__/interaction-read.test.tspnpm vitest run scripts/layering/snapshot-presentation-boundary.test.tsIf a listed consumer test path differs on current main, select the existing test that imports that consumer and record the exact substitution in the PR.
Planted-red proof
This slice adds no new structural rule. Use the existing boundary test's named positive control as the planted-red proof: its synthetic
src/snapshot/** -> src/daemon/**edge must fail if the boundary matcher is weakened. Record that the positive-control test is observed red only in the temporary violation experiment and green again after removal; do not add a second rule.Dependency order
This can land before the Android-helper, scroll/evidence, and surface-output children. The surface-output child may later extract snapshot cases from its mixed legacy output test, but it must not reintroduce this module or duplicate its tests.
Shrink target
Delete the two old
src/utilsfiles; do not duplicate their implementation. Destination production LOC, excluding the physical move, must be no greater than the old module and the change must have zero new public exports. The final diff must have no trackedsrc/utils/text-surface.tsor test path.