Skip to content

feat: typed command results, batch 2 (home/back/rotate/app-switcher) — Phase 2#934

Merged
thymikee merged 1 commit into
mainfrom
refactor/phase2-typed-results-batch2
Jun 29, 2026
Merged

feat: typed command results, batch 2 (home/back/rotate/app-switcher) — Phase 2#934
thymikee merged 1 commit into
mainfrom
refactor/phase2-typed-results-batch2

Conversation

@thymikee

Copy link
Copy Markdown
Member

What

Phase 2 (typed results) batch 2: wire four more commands into the CommandResultMap spine, narrowing their public client return types from the open DaemonResponseData bag to closed shapes. Continues #913 (batch 1: boot/shutdown/viewport).

Shapes (each grounded in the handler's literal return)

Re-read of src/core/dispatch.ts DISPATCH_HANDLERS — a fixed action discriminant plus the always-present successText message:

command result
home { action: 'home'; message }
back { action: 'back'; mode: BackMode; message }
rotate { action: 'rotate'; orientation: DeviceRotation; message }
app-switcher { action: 'app-switcher'; message }

The handlers spread nothing else, so the shapes are closed. Consistent with the viewport contract, the generic-dispatch Android dialog-recovery warning annotation is intentionally not part of the contract (it's a rare runtime annotation, not the command's result shape).

Mechanics (same template as batch 1)

  • New src/contracts/navigation.ts holds the four closed types (moved out of the client-types.ts mirror); the now-unused CommandActionResult helper is deleted.
  • CommandResultMap gains home/back/rotate/'app-switcher'; the client methods return CommandResult<'name'>.
  • Public export names preserved (HomeCommandResult, … re-exported via client-types.tsindex.ts), so no API break.
  • The exact-equality parity test now pins CommandResult<name> === its contract type for all 10 migrated commands; the public-root export test gains back/rotate samples.

Why these four / not the rest yet

clipboard is also closeable (a discriminated union) but its CLI formatter passes the result straight into a Record<string, unknown> param, so it needs a careful follow-up. keyboard / alert / app-state / wait are genuinely platform-/action-conditional (open) — they stay as the existing mirror until modeled as unions in later batches. This keeps each batch grounded and low-risk, per the plan's per-command discipline.

Verification

  • tsc --noEmit exit 0
  • oxfmt + oxlint --deny-warnings clean
  • fallow audit --base origin/main clean
  • vitest core/contracts/client/commands → 104 files / 791 tests pass (the one failure was the known-flaky daemon-client mid-stream-abort test — passes 30/30 in isolation, unrelated to types)
  • Layering Guard grep empty

Remaining for Phase 2

~50 commands still on the Record default (most genuinely dynamic and deliberately left open per the spine's doctrine); clipboard next; then the platform-union commands; then (b) the TypedError graft and (c) deleting the client-types.ts result-type mirror once enough is migrated.

…— Phase 2

Wire four more commands into the CommandResultMap spine, narrowing their public
client return types from the open DaemonResponseData bag to closed shapes.

Each shape is grounded in a re-read of the dispatch handler's literal return
(src/core/dispatch.ts DISPATCH_HANDLERS) — a fixed `action` discriminant plus
the always-present successText `message`:

- home         -> { action: 'home'; message }
- back         -> { action: 'back'; mode: BackMode; message }
- rotate       -> { action: 'rotate'; orientation: DeviceRotation; message }
- app-switcher -> { action: 'app-switcher'; message }

The handlers spread nothing else, so the shapes are closed (consistent with the
viewport contract, the generic-dispatch Android dialog-recovery `warning`
annotation is intentionally not part of the contract). The result types move
from the client-types.ts mirror into a new src/contracts/navigation.ts; the
now-unused CommandActionResult helper is deleted. Public export names are
preserved (re-exported via client-types.ts -> index.ts), so no API break.

The exact-equality parity test pins CommandResult<name> === the contract type
for all ten migrated commands; the public-root export test gains back/rotate
samples.

Verified: tsc --noEmit, oxfmt + oxlint --deny-warnings, fallow audit clean,
Layering Guard empty, 791 tests across core/contracts/client/commands pass
(the lone failure was the known-flaky daemon-client mid-stream-abort test, which
passes in isolation).
@github-actions

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 1.4 MB 1.4 MB 0 B
JS gzip 450.7 kB 450.7 kB 0 B
npm tarball 552.9 kB 553.6 kB +750 B
npm unpacked 2.0 MB 2.0 MB +1.0 kB

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 28.4 ms 28.6 ms +0.2 ms
CLI --help 49.5 ms 49.7 ms +0.2 ms

Top changed chunks: no changes in the largest emitted chunks.

@thymikee

Copy link
Copy Markdown
Member Author

Reviewed current head 6fcae4a. I checked the #913 typed-results context, the diff, the dispatch returns for back/home/rotate/app-switcher, and daemon routing/Android dialog recovery behavior. No actionable blockers found: public export names are preserved, back/home/rotate map to fixed generic dispatch returns, app-switcher has no daemon-route traits that would add Android dialog warnings, and all 21 checks are green. Residual risk is type-surface only; runtime behavior is unchanged. Marking ready-for-human.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Jun 29, 2026
@thymikee thymikee merged commit e9975e1 into main Jun 29, 2026
21 checks passed
@thymikee thymikee deleted the refactor/phase2-typed-results-batch2 branch June 29, 2026 16:25
@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-06-29 16:26 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant