Skip to content

Commit f474f07

Browse files
authored
feat: unify gesture planning and multi-touch execution (#1212)
* feat: unify gesture planning and multi-touch execution * fix: correct unified gesture helper behavior * refactor: tighten unified gesture architecture * fix: preserve gesture routing contracts * test: account for fresh gesture viewport * refactor: remove retired gesture series * fix: preserve example app navigation targets * test: reconcile unified gestures with helper ownership * docs: update Android helper gesture protocol * fix: refresh Maestro percentage swipe frames * refactor: remove stale Maestro frame cache * fix: harden unified gesture execution * fix: model gesture viewport in providers * refactor: remove legacy gesture paths * fix: remove unused swipe preset parser * refactor: tighten unified gesture boundaries * fix: close gesture review gaps * fix: preserve gesture compatibility contracts * fix: preserve multi-touch recording semantics * fix: refresh Apple runner state after app relaunch * test: lock Apple fling fallback route * fix: close Apple runner review gaps * refactor: tighten unified gesture seams * refactor: consolidate gesture planning policy * fix: preserve swipe response compatibility * fix: keep gesture lab aligned with replay coordinates
1 parent 4e06304 commit f474f07

156 files changed

Lines changed: 6082 additions & 4546 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ios.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ jobs:
3131
AGENT_DEVICE_STATE_DIR: ${{ github.workspace }}/.tmp/agent-device-state
3232
AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH: ${{ github.workspace }}/.tmp/ios-runner-derived
3333
AGENT_DEVICE_IOS_PREPARE_TIMEOUT_MS: '420000'
34+
AGENT_DEVICE_XCUITEST_INCLUDE_UNIT_TESTS: '1'
3435
steps:
3536
- name: Checkout
3637
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
@@ -56,6 +57,17 @@ jobs:
5657
runtime-version: ${{ env.IOS_RUNTIME_VERSION }}
5758
preferred-device-name: iPhone 17 Pro
5859

60+
- name: Run iOS runner gesture and lifecycle regressions
61+
run: |
62+
XCTESTRUN_PATH="$(find "$AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH/Build/Products" -maxdepth 1 -name '*.xctestrun' -print -quit)"
63+
test -n "$XCTESTRUN_PATH"
64+
xcodebuild test-without-building \
65+
-xctestrun "$XCTESTRUN_PATH" \
66+
-destination "platform=iOS Simulator,id=${{ steps.ios-simulator.outputs.simulator-udid }}" \
67+
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testSinglePointerFlingFallsBackToXCTestCoordinateDragWhenPrivateSynthesisFails \
68+
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testMissingBundleCommandInvalidatesCompleteCachedTargetState \
69+
-only-testing:AgentDeviceRunnerUITests/RunnerTests/testCachedTargetInvalidationClearsProcessBoundState
70+
5971
- name: Prepare iOS runner
6072
run: |
6173
pnpm clean:daemon

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ Single-context repo. Read `CONTEXT.md` for domain language and testing/architect
6161
- prefer deep modules over mechanical splits: extract when it improves locality for a concept callers already need, not just to reduce line count.
6262
- Before finalizing a code change, do one tightening pass over touched and directly adjacent areas: drop obsolete code, redundant tests, stale helpers/fixtures, and needless duplication made unnecessary by the change.
6363
- Prefer existing helpers. Add a helper only when it reduces real repetition or clarifies domain behavior.
64+
- Prefer composition at platform boundaries: public aliases normalize into shared primitives, and providers contribute transport/device bindings instead of cloning interaction runtimes.
6465
- When adding new guidance, examples, schemas, or command metadata, decide whether it belongs in the command surface, CLI grammar, CLI help, MCP projection, or daemon runtime before editing.
6566
- Prefer updating existing domain vocabulary in `CONTEXT.md` when naming a new durable module concept. Do not coin parallel names in docs, tests, and code.
6667

CONTEXT.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
- Runner command traits: per-command-type classification for iOS/macOS runner lifecycle behavior, distinct from the public command surface and daemon command registry. The Swift runner traits classify interaction, read-only, and runner-lifecycle axes for XCTest execution; Swift resolves the alert command as read-only only for its `get` action. The TypeScript runner command traits classify daemon-side runner send/recovery policy such as read-only retry routing, readiness probes, and recent-healthy-mutation preflight skips; the TypeScript table is command-type keyed and currently classifies alert as read-only for daemon retry policy. Each side keeps one source of truth keyed by runner command type.
4848
- Coordinate-first resolved element activation: iOS/macOS runner interaction pattern where a selector or text query resolves the semantic `XCUIElement`, then activation uses the element's resolved center coordinate when a frame is available. This keeps target selection semantic while avoiding `XCUIElement.tap()` post-action element re-resolution after normal navigation. tvOS remains focus/remote-driven.
4949
- Interaction dispatch path: one concrete route an interaction command takes to the device (runtime selector/ref resolution, direct iOS selector, native ref via web clickRef, coordinate, maestro non-hittable fallback). Every path classifies every guarantee in the ADR 0011 registry.
50+
- Gesture plan: typed, platform-neutral normalization of one- or two-contact gesture intent into bounded pointer trajectories. Contact topology is separate from motion; two-contact intent remains pan/pinch/rotate/transform even when native injection shares one executor. See ADR 0013.
51+
- Multi-touch geometry: the internal initial span and angle plus centroid translation, scale, and rotation used to build both contact trajectories. Geometry is viewport-aware and fails early when the requested motion cannot fit; it is not a public tuning surface.
5052
- Guarantee cell: one (dispatch path, guarantee) entry in `src/contracts/interaction-guarantees.ts`, classified as runtime/runner/delegated/inapplicable/waived. Completeness is a compile error; honesty is gate-tested.
5153
- Owned waiver: a `gap:`-prefixed waived cell carrying a `trackingIssue` URL. Waivers are diffable debt with an owner, never folklore.
5254
- Parity table: golden JSON fixture under `contracts/fixtures/` consumed by both vitest and the runner's gated Swift tests, so a cross-language rule (e.g. tap-point policy) cannot drift silently. Change the rule only via the table.

android-multitouch-helper/README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,16 @@ sh ./scripts/build-android-multitouch-helper.sh "$VERSION" .tmp/android-multitou
1818
## Run
1919

2020
```sh
21-
PAYLOAD="$(printf '%s' '{"kind":"transform","x":672,"y":1500,"dx":80,"dy":-40,"scale":1.8,"degrees":35,"durationMs":700}' | base64)"
21+
PAYLOAD_JSON='{
22+
"protocol":"android-multitouch-helper-v1",
23+
"kind":"transform",
24+
"durationMs":32,
25+
"pointers":[
26+
{"pointerId":0,"samples":[{"offsetMs":0,"x":120,"y":180},{"offsetMs":16,"x":130,"y":175},{"offsetMs":32,"x":140,"y":170}]},
27+
{"pointerId":1,"samples":[{"offsetMs":0,"x":120,"y":260},{"offsetMs":16,"x":135,"y":270},{"offsetMs":32,"x":150,"y":280}]}
28+
]
29+
}'
30+
PAYLOAD="$(printf '%s' "$PAYLOAD_JSON" | base64)"
2231
adb install -r -t ".tmp/android-multitouch-helper/agent-device-android-multitouch-helper-$VERSION.apk"
2332
adb shell am instrument -w \
2433
-e payloadBase64 "$PAYLOAD" \
@@ -30,12 +39,19 @@ adb shell am instrument -w \
3039
The APK emits instrumentation result records using
3140
`agentDeviceProtocol=android-multitouch-helper-v1`.
3241

42+
Before planning a gesture, the runtime invokes the same instrumentation with
43+
`-e mode viewport`. That read-only mode waits for `UiAutomation` window state and returns the
44+
active application window bounds, falling back to the active accessibility root when Android does
45+
not expose interactive-window metadata. It does not use or cache the physical display size.
46+
3347
Successful results include:
3448

3549
- `ok=true`
3650
- `helperApiVersion=1`
37-
- `kind` (`swipe`, `pinch`, `rotate`, or `transform`)
51+
- `kind` (`swipe` for one planned pointer path or `transform` for two)
3852
- `injectedEvents`
3953
- `elapsedMs`
4054

55+
Viewport results use `kind=viewport` plus `x`, `y`, `width`, and `height`.
56+
4157
Failures return `ok=false`, `errorType`, and `message`.

0 commit comments

Comments
 (0)