@@ -22,22 +22,31 @@ the Android planned-touch executor.
2222## Decision
2323
2424Public gesture inputs normalize once in ` src/contracts/gesture-normalization.ts ` . This is the
25- explicit compatibility boundary: convenience APIs and deprecated arguments become canonical
26- semantic intent before entering the runtime. The private daemon wire is free to evolve with that
27- model; compatibility is owed at CLI, Node.js, and MCP.
25+ explicit public compatibility boundary: canonical semantic intent is produced before entering the
26+ runtime. Deprecated arguments that have been removed (timed ` swipe ` , timed ` gesture fling ` ,
27+ ` gesture rotate ` ` velocity ` ) are rejected with actionable ` INVALID_ARGS ` messages rather than
28+ silently reinterpreted. The private daemon wire remains free to carry compatibility-only hints
29+ that do not appear on public surfaces; Maestro timed swipes use
30+ ` internal.gestureExecutionProfile: 'endpoint-hold' ` to preserve iOS fast-swipe-then-hold behavior
31+ while still routing through the canonical ` pan ` input.
2832
2933The runtime plans canonical intent in ` src/contracts/gesture-plan.ts ` . Contact topology is separate
3034from motion:
3135
3236- one contact: pan or fling with a complete pointer trajectory and an explicit execution profile;
3337- two contacts: pan, pinch, rotate, or transform with two complete, synchronized trajectories.
3438
35- ` swipe ` without a duration is public sugar for a fixed-duration fling. Its historical optional
36- duration normalizes to pan intent with an endpoint-hold execution profile and reports a deprecation
37- toward explicit pan. Maestro-authored swipes follow the same normalization and materialize
38- Maestro's 400 ms default when duration is omitted. A genuine pan uses the timed-pan profile, so
39- compatibility aliases retain their release behavior without becoming a new semantic intent. The
40- same deprecation-to-pan rule applies to the historical fling duration. Pinch fixes translation and rotation at zero; rotate fixes
39+ ` swipe ` without a duration remains public sugar for a fixed-duration fling. Timed public forms
40+ (` swipe x1 y1 x2 y2 durationMs ` , ` gesture fling direction x y distance durationMs ` ,
41+ ` gesture swipe preset durationMs ` , and ` gesture rotate degrees x y velocity ` ) are rejected; callers
42+ must use ` gesture pan ` for deliberate timed translation and ` gesture rotate ` without ` velocity ` .
43+ Maestro-authored swipes normalize to the canonical ` pan ` input (origin, delta, durationMs) and carry
44+ the ` endpoint-hold ` execution profile through a daemon-internal compatibility seam
45+ (` internal.gestureExecutionProfile ` ). This preserves the iOS fast-swipe-then-hold behavior that
46+ matches Maestro's XCTest driver, without exposing the profile on the public command surface. Maestro
47+ materializes its 400 ms default when duration is omitted. A genuine public ` pan ` uses the ` timed-pan `
48+ profile, so compatibility-only paths retain their release behavior without becoming a new semantic
49+ intent. Pinch fixes translation and rotation at zero; rotate fixes
4150translation at zero and scale at one; two-finger pan fixes scale at one and rotation at zero;
4251transform can apply all three
4352components atomically. Intent remains on the plan even when aliases share an executor.
0 commit comments