Skip to content

Closed in error#2050

Closed
devtronic-me wants to merge 95 commits into
AppiumTestDistribution:mainfrom
kryworks:feat/ios-tap-perf-issues
Closed

Closed in error#2050
devtronic-me wants to merge 95 commits into
AppiumTestDistribution:mainfrom
kryworks:feat/ios-tap-perf-issues

Conversation

@devtronic-me

@devtronic-me devtronic-me commented May 18, 2026

Copy link
Copy Markdown

Accidentally targeted upstream; closed.

Koray Cirak and others added 30 commits May 14, 2026 20:54
…ions

Slice 0 (Discovery) and the first piece of foundation work for Slice 1:

- docs/: 16 discovery docs across product, architecture, hub/node protocol,
  plugin lifecycle & extension points, data model, auth/RBAC, device
  management, session lifecycle, UI inventory, devops, testing,
  observability, security, performance, plus strengths/weaknesses/risks
  synthesis and 38 open questions. Tick Slice 0; replace the speculative
  Slice 2+ list in docs/SLICES.md with a concrete prioritized list driven
  by Discovery. Slice 1 spec drafted at docs/slices/01-falx-baseline.md
  (kept as reference; Slice 1 will be reshaped before execution).
  Execution plan record at docs/superpowers/plans/.

- falx-ui/: one-time copy from dashboard-frontend/. dashboard-frontend/
  stays untouched per CLAUDE.md hard rule.
- buildAndCopyWeb.sh: switched to building falx-ui/ instead of
  dashboard-frontend/. Plugin still serves from src/public/.
- falx-ui/vite.config.js: dev server proxies /device-farm to
  localhost:4723 so `npm run dev` HMR runs against a live appium plugin
  backend without rebuilds.

- CLAUDE.md: project context, naming rules, upstream-relationship
  workflow, hard rules, slice methodology.
- .gitignore: ignore .playwright-mcp/ test artifacts.
- package.json: pin sharp@0.34.4; add appium-device-farm@^11.3.2 dev dep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the ProtectedRouteWrapper body — swaps the bg-gray-900 div +
<Header /> with <AppLayout> — and delete Header.tsx / NewHeader.tsx
which are now dead code.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move Falx logo + wordmark from sidebar header into the left edge of TopBar.
Sidebar now starts at top:56 (z-40) so the top bar spans full viewport width
unbroken. AppLayout renders TopBar first then Sidebar+main side-by-side.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sidebar now starts at top-0 with z-50 (covers the top-left corner of the
top bar), carrying the Falx brand header in an h-14 block. TopBar drops
to z-40, removes the brand, and uses dynamic paddingLeft from pinned
state so the page title aligns with content below the sidebar edge.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dings

Spike 01 (Android via Tango): GREEN — Tango drives upstream
scrcpy-server-v3.3.3 with first frame in 539 ms, 5-min run stable, taps
sub-pixel accurate. Cleared the way for the Falx browser device-use slice
on Android.

Spike 02 (iOS via WDA + go-ios), Phase 1:
- Streaming PASSES — 19.08 fps over 5 min, max gap 187 ms at tuned WDA
  settings (framerate 20, quality 70, scaling 100). No Phase 2 (WebRTC)
  needed for streaming quality.
- Tap injection FAILS on iOS 26.4.2 with WDA 12.2.2: every coordinate
  and element-based tap endpoint returns 200 null and no-ops on the
  device. Reads / element finders work; writes don't. Needs a separate
  follow-up spike to enumerate working tap channels before iOS device-use
  can ship.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ssons

Spike 02 found that WDA 12.2.2 on iOS 26.4.2 silently no-ops all tap
APIs (coord, W3C, element-based) while reads keep working. That breaks
the iOS device-use feature and needs its own follow-up before any slice.

- docs/spikes/03-ios-tap-injection-spike.md — plan to enumerate candidate
  tap channels (extended WDA caps, /appium/settings tunables, latest WDA
  rebuild, Sauce/HeadSpin forks, go-ios direct HID, tidevice). Run
  cheapest first, stop at first channel that passes tap + swipe + typing
  on iOS 26.
- docs/spikes/README.md — list spike 03 as the next required spike.
- docs/BACKLOG.md — log the WDA + iOS 26 regression, the runwda bundle-ID
  convention shift for iOS 17+, the RSD parallel-spawn race, the dropped
  /wda/tap/0 endpoint, WDA's non-standard MJPEG boundary, the
  single-client MJPEG constraint, the unlock-bypass limitation, and the
  pixel-vs-points tap-coordinate gotcha.
- .gitignore — ignore selfIdentity.plist (go-ios's device-pairing
  identity, contains a private key).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
First slice replacing the proprietary appium-device-farm@11.3.2 "Use
Device" feature with a Falx-owned, MIT/Apache-licensed implementation
on top of Tango (yume-chan) + scrcpy. Vertical-per-platform; iOS lands
in a follow-up slice. Plan is subagent-driven with two-stage review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…cpy-server.jar

