Skip to content

iOS gesture pan duration has no automated guard; the nightly gesture gate cannot catch a #1562 regression #1584

Description

@thymikee

Follow-up to #1562 / #1572.

#1572 fixed gesture pan ignoring its duration on iOS, and the fix is real — but nothing in CI would catch it coming back.

Why the existing gate does not cover it

examples/test-app/replays/gesture-lab.ad already drives the exact command class that regressed:

gesture pan 110 443 48 0 500

Two problems:

  1. It does not run on PRs. fixtureReplays is a full-tier scenario (test/integration/ios-simulator-e2e/scenarios.ts: { id: 'full:fixture-replays', runner: 'fixtureReplays', tier: 'full' }), and .github/workflows/ios.yml runs AGENT_DEVICE_IOS_E2E_TIER: smoke. Only replays-nightly.yml runs the full tier.
  2. What it asserts is activation counts, not timing. The verified behavior is "gesture fixture counters prove pan/fling/pinch/rotate/transform". A pan that collapses to ~100 ms still increments the counter, so the assertion stays green through the entire iOS gesture pan ignores its duration argument (daemon plan-builder offsetMs spread) #1562 symptom.

Why the obvious fix does not work

The runner reports gestureStartUptimeMs / gestureEndUptimeMs, but normalizeAppleRunnerResultForResponse (src/platforms/apple/core/runner/runner-result-response-normalization.ts) strips both from the response as diagnostic-only fields. The e2e harness runs the CLI with --json, so it cannot see them. #1572's evidence table had to be read out of --debug per-request ndjson.

Exposing those fields publicly just to test them would be the wrong trade — they are deliberately internal.

Suggested approach

Make the duration observable in the fixture instead of in the protocol. examples/test-app/src/screens/GestureLab.tsx already uses Gesture.Pan() and renders counters as plain text that replays assert with wait. Recording an observed-duration bucket from the handler's begin/end timestamps and rendering it the same way makes the assertion a one-line wait in gesture-lab.ad:

gesture pan 110 443 48 0 500
wait "pan duration >=400ms" 5000

No new plumbing, no diagnostic-field exposure, and it exercises the public replay path end to end.

Worth deciding separately whether a single duration-checked pan should be promoted into the smoke tier, since a nightly-only guard means a regression can sit on main for a day.

Context

ADR 0013 now states that unit tests cannot prove timing or event delivery inside the private XCTest bridge, so live evidence is the only mechanism available — which is exactly why the live gate needs to actually assert timing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions