Commit Graph

806 Commits

Author SHA1 Message Date
Michał Pierzchała cb28f6862e fix: align web snapshot and capability support (#828)
* fix: align web snapshot and capability support

* test: cover desktop snapshot presentation
2026-06-19 16:00:31 +02:00
Michał Pierzchała bc5726e8b0 test: cover web provider scenario (#827) 2026-06-19 13:39:39 +02:00
Michał Pierzchała 833479e01b feat: add semantic web provider seam (#825)
* feat: add semantic web provider seam

* fix: forward web provider through request router
2026-06-19 12:26:19 +02:00
Michał Pierzchała 188715b409 feat: add web platform vocabulary (#824)
* feat: add web platform vocabulary

* fix: tighten web platform admission
2026-06-19 11:56:45 +02:00
Michał Pierzchała f9a9662f05 0.17.6 v0.17.6 2026-06-16 16:52:40 +01:00
Michał Pierzchała afd413021a feat: improve maestro test reporter (#811) 2026-06-16 16:51:47 +01:00
Michał Pierzchała d29b86d7b8 fix: report maestro ios runner setup failures (#809) 2026-06-16 16:28:28 +01:00
Hanno J. Gödecke d14dfab41c fix(ios): support no-op xctest runner startup (#807) 2026-06-16 15:54:25 +01:00
Michał Pierzchała feb5309e38 fix: classify external xctest runner flags (#810) 2026-06-16 15:54:00 +01:00
Hanno J. Gödecke 350cd0c1cb feat(ios): support external xctest runner artifact (#806)
* feat(ios): support external xctest runner artifact

* fix(ios): pass derived data path to xctest runner

* fix(ios): reuse external xctest runner sessions
2026-06-16 15:44:41 +01:00
Michał Pierzchała 0b499f22db chore: update stale callstackincubator references 2026-06-15 20:12:03 +01:00
Michał Pierzchała 204be34dec 0.17.5 2026-06-15 20:08:26 +01:00
Michał Pierzchała 9e165114c0 perf: optimize rslib startup build (#803) 2026-06-15 08:51:47 +02:00
Michał Pierzchała a6bb86539f fix: stabilize Android Maestro replay interactions (#805)
* fix: stabilize Android Maestro replay interactions

* refactor: dedupe Maestro visible recovery

* test: relax Android Maestro snapshot count assertions

* refactor: unify Maestro recoverable interaction state
2026-06-14 15:46:26 +02:00
Yoni Samlan 93a6998188 fix: rotate synthesized iOS taps into native screen space (#804)
* fix: rotate synthesized iOS taps into native screen space

* fix: rotate synthesized iOS transform gestures

---------

Co-authored-by: Michał Pierzchała <thymikee@gmail.com>
2026-06-14 11:24:31 +02:00
Michał Pierzchała 71db11b744 0.17.4 v0.17.4 2026-06-13 20:49:01 +02:00
Michał Pierzchała 991f4c708b fix: match Maestro directory test order (#802)
* fix: match Maestro directory test order

* test: cover Maestro nested directory discovery
2026-06-13 20:48:34 +02:00
Michał Pierzchała 778349a991 fix: stabilize Android Maestro replay reliability (#799)
* docs: clarify Android snapshot helper idle waits

* fix: stabilize Android Maestro replay context
2026-06-13 19:08:57 +02:00
Michał Pierzchała 0034a7672a fix: align Maestro test discovery order (#801) 2026-06-13 13:29:24 +02:00
pupuking723 98376b93d5 fix: report snapshot timing diagnostics (#798)
* fix: report snapshot timing diagnostics

* fix: refine snapshot diagnostics reporting

* fix: preserve replay snapshot diagnostics on failure

* refactor: simplify snapshot diagnostics plumbing

---------

Co-authored-by: Michał Pierzchała <thymikee@gmail.com>
2026-06-13 12:17:25 +02:00
Kenichi Saito c4950a945c fix: detect disabled Developer Tools mode for iOS runner (#792)
* fix: terminate simulator runner apps during cleanup

* fix: detect disabled developer mode before iOS runner startup
2026-06-13 11:59:37 +02:00
Michał Pierzchała 1ce2e97175 0.17.3 2026-06-13 11:48:03 +02:00
Michał Pierzchała 945a780c37 fix: stabilize iOS runner gestures (#800)
* fix: avoid stale iOS window viewport queries

* fix: synthesize iOS swipe gestures

* fix: honor iOS drag gesture durations

* test: update iOS gesture provider transcript

* fix: align sequence drag fallback timing
2026-06-13 09:54:53 +02:00
Michał Pierzchała 8de4dddd54 fix: tighten ios runner crash classification (#797) 2026-06-13 07:43:41 +02:00
Michał Pierzchała 4f0886d110 fix: improve iOS runner crash diagnostics (#793)
* fix: improve ios runner crash diagnostics

* fix: keep runner failure helpers internal
2026-06-12 20:51:57 +02:00
Michał Pierzchała 96534e860b fix: stream replay suite progress (#795)
* fix: stream replay suite progress

* fix: tighten replay progress cancellation
2026-06-12 20:51:40 +02:00
Michał Pierzchała dd5c0be0ed fix: relax Android snapshot helper session timeout (#796)
* fix: relax Android snapshot helper session timeout

* test: cover Android helper session timeout cap
2026-06-12 20:50:57 +02:00
Michał Pierzchała 5c83fe4e50 fix: improve daemon diagnostics and remove compact snapshots (#786)
* fix: improve daemon startup diagnostics

* perf: relax query-sweep recovery budget

* fix: make compact snapshot flag a no-op

* fix: remove compact snapshot mode

* test: align tvOS remote provider expectation

* test: drop compact snapshot progress target
2026-06-12 17:32:56 +02:00
Michał Pierzchała 4142daa0c3 docs: update internal agent guidance (#789) 2026-06-12 14:58:18 +02:00
Michał Pierzchała c925563959 fix: avoid focusing booted iOS simulators (#790) 2026-06-12 14:57:58 +02:00
Michał Pierzchała 1da6fd5180 refactor: split debug symbols workflow modules (#787)
* refactor: split debug symbols workflow modules

* refactor: simplify debug symbols module dependencies

* refactor: align debug symbols with command families

* refactor: move Apple debug symbols under ios platform
2026-06-12 14:44:50 +02:00
Michał Pierzchała c7c9db7439 refactor: split Android native perf collector (#788)
* refactor: split Android native perf collector

* fix: keep android perf hint helper local

* refactor: simplify android perf artifact polling
2026-06-12 14:28:03 +02:00
Michał Pierzchała fa1c1d55da refactor: localize command surface modules (#772)
* refactor: localize command surface modules

* refactor: localize command runtime modules

* refactor: tighten localized command exports

* refactor: address command localization review

* refactor: deepen batch command policy

* refactor: split provider progress model

* refactor: collapse command client facets

* refactor: run progress metrics as TypeScript

* refactor: remove obsolete command shims

* fix: update localized snapshot output import

* fix: preserve debug command localization
2026-06-12 14:02:04 +02:00
Michał Pierzchała 48c121d5e6 feat: add debug symbols workflow (#756) 2026-06-12 13:14:14 +02:00
Michał Pierzchała f0d1674cdf feat: add Android native perf profiling (#757)
* feat: add Android native perf profiling

* fix: satisfy fallow for Android perf profiling

* fix: harden Android native perf lifecycle

* test: reduce native perf mock complexity

* docs: show compact native perf evidence example

* fix: align perf rebase validation

* fix: summarize Android perfetto artifacts

* fix: clean up Android native perf on session close
2026-06-12 13:12:41 +02:00
Michał Pierzchała 385c1dd655 fix(daemon): use snapshot quality for sparse handling (#779)
* fix(daemon): use snapshot quality for sparse handling

* fix(daemon): preserve sparse snapshot verdict state

* fix(daemon): route sparse verdicts through selector reads
2026-06-12 13:04:39 +02:00
Michał Pierzchała 931cbba14f refactor(ios): share snapshot filter predicates (#780) 2026-06-12 12:59:12 +02:00
Michał Pierzchała 0425df2be6 refactor: bundle snapshot capture annotations (#777)
* refactor: bundle snapshot capture annotations

* refactor: address snapshot annotations review

* test: cover snapshot annotation quality mapping
2026-06-12 12:43:13 +02:00
Michał Pierzchała fa8cce37d1 refactor(ios): snapshot capture plans with a structured quality verdict (#783)
* refactor(ios): snapshot capture plans with a structured quality verdict

Implements ADR 0004's explicit-strategies decision as architecture
(candidates 1+2 of the snapshot pipeline review):

- Snapshot backend seam: three adapters (recursive tree, query sweep,
  private AX) behind one captureWithBackend dispatch. Each strategy
  declares its chain as data (regular: tree→queries→private-ax,
  compact: queries→private-ax, raw: tree→private-ax) and one plan
  runner walks it under a 20s umbrella budget so chained recovery can
  never stack past the 30s main-thread watchdog. Terminal policy is
  per-plan: raw rethrows AX failures (diagnostics preserve errors),
  interactive fails closed with runnerFatal invalidation.
- Single quality classifier: one sparsePayloadReason predicate (with
  reason codes), one collapsed-leaf detector, replacing the three
  divergent sparse detectors (Swift structural, daemon count==1, CLI
  count<=3) that each patched a different failure shape.
- Structured snapshot quality verdict on the wire (state, backend,
  reason, reasonCode, effectiveDepth, collapsedLeafIndexes): the daemon
  and CLI render warnings from it instead of re-deriving degradation
  from node shapes; budget starvation is no longer blamed on the app's
  accessibility. Legacy runner messages and daemon-side detectors stay
  behind a verdict-absent gate for mixed-version compat.
- The verdict surfaces in --json (snapshotQuality) for agents; the
  generic sparse CLI hint is suppressed when a verdict explains it.

Threading the verdict exposed two more hand-copy field drops
(captureInteractionOutcomeAwareSnapshot, serializeSnapshotResult,
client response mapping) - now carried alongside warnings everywhere.

Verified live: Settings healthy (tree, no warnings), Settings compact
under load (recovered/private-ax/budget), production login (sparse
best-effort with honest warning), collapse fixture (healthy +
collapsedLeafIndexes -> @ref warning), Bluesky Home (recovered/
private-ax, 24 nodes in 2s). Full unit suite 2327 passed, fallow clean,
runner builds.

* fix(ios): correct recovered-snapshot viewport and private-AX scope semantics

Review follow-ups on the capture-plan refactor:

- The query-sweep synthetic root doubles as the daemon's viewport
  (find.ts prefers on-screen matches inside nodes[0].rect), but it was
  built from candidate bounds, so off-screen controls below the screen
  could inflate it and win duplicate-label resolution. The root now
  uses the real finite viewport, falling back to candidate bounds only
  when viewport capture failed.

- The private-AX backend applied --scope as a per-node text filter,
  hiding the matched container's children — diverging from regular
  snapshot scope semantics and contradicting the depth-cap hint that
  recommends scoped re-runs. Scope now selects the matched subtree:
  descendants inherit the match and only the normal option filters
  apply to them (in-bundle test covers a non-matching descendant).

Verified live on Bluesky Home: scope homeScreen returns the 52-node
subtree including non-matching descendants; compact root rect equals
the screen (0,0,402,874).

* fix(ios): fail closed on interactive AX failure, stamp fatal verdict, validate parser

Three review findings on the capture-plan terminal path:

- P1: the fail-closed guard required `best == nil`, but the query-sweep
  tier always returns a synthetic-root sparse payload that sets `best` —
  so an interactive recursive-tree AX serialization failure that no
  backend recovered returned a sparse snapshot instead of invalidating
  the cached target. Reaching the terminal already means no backend
  produced a usable tree, so the sparse `best` must not suppress the
  fail-closed path. Extracted the decision into a pure, unit-tested
  `resolveSnapshotPlanTerminal` (closes the terminal-ordering testability
  gap the architecture review flagged).
- P2: `snapshotAccessibilityUnavailable` returned a payload with no
  `snapshotQuality`, leaving one planned sparse result on the
  legacy-message path. It now carries a sparse/ax-rejected verdict like
  every other planned snapshot, so downstream sparse handling keys off
  the verdict.
- P2: `readSnapshotQualityVerdict` cast any string state/backend into the
  union, so a malformed object suppressed the legacy node-shape
  detectors. State and backend are now validated against their unions
  (unknown → verdict-absent → legacy detectors run); an unknown
  reasonCode is dropped rather than rejecting the whole verdict, so a
  forward-version runner still yields a usable verdict.

Unit-covered: Swift resolveSnapshotPlanTerminal matrix + fatal-verdict
assertion; TS parser accept/reject/forward-compat. Full suite 249 files
/ 2449 tests, fallow, lint, runner build green.
2026-06-12 12:25:40 +02:00
Michał Pierzchała 3b94b36432 docs: add JPMorgan Chase to readme users (#782) 2026-06-12 11:23:44 +02:00
Michał Pierzchała 60e4fe01c1 docs: narrow delay-ms text entry guidance (#781) 2026-06-12 10:19:50 +02:00
Michał Pierzchała dfc5dba0ee refactor: split daemon client facade (#773)
* refactor: split daemon client facade

* fix: keep daemon timeout cleanup on resolved paths
2026-06-12 10:10:42 +02:00
Michał Pierzchała 3f6363c951 fix: route replay path commands correctly (#778)
* fix: route replay path commands correctly

* test: cover dedicated CLI handler declines
2026-06-12 09:25:34 +02:00
Michał Pierzchała cba020de21 fix: add iOS private AX snapshot fallback (#758)
* fix: add iOS private AX snapshot fallback

* fix: add public iOS snapshot query recovery

* fix(ios): make private AX snapshot fallback recover deep React Native trees

Four fixes that turn the #758 private AX fallback from
works-on-one-tree-shape into reliable on Bluesky Home:

- Depth ladder: the AX server rejects bulk snapshot requests outright
  (kAXErrorIllegalArgument) once requested depth crosses a
  tree-size-dependent limit that moves with live content. Retry at
  56/40/24/12 instead of giving up after one attempt at 64.
- Real attribute identifiers: the server silently ignored the raw
  keypath strings the bridge passed, so every node came back with a
  zero frame (breaking ref taps and the interactive/compact filters,
  which is why 'snapshot -i -c' stayed sparse). Map keypaths through
  XCElementSnapshot.axAttributesForElementSnapshotKeyPaths (it returns
  an NSSet) and drop the mapper's expensive extras (automation type,
  window display id, base type) that pushed deep requests past the 30s
  main-thread watchdog.
- Viewport from the private root frame when the public windows query
  degrades to an infinite viewport, so off-screen drawer content stops
  passing the visibility filter.
- Runner source fingerprint now includes .m/.h, so bridge edits stop
  reusing stale cached runner builds.

Also hardens the bridge per review: UInt(exactly:) for untrusted
element types, pid_t-sized objc_msgSend for process id matching, and
objCType-checked NSValue frame decoding.

* fix(ios): recover deadline-truncated near-empty compact snapshots

The all-structural sparse detector misses the common large-RN-tree case
where the typed-query sweep resolves one or two stray controls before
its 1s deadline: the payload has 'content', so recovery never fires,
yet 2 nodes is useless in practice. Treat deadline-truncated payloads
with <= 8 nodes as needing recovery, and only replace the original
payload when the recovered tree actually carries more nodes. Completed
sweeps on legitimately minimal screens stay untouched (not truncated).

* chore: fix CI for the AX snapshot fallback branch

- Sync the setup metadata script's fingerprint extension list with the
  runtime (.m/.h were added for the ObjC bridge), fixing the cache
  metadata parity test.
- Reduce find.ts complexity flagged by fallow: hoist the node fetcher
  into createFindNodeFetcher with a recoverSparseInteractiveSnapshot
  helper, split match disambiguation and resolution scoring into
  narrowMultipleMatches/resolvedTouchScore, extract rectsMatch.

* feat(ios): make accessibility fallbacks and collapsed containers visible in snapshot output

Two transparency gaps from #701's 'no silent fallback' requirement:

- Runner-attached snapshot messages now surface as snapshot warnings
  (readAppleSnapshotResult previously dropped them), so every recovery
  through the fallback accessibility backend or query tier is announced,
  states what it usually means (the app publishes an unhealthy
  accessibility tree - fixing the app is the real cure), and points to
  screenshot as visual truth.

- A leaf whose label merges many comma-joined segments is flagged as a
  collapsed accessible container: the app marks a container accessible,
  hiding every descendant from assistive tech and automation alike.
  Nothing can be recovered below it (VoiceOver sees the same merged
  element), so the warning names the node, estimates the merged label
  count, and gives the app-side fix plus the screenshot/coordinate-tap
  workaround.

Validated live on the lab stress fixture (adlab://stress?accessible=1):
the 6-node tree now carries '@e5 [Other] merges ~126 labels...'.

* fix(ios): detect sparse trees with labeled roots and surface warnings through the daemon

Validated against a real-world repro (a production React Native app's
login screen, simulator build provided privately by the reporter): a
full-screen accessibilityViewIsModal overlay leaves the public snapshot
with just Application+Window. Two gaps kept recovery off:

- The sparse detector counted the Application label (the app's display
  name) as content and the full-screen root as hittable, so the app
  name alone defeated recovery. Application/Window labels and root
  hittability say nothing about tree health and no longer count.
- Interactor-level snapshot warnings were dropped by the daemon capture
  chain (only the runtime/commands layer kept them); they now thread
  through CaptureSnapshotResult into BackendSnapshotResult.

With both fixes that login screen recovers through the public query
tier: 16 nodes with every control addressable (fill @ref + read-back
verified), and the output carries the recovery warning. Bluesky-class
trees still ladder into the private fallback unchanged.
2026-06-12 07:55:17 +02:00
Michał Pierzchała f8704f46ef feat: add Apple xctrace perf profiling (#755) 2026-06-11 16:45:29 +02:00
Michał Pierzchała a35c444df6 feat: add perf memory diagnostics (#759)
* feat: add perf memory diagnostics

* fix: address perf memory CI findings

* fix: address perf memory review feedback

* docs: explain perf memory diagnostics benefits
2026-06-11 14:58:09 +02:00
Michał Pierzchała 86941579a8 perf(ios): anchor recording gesture clock from runner response stamps (#762)
Every ok runner response now carries a transport-stamped currentUptimeMs
captured just before the HTTP write. Simulator recording start anchors
gesture overlay timing from the warm snapshot response it already makes,
skipping the standalone uptime request. The standalone uptime path stays
as fallback for older runner builds, and journal-stored responses remain
unstamped so recovered results never pair a stale uptime with a late
receipt time.

Closes #670
2026-06-11 14:23:55 +02:00
Michał Pierzchała 3a02e514e1 refactor(ios): consolidate series batching onto the sequence runner command (#768)
* refactor(ios): consolidate series batching onto the sequence runner command

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

* refactor(ios): drop dead series wire surface from the daemon

- 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

* refactor(ios): remove retired series and frame wire commands entirely

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-11 14:08:30 +02:00
Michał Pierzchała bef5cf3254 chore: lint raw child process imports (#770) 2026-06-11 13:29:53 +02:00
Michał Pierzchała c3d50f7a84 docs: add agent PR readiness checklist (#769) 2026-06-11 13:29:19 +02:00