ADR 0001 documents the Tango + WDA decision. Pins:
- server: @yume-chan/{adb,adb-server-node-tcp,adb-scrcpy,scrcpy,stream-extra}
- falx-ui: @yume-chan/{scrcpy,scrcpy-decoder-webcodecs,stream-extra}
- on-device: scrcpy-server-v3.3.3.jar (sha256 7e70323b...)

Refs: docs/superpowers/specs/2026-05-16-android-use-device-design.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ight (TDD)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Koray Cirak and others added 26 commits May 18, 2026 12:43
…maxBuffer

Plain 'ios apps' emits full plist metadata (~3.4 MB on a typical device)
which blows Node's default 1 MB execFile maxBuffer; the catch then
miscategorises the buffer overflow as WDANotInstalledError. '--list'
returns bundle-id-only lines (~8 KB) and still contains the runner.
…unner

go-ios v1.0.188+ enforces 'all-or-none' on the
bundleid/testrunnerbundleid/xctestconfig trio in 'ios runwda'. Spike 02
used an older version that accepted partial flags. With no flags
passed, go-ios auto-discovers the single installed XCTest runner — more
robust to varying signed bundle names and xctest target names than
hardcoding xctestconfig=WebDriverAgentRunner.xctest.
…onfig

go-ios v1.0.188's 'no flags' path falls back to hardcoded Facebook
defaults (com.facebook.WebDriverAgentRunner.xctrunner) rather than
scanning installed apps, so any non-Facebook re-signing fails to launch.
Pass bundleid + testrunnerbundleid (the installed runner) plus
xctestconfig=WebDriverAgentRunner.xctest (canonical WDA test-target name,
unchanged by re-signing).
aspect-ratio on a canvas element is unreliable: its intrinsic backing-
store dimensions (width/height HTML attrs) override CSS sizing when both
CSS dimensions are auto. Computed style would resolve to e.g. 1352×700
instead of the locked 323.5×700 portrait shape — the image rendered into
the misshaped canvas appeared stretched horizontally.

Fix: wrap canvas in a regular block element that carries the aspect-
ratio + definite height; have the canvas fill it via width/height: 100%.
alignSelf: center on the wrapper opts out of cross-axis stretch in the
flex-column parent so the wrapper shrink-wraps to height × aspect.

Diagnosed via Playwright DOM inspection on the live session.
…er WDA

Appium's xcuitest driver always POSTs to WDA's /session when attaching
via webDriverAgentUrl, displacing our bridge's session. Every subsequent
/session/<stale>/wda/{tap,drag,activeAppInfo,apps/terminate} call from
the WS handler then 404s — taps, swipes, Home and App Switcher all dead.

After Appium createSession succeeds, probe any unknown WDA path; WDA
includes the current sessionId in every JSON response. Rebind
bridgeHandle.sessionId, then re-apply MJPEG settings (they're session-
scoped on some WDA builds and would otherwise revert to defaults).

Verified end-to-end on kry-phone with Playwright: tap, Home, App
Switcher all changed the canvas hash and the backend log shows the
rebind line with no dispatch 404s.
Records Playwright-driven live results, the five fix commits, open
validation items, and the iOS vs Android architecture limitations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sequential start→stop loop records p50/p95/max timing and lets the
operator confirm no ios runwda / forward process leaks post-cycle.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Task 13 Steps 1-7 verified via Playwright. Steps 8-13 marked pending
operator validation. Tasks 14/15 marked pending second iPhone / Safari+Firefox.
Task 16 Step 1 ticked (script written).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
50 sequential start->stop cycles against kry-phone:
- Start: p50 5331ms / p95 5773ms / max 5788ms (under 8s budget;
  latency trended *down* over the run — warm cache, no leak).
- Stop: p50 26ms / p95 31ms / max 59ms (HTTP ACK only; teardown
  runs async via registry stop closure).
- Zero leaked 'ios runwda' or 'ios forward' processes post-run.
- Port allocator reused slot 0 (8100/9100) cleanly across all cycles.
Captures the two operator-flagged gaps on the iOS slice for a fresh
session to pick up:
  A. Lock-screen probe doesn't trip the 423 path on iOS 26.
  B. Tap/swipe responsiveness is well below Android — root cause is
     WDA's per-input HTTP round trip + MJPEG observe lag. Lists four
     candidate levers (optimistic UI, W3C actions, WebRTC, drop Appium
     attach) without picking one.
Includes a kickoff prompt to start the new session against this doc.
Brainstorm output for the iOS input-responsiveness follow-up. Spec covers
live drag tracking, optimistic canvas overlays, and a duration-cap
fallback to bring iOS Use Device input feel to BrowserStack parity.
Plan is 19 tasks across spike (Phase 1), implementation (Phase 2 with
two conditional branches), and verification (Phase 3 including
agent-side Playwright MCP self-verification).

Picks up from feat/ios-use-device. Issue A (lock probe) deferred to a
separate slice; WebRTC deferred; Appium attach kept (gestures already
bypass it).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase-1 spike (docs/spikes/04-ios-input-latency-spike.md) measured WDA
dispatch wall-time on iOS 26.4.2 at 600-1800ms per call — 20x worse
than the original spec's working assumption (30-80ms). Keep-alive
doesn't help; only 2 of 8 attempted runtime tunables stick.

