Skip to content

refactor(ios): consolidate series batching onto the sequence runner command#768

Merged
thymikee merged 3 commits into
mainfrom
claude/open-prs-review-usc6js
Jun 11, 2026
Merged

refactor(ios): consolidate series batching onto the sequence runner command#768
thymikee merged 3 commits into
mainfrom
claude/open-prs-review-usc6js

Conversation

@thymikee

@thymikee thymikee commented Jun 11, 2026

Copy link
Copy Markdown
Member

Closes #767

What

Routes every Apple multi-press variant (plain, double-tap, hold, jitter) and swipe series through budget-chunked sequence requests (#764), retiring tapSeries and dragSeries — and removes the retired wire commands (including interactionFrame, unsent since #760) from both daemon and runner entirely. Net diff across the three commits: +223 / −400.

  • Press routing collapsed: shouldUseIosTapSeries / shouldUseIosPressSequence merge into one gate (isApple && count > 1); press dispatch goes from four routes to three.
  • New doubleTap step kind in the sequence allowlist on both ends (TS validator + Swift executor calling doubleTapAt). The single doubleTap interactor now sends a one-step sequence and parses the result, so step failures surface as errors instead of ok-shaped payloads.
  • Swipe series migrated off dragSeries: ping-pong unrolls daemon-side into per-step endpoint swaps. This gives the drag step kind its first production caller. Semantics preserved exactly — the daemon never sent synthesized dragSeries, and that path already ignored durationMs, same as sequence drag steps.
  • Latent watchdog bug fixed: press --count 4 --interval-ms 10000 previously executed 30s+ of pauses inside one main-thread block on the unchunked tapSeries path; it now budget-chunks via chunkRunnerSequenceStepsByBudget like everything else.
  • Shared chunk loop: runIosSequenceChunks extracted so press and swipe reuse chunking, aggregation, and global step-index rebasing.

Legacy removal (verified dead first)

  • TS: tapSeries/dragSeries/interactionFrame dropped from the RunnerCommand union, isReadOnlyRunnerCommand, protocol fixtures, and the preflight-skip allowlist, along with the orphaned fields (count, intervalMs, doubleTap, pauseMs, pattern) and the superseded count-only chunker chunkRunnerSequenceSteps. ADR 0005 / protocol docs updated.
  • Swift: the three handler cases, performDragSeries, runSeries (no remaining callers), the CommandType enum cases, journal-retention and traits entries, and the matching Command model fields — including the never-sent synthesized dragSeries branch.
  • Dead-code verification: no dynamic command construction anywhere (runner-command-recovery only echoes in-flight command ids), no raw-string references in Swift, no docs references; shared helpers (synthesizedDragAt, doubleTapAt, keyboardAvoidingDragPoints, sleepFor) all retain live callers.

Compatibility note

This intentionally drops old-daemon → new-runner wire compat for the three retired commands (a deliberate departure from the #760 interactionFrame precedent): an old daemon paired with a runner built from these sources gets a CommandType decode rejection, and the source-fingerprint check rebuilds a matching runner on the next session. The exposure is limited to brief upgrade overlap or multiple checkouts sharing a device.

Behavior note

Plain tap series now use the synthesized HID tap path on iOS non-tv (with runner-side tapAt fallback), matching the individual tap command — the retired tapSeries used XCUICoordinate tapAt. Result timingMode for migrated paths is runner-sequence (was runner-series).

Validation

  • pnpm typecheck, pnpm check:quick, pnpm format, git diff --check clean.
  • pnpm check:unit: 248 files, 2386 tests passed (4 skipped), 8 smoke tests.
  • pnpm check:fallow --base origin/main: no issues in changed files.
  • pnpm build succeeds.
  • New coverage: plain-series and double-tap-series fusion tests, ping-pong unroll assertion, doubleTap validator tests (TS), wire-decode + allowlist-acceptance tests (Swift).

Pending

⚠️ This environment has no Swift toolchain: pnpm build:xcuitest and an on-device smoke of the migrated paths (plain press series, double-tap, ping-pong swipe series) are still needed before merge.

https://claude.ai/code/session_01VokBZWESTDgcnbYwS4DkJo

@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 1.2 MB 1.2 MB -283 B
JS gzip 392.0 kB 392.0 kB +20 B
npm tarball 510.2 kB 509.6 kB -654 B
npm unpacked 1.7 MB 1.7 MB -4.9 kB

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 26.0 ms 25.9 ms -0.1 ms
CLI --help 41.1 ms 41.0 ms -0.0 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/2415.js -324 B -6 B

Base automatically changed from perf/669-runner-sequence-tracer to main June 11, 2026 10:50
…ommand

Closes #767

Routes every Apple multi-press variant (plain, double-tap, hold, jitter)
and swipe series through budget-chunked sequence requests, retiring the
daemon-side tapSeries and dragSeries senders:

- Add a doubleTap step kind to the sequence allowlist on both ends,
  mirroring the retired tapSeries doubleTapAt branch.
- The single doubleTap interactor sends a one-step sequence and parses
  the result, surfacing step failures as errors.
- Swipe series unroll ping-pong daemon-side into per-step endpoints;
  the runner's coordinate-drag path ignores durationMs exactly as the
  daemon-sent (non-synthesized) dragSeries did.
- Extract runIosSequenceChunks so press and swipe share the chunking,
  aggregation, and global step-index rebasing.
- Keep tapSeries/dragSeries runner handlers for wire compatibility with
  older daemons, annotated like interactionFrame; remove both from the
  preflight-skip allowlist (daemon never sends them) and update ADR
  0005 / protocol-optimizations docs.

This also closes the latent watchdog exposure where press --count N
--interval-ms M routed to tapSeries and executed all pauses inside one
30s-watchdog main-thread block with no chunking.

Behavior note: plain tap series now use the synthesized HID tap path on
iOS non-tv (with runner-side tapAt fallback), matching the individual
tap command instead of the retired tapSeries' XCUICoordinate taps.

https://claude.ai/code/session_01VokBZWESTDgcnbYwS4DkJo
@thymikee thymikee force-pushed the claude/open-prs-review-usc6js branch from bbc01c0 to 253b4a2 Compare June 11, 2026 10:51
claude added 2 commits June 11, 2026 11:29
- Remove chunkRunnerSequenceSteps: superseded by the budget-aware
  chunker; no production callers remained.
- Remove tapSeries/dragSeries from the RunnerCommand union along with
  their orphaned fields (count, intervalMs, doubleTap, pauseMs,
  pattern) and protocol fixtures: this type is the send surface of the
  current daemon, which no longer sends either command. The Swift
  runner keeps serving both for wire compatibility with older daemons.
- Retarget the ready-mutation preflight test from tapSeries to
  sequence.

https://claude.ai/code/session_01VokBZWESTDgcnbYwS4DkJo
Drops the runner-side wire compatibility for tapSeries, dragSeries, and
interactionFrame now that no daemon path sends them (series fuse into
sequence since this branch; interactionFrame was fused into scroll in
#760):

- Swift: delete the three handler cases, performDragSeries, runSeries
  (no remaining callers), the CommandType enum cases, journal-retention
  and traits entries, and the Command fields (count, intervalMs,
  doubleTap, pauseMs, pattern) that existed only for them. The
  never-sent synthesized dragSeries branch goes with it.
- TS: drop interactionFrame from the RunnerCommand union and
  isReadOnlyRunnerCommand, and its protocol fixture.
- Update stale perf scenario labels referencing the retired commands.

Verified dead before removal: no dynamic command construction anywhere
(runner-command-recovery only echoes in-flight command ids), no
raw-string references in Swift, no docs references. Helpers shared with
live paths (synthesizedDragAt, doubleTapAt, keyboardAvoidingDragPoints,
sleepFor) all retain callers.

Compat: an old daemon paired with a runner built from these sources
gets a CommandType decode rejection; the source-fingerprint check
rebuilds a matching runner on the next session.

https://claude.ai/code/session_01VokBZWESTDgcnbYwS4DkJo
@thymikee thymikee merged commit 3a02e51 into main Jun 11, 2026
19 of 21 checks passed
@thymikee thymikee deleted the claude/open-prs-review-usc6js branch June 11, 2026 12:08
@github-actions

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-06-11 12:08 UTC

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(ios): consolidate series batching onto the sequence runner command

2 participants