Parent: #2129
Blocked by: #2133, #2134, and #2135. Wave 3; the formatter consumes the final text-surface, Android-helper, repeated-nav, and scroll/evidence paths.
Scope — exact tracked files
Production:
src/utils/doctor-output.ts
src/utils/doctor-progress.ts
src/utils/duration-format.ts
src/utils/error-candidates.ts
src/utils/output.ts
src/utils/result-serialization.ts
src/utils/screenshot-result.ts
src/utils/status-markers.ts
Tests:
src/utils/__tests__/error-candidates.test.ts
src/utils/__tests__/output-error.test.ts
src/utils/__tests__/output.test.ts
src/utils/__tests__/result-serialization.test.ts
Destination and importer edits
Move/split by the existing owner boundaries; no shared output replacement or internal barrel:
output.ts -> src/commands/output/json.ts, error.ts, snapshot.ts, diff.ts, and color.ts by exported function (printJson, printHumanError, formatSnapshotText, the two diff formatters, supportsColor, and colorize)
doctor-output.ts -> src/daemon/handlers/doctor-output.ts
doctor-progress.ts -> src/daemon/client/doctor-progress.ts
status-markers.ts -> src/daemon/handlers/status-markers.ts
duration-format.ts -> src/replay/test/duration-format.ts
screenshot-result.ts -> src/client/screenshot-result.ts
buildAppIdentifiers and buildDeviceIdentifiers from result-serialization.ts -> src/client/client-identifiers.ts
- the session/device/deploy/install/open/close/snapshot serializers from
result-serialization.ts -> src/daemon/result-serialization.ts
Move/split tests:
error-candidates.test.ts -> src/daemon/handlers/__tests__/interaction-error-candidates.test.ts
output-error.test.ts and the error cases from output.test.ts -> src/commands/output/error.test.ts
- the snapshot cases from
output.test.ts -> src/commands/output/snapshot.test.ts
- the diff/color cases from
output.test.ts -> src/commands/output/diff.test.ts and src/commands/output/color.test.ts
- the identifier/serializer sections of
result-serialization.test.ts -> src/client/__tests__/client-identifiers.test.ts and src/daemon/__tests__/result-serialization.test.ts
Update exact production importers:
src/cli.ts, src/cli/commands/shared.ts, src/cli/commands/web.ts, src/replay/test/reporting.ts -> command JSON output
src/cli.ts, src/mcp/tool-error.ts only through their existing owners -> human error/candidate rendering as applicable
src/commands/capture/output.ts, scripts/__tests__/help-conformance-sample-producers.ts -> snapshot output
src/cli/commands/screenshot.ts -> diff output and client screenshot-result
src/cli/commands/proxy.ts, src/replay/test/progress.ts, src/replay/test/reporters/default.ts, src/__tests__/proxy-command.test.ts -> color output
src/replay/test/progress.ts, src/replay/test/reporters/default.ts, src/replay/test/trace.ts -> replay duration
src/replay/test/progress.ts and src/daemon/handlers/doctor-output.ts -> status markers
src/daemon/handlers/session-doctor-output.ts, src/commands/management/output.ts, src/daemon/client/daemon-client-progress.ts -> doctor output/progress
src/agent-device-client.ts, src/cli/commands/screenshot.ts -> client screenshot-result
src/client/client-normalizers.ts -> client identifiers
src/commands/capture/output.ts, src/commands/management/output.ts, src/daemon/handlers/session-app-deployment.ts, src/daemon/handlers/session-app-source-deployment.ts, src/mcp/tool-result.ts -> their exact serializer functions
src/daemon/handlers/find-match-resolution.ts, src/daemon/handlers/interaction-ambiguity-publication.ts, src/mcp/tool-error.ts, src/mcp/tool-ref-pins.ts -> interaction error candidates
The final destination paths must stay in existing ranked zones (commands, client, daemon, or replay); do not add a new top-level output or common zone.
Behavior invariants
Preserve every human/JSON output byte, snapshot raw/regular/unchanged/visibility/warning/Android-helper rendering, diff formatting, color/TTY detection, candidate caps and ref-generation pinning, doctor marker/progress state, duration formatting, screenshot overlay/result parsing, and all public client/daemon/MCP serializer keys, omission rules, success text, and error behavior. Preserve help-conformance sample output and lazy CLI closure. No wire shape, retry, timeout, snapshot policy, or MCP projection changes.
The mixed 1,861-line output test must be split along these exact production owners and no resulting test may remain over the 1,000-line ratchet.
Focused validation
Run all moved output/serializer tests, then:
pnpm vitest run src/commands/output/*.test.ts src/daemon/handlers/__tests__/interaction-error-candidates.test.ts src/client/__tests__/client-identifiers.test.ts src/daemon/__tests__/result-serialization.test.ts
- the existing CLI, capture, management, MCP, replay, screenshot, and help-conformance tests
pnpm vitest run scripts/__tests__/test-file-size-ratchet.test.ts
pnpm check:affected --run
Planted-red proof
No new structural rule is added. Temporarily alter one help-conformance sample, omit one serializer key, or disable candidate ref pinning and observe the independent named test fail before restoring the original. The split must not turn tests into comparisons against the same moved implementation.
Dependency order
Start only after #2133, #2134, and #2135. The terminal child is blocked by this child. The transport child remains independent.
Shrink target
Delete all eight old production modules and four old utility tests. Split output.ts and its 1,861-line test below the file-size ratchet. After discounting physical moves, the aggregate production diff must be negative (additions minus deletions <= -1); remove redundant re-export/helper lines rather than adding a shared facade.
Parent: #2129
Blocked by: #2133, #2134, and #2135. Wave 3; the formatter consumes the final text-surface, Android-helper, repeated-nav, and scroll/evidence paths.
Scope — exact tracked files
Production:
src/utils/doctor-output.tssrc/utils/doctor-progress.tssrc/utils/duration-format.tssrc/utils/error-candidates.tssrc/utils/output.tssrc/utils/result-serialization.tssrc/utils/screenshot-result.tssrc/utils/status-markers.tsTests:
src/utils/__tests__/error-candidates.test.tssrc/utils/__tests__/output-error.test.tssrc/utils/__tests__/output.test.tssrc/utils/__tests__/result-serialization.test.tsDestination and importer edits
Move/split by the existing owner boundaries; no shared output replacement or internal barrel:
output.ts->src/commands/output/json.ts,error.ts,snapshot.ts,diff.ts, andcolor.tsby exported function (printJson,printHumanError,formatSnapshotText, the two diff formatters,supportsColor, andcolorize)doctor-output.ts->src/daemon/handlers/doctor-output.tsdoctor-progress.ts->src/daemon/client/doctor-progress.tsstatus-markers.ts->src/daemon/handlers/status-markers.tsduration-format.ts->src/replay/test/duration-format.tsscreenshot-result.ts->src/client/screenshot-result.tsbuildAppIdentifiersandbuildDeviceIdentifiersfromresult-serialization.ts->src/client/client-identifiers.tsresult-serialization.ts->src/daemon/result-serialization.tsMove/split tests:
error-candidates.test.ts->src/daemon/handlers/__tests__/interaction-error-candidates.test.tsoutput-error.test.tsand the error cases fromoutput.test.ts->src/commands/output/error.test.tsoutput.test.ts->src/commands/output/snapshot.test.tsoutput.test.ts->src/commands/output/diff.test.tsandsrc/commands/output/color.test.tsresult-serialization.test.ts->src/client/__tests__/client-identifiers.test.tsandsrc/daemon/__tests__/result-serialization.test.tsUpdate exact production importers:
src/cli.ts,src/cli/commands/shared.ts,src/cli/commands/web.ts,src/replay/test/reporting.ts-> command JSON outputsrc/cli.ts,src/mcp/tool-error.tsonly through their existing owners -> human error/candidate rendering as applicablesrc/commands/capture/output.ts,scripts/__tests__/help-conformance-sample-producers.ts-> snapshot outputsrc/cli/commands/screenshot.ts-> diff output and client screenshot-resultsrc/cli/commands/proxy.ts,src/replay/test/progress.ts,src/replay/test/reporters/default.ts,src/__tests__/proxy-command.test.ts-> color outputsrc/replay/test/progress.ts,src/replay/test/reporters/default.ts,src/replay/test/trace.ts-> replay durationsrc/replay/test/progress.tsandsrc/daemon/handlers/doctor-output.ts-> status markerssrc/daemon/handlers/session-doctor-output.ts,src/commands/management/output.ts,src/daemon/client/daemon-client-progress.ts-> doctor output/progresssrc/agent-device-client.ts,src/cli/commands/screenshot.ts-> client screenshot-resultsrc/client/client-normalizers.ts-> client identifierssrc/commands/capture/output.ts,src/commands/management/output.ts,src/daemon/handlers/session-app-deployment.ts,src/daemon/handlers/session-app-source-deployment.ts,src/mcp/tool-result.ts-> their exact serializer functionssrc/daemon/handlers/find-match-resolution.ts,src/daemon/handlers/interaction-ambiguity-publication.ts,src/mcp/tool-error.ts,src/mcp/tool-ref-pins.ts-> interaction error candidatesThe final destination paths must stay in existing ranked zones (
commands,client,daemon, orreplay); do not add a new top-leveloutputorcommonzone.Behavior invariants
Preserve every human/JSON output byte, snapshot raw/regular/unchanged/visibility/warning/Android-helper rendering, diff formatting, color/TTY detection, candidate caps and ref-generation pinning, doctor marker/progress state, duration formatting, screenshot overlay/result parsing, and all public client/daemon/MCP serializer keys, omission rules, success text, and error behavior. Preserve help-conformance sample output and lazy CLI closure. No wire shape, retry, timeout, snapshot policy, or MCP projection changes.
The mixed 1,861-line output test must be split along these exact production owners and no resulting test may remain over the 1,000-line ratchet.
Focused validation
Run all moved output/serializer tests, then:
pnpm vitest run src/commands/output/*.test.ts src/daemon/handlers/__tests__/interaction-error-candidates.test.ts src/client/__tests__/client-identifiers.test.ts src/daemon/__tests__/result-serialization.test.tspnpm vitest run scripts/__tests__/test-file-size-ratchet.test.tspnpm check:affected --runPlanted-red proof
No new structural rule is added. Temporarily alter one help-conformance sample, omit one serializer key, or disable candidate ref pinning and observe the independent named test fail before restoring the original. The split must not turn tests into comparisons against the same moved implementation.
Dependency order
Start only after #2133, #2134, and #2135. The terminal child is blocked by this child. The transport child remains independent.
Shrink target
Delete all eight old production modules and four old utility tests. Split
output.tsand its 1,861-line test below the file-size ratchet. After discounting physical moves, the aggregate production diff must be negative (additions minus deletions <= -1); remove redundant re-export/helper lines rather than adding a shared facade.