True live drag tracking is therefore not achievable in this slice
with vanilla WDA. Operator decision: ship the achievable wins now.

Spec amended with a "Revision" section at top noting the scope cut.
Plan rewritten from 19 tasks (live drag, pointer state machine,
streaming pointer wire protocol) to 7 focused tasks:

  1. Apply WDA tunables on session start (~40% dispatch reduction)
  2. Add WDAClient.actions() + tapViaActions() helpers
  3. Swap tap dispatch to /actions + cap swipe duration at 120ms
  4. Optimistic canvas overlays (ring + trail) for falx-ui
  5. Run full unit-test suite
  6. Agent Playwright MCP self-verification against running app
  7. Operator subjective gate on kry-phone

Acceptance bar reframed from "BrowserStack-grade" to "noticeably more
responsive Y/N".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reduces per-call WDA dispatch wall-time by ~40% on iOS 26.4.2 by setting
waitForIdleTimeout=0 and animationCoolOffTimeout=0 immediately after
WDA session creation. Other tunables attempted in the spike were not
recognized by WDA 12.2.2 and are documented for future revisits.

See docs/spikes/04-ios-input-latency-spike.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…helpers

Spike 04 found /actions p50 ~631ms vs /wda/tap ~818ms with tunables
applied. Adds the W3C Actions wrapper and a 1-frame tap helper for
the router to swap to in the next commit.

See docs/spikes/04-ios-input-latency-spike.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… at 120ms

Two iOS input-responsiveness changes:
- Tap dispatch now uses WDA's W3C /actions endpoint via tapViaActions
  (p50 ~631ms vs /wda/tap ~818ms after tunables, per spike 04).
- Swipe duration is clamped to [50, 120]ms regardless of how long the
  operator drew the gesture. Eliminates the 'WDA replays the swipe
  slowly on the iPhone' complaint without breaking tap/swipe
  distinguishability.

See docs/spikes/04-ios-input-latency-spike.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…trail)

Draws a transient ring at pointerdown and a fading trail during drag,
layered over the MJPEG frame on the same canvas. Renders instantly,
no network round-trip. Masks the unavoidable ~600ms WDA dispatch wait
on iOS 26.4.2 (see docs/spikes/04-ios-input-latency-spike.md) by
giving the operator immediate visual confirmation that the gesture
was registered.

Pure-function renderer with unit tests for ring drawing, trail
polyline, expiry, and trim semantics.

Also installs vitest + wires test script in falx-ui (was absent;
required for the spec file).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously the MJPEG handler called drawImage which clears the canvas
bitmap, erasing the optimistic ring + drag trail overlays for up to
~16ms (one rAF tick) at every MJPEG frame arrival. On a static
overlay that's a visible 20Hz flicker.

Fix: invoke renderOverlays synchronously after drawImage so the
overlay is restored same-tick. The rAF loop continues to drive the
fade-out animation between MJPEG frames.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Retroactively ratifies the vitest dep addition that landed as part of
commit 9cab3d7 (iOS canvas overlay renderer + unit tests). vitest is
the right test runner for falx-ui (Vite + React, zero-config); future
falx-ui slices use it freely.

Server-side stays on mocha + chai (no change to existing convention).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After the iOS input responsiveness slice landed and a research subagent
confirmed vanilla WDA is the universal OSS ceiling (GADS, Sonic,
ControlFloorAgent, STF-iOS, atxserver2, tidevice all use WDA), document:

- The 600-1800ms per-call WDA latency floor as a "lesson" so future
  iOS work doesn't re-discover.
- The Appium issue #16230 WDA-patch spike as a deferred tech item —
  one identified local lever, ≤2 days, would patch the accessibility-
  snapshot calls out of WDA's tap/actions hot path.
- tddworks/baguette tracking for real-device iOS HID injection.

See docs/spikes/04-ios-input-latency-spike.md for the data.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Agent Playwright MCP self-verification (2026-05-19): dashboard loads,
  Use Device → stream renders, WS protocol correct (CLIENT_TAP_TAG
  0x20 / 9 bytes), end-to-end pipeline works (synthetic tap on Photos
  icon at iOS-points coords launched Photos on the device),
  optimistic ring overlay paints before WS round-trip (pixel sample
  RGB 234,231,226 at expected ring-stroke location), clean teardown
  (zero leaked ios runwda / ios forward processes).

- Operator manual gate (2026-05-18): "noticeably more responsive Y,
  but still way behind Android" — accepts shipping the wins given
  the WDA ceiling. Diagnostic confirmed: streaming half is real-time;
  dispatch half is the bottleneck.

- Slice outcome: at the OSS state-of-the-art ceiling for iOS 26.4.2.
  WDA-patch spike (Appium #16230) logged in BACKLOG for future round.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@devtronic-me

Copy link
Copy Markdown
Author

Accidentally targeted upstream; re-opening against my own fork. Apologies for the noise.

@devtronic-me devtronic-me changed the title Feat/ios tap perf issues Closed in error May 18, 2026
@devtronic-me devtronic-me deleted the feat/ios-tap-perf-issues branch May 18, 2026 23:18
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.

1 participant