Commit Graph

9 Commits

Author SHA1 Message Date
Michał Pierzchała 5a84507b08 docs: add selector capture reliability contract (#858) 2026-06-24 17:03:57 +02:00
Michał Pierzchała 091c7dbc14 refactor: deepen runner command traits (#847) 2026-06-23 19:00:21 +02:00
Michał Pierzchała d47cd30117 feat: add agent-device proxy command (#844) 2026-06-23 17:20:08 +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 76cee982ba fix: stabilize iOS runner navigation taps (#702)
* 0.16.14

* fix: stabilize iOS runner navigation taps

* fix: recover iOS runner after AX failures

* docs: clarify AX-unavailable snapshot recovery

* test: cover synthesized ios provider taps

* test: cover iOS runner AX failure paths

* fix: clarify sparse iOS AX recovery hint
2026-06-07 11:17:27 +02:00
Michał Pierzchała f2424f9d3a refactor: centralize daemon command registry (#693) 2026-06-05 18:34:01 +02:00
Michał Pierzchała 5492cf4642 refactor(ios): single CommandTraits table for runner command classification (#642)
* refactor(ios): single CommandTraits table for runner command classification

Replace the three hand-maintained switches in RunnerTests+Lifecycle.swift
(isInteractionCommand / isReadOnlyCommand / isRunnerLifecycleCommand) with one
source of truth: CommandType.traits, an exhaustive switch returning a
CommandTraits struct (interaction / readOnly / lifecycle axes), collocated with
CommandType in RunnerTests+Models.swift.

Pure refactor: every command's classification is reproduced verbatim, and the
three predicates become one-line lookups with unchanged signatures, so call
sites are untouched. The exhaustive switch makes it a compile error to add a
CommandType without classifying it, closing the drift that historically let
tapSeries/dragSeries/keyboardReturn fall out of isInteractionCommand.

readOnly is a 3-state enum (.always/.never/.conditional); .conditional preserves
alert's action-dependent read-only behavior, resolved in isReadOnlyCommand.
Classification feeds ADR-0002 session invalidation (the read-only retry that
nulls currentApp/currentBundleId), so behavior is intentionally unchanged.

Adds the "Runner command traits" term to CONTEXT.md.

* docs(ios): note CommandTraits.readOnly .conditional is alert-only (review follow-up)

* fix(ios): classify tapSeries/dragSeries/keyboardReturn as interaction commands (#643)

* fix(ios): classify tapSeries/dragSeries/keyboardReturn as interaction commands

tapSeries and dragSeries are the series forms of tap/drag (already interaction
commands); keyboardReturn is the sibling of keyboardDismiss (already an
interaction command). All three were missing from the historical
isInteractionCommand switch — a drift the new CommandTraits table (#642) makes
visible. Classifying them as interaction commands gives them the foreground-guard
+ stabilization preflight that their single-shot/sibling forms already get.

Behavior change: these three commands now re-activate a backgrounded target to
foreground and pay the stabilization delays before running. Ships separately from
the CommandTraits refactor (#642) and should land after that bakes.

mouseClick left unchanged: macOS-only and the foreground guard interacts with
bespoke macOS activation, so it needs a macOS smoke check first.

* test: cover iOS runner series commands in perf harness
2026-06-01 18:11:04 +02:00
Michał Pierzchała 819d7dc8aa feat: expose structured MCP command tools (#593)
* feat: expose semantic MCP tools

* docs: remove semantic mcp prd

* refactor: deepen semantic command surface

* refactor: add mcp execution seam

* refactor: deepen command grammar

* refactor: remove legacy command definitions

* refactor: collapse semantic cli wrappers

* refactor: remove local mcp placeholders

* refactor: derive semantic cli routing

* refactor: trim mcp status metadata

* refactor: derive semantic input contracts

* refactor: split semantic grammar modules

* refactor: derive batch input schema

* refactor: centralize cli command schema catalog

* refactor: share semantic cli output projections

* refactor: remove legacy cli output paths

* refactor: consolidate command interface surface

* docs: align command contract wording

* refactor: split command projection from cli grammar

* refactor: trim projection exports

* fix: satisfy fallow command contract audit

* refactor: structure public batch steps

* chore: clean batch architecture references

* fix: keep legacy cli batch steps working

* fix: serialize mcp batches

* chore: tighten command surface cleanup

* fix: serialize mcp stdin requests

* chore: keep mcp config out of command contracts

* fix: project structured batch targets

* chore: harden command input typing

* fix: project maestro backend for replay tests

* fix: preserve session mcp request options
2026-05-28 09:20:55 +02:00
Michał Pierzchała 59d28e8446 refactor: add provider-first device lab tests (#542)
* refactor: add provider-first device lab tests

* refactor: tighten device lab provider seams

* test: cover provider lab contracts

* docs: record device lab harness direction

* ci: run device lab integration tests

* test: move device lab under integration

* test: extract device lab helpers

* refactor: centralize apps filter defaults

* test: drop lab-covered unit tests

* test: fold platform happy paths into device lab

* test: reuse device lab helpers

* test: move device lab to in-process harness

* test: replace session handler cases with device lab

* test: harden device lab scenario contracts

* docs: define unit test retention policy

* test: expand provider device lab coverage

* test: harden provider device lab coverage

* test: cover manifest install and runner session contracts

* chore: remove unused provider cleanup code

* test: split android find device lab scenario

* test: track provider lab architecture progress

* test: clarify provider lab roadmap progress

* test: advance provider lab session coverage

* test: move menubar click routing to device lab

* test: move menubar snapshots to device lab

* refactor: centralize screenshot flag plumbing

* refactor: colocate screenshot flag metadata

* test: cover all public commands in device lab

* test: move macos wait success to device lab

* test: drop redundant perf and diff units

* test: move push payload paths to device lab

* test: move network parsing to device lab

* test: move log cleanup to device lab

* test: move log restart and boot to device lab

* test: move ios physical boot to device lab

* test: cover perf startup in device lab

* test: extract android and ios device lab worlds

* test: trim device lab world surface

* test: split snapshot capture unit coverage

* test: deepen device lab coverage and trim handler units

* test: clean up device lab migration scaffolding

* test: report device lab public command coverage

* refactor: make Apple provider seams semantic

* refactor: tighten device inventory and Linux provider seams

* refactor: tighten request provider scoping

* refactor: add semantic macos host provider

* test: broaden device lab find coverage

* test: cover workflow flags in device lab

* refactor: promote linux input provider seam

* test: clarify device lab flag coverage

* test: classify snapshot force-full progress

* test: enforce device lab progress in ci

* test: stabilize device lab ci

* test: move packaged metro smoke to integration

* test: drop stale provider seam coverage

* test: harden provider scope regression coverage

* refactor: remove stale platform barrels

* refactor: keep linux clipboard and screenshots semantic

* refactor: move macos host tools behind provider

* fix: honor remote artifact output paths

* test: deepen runtime coverage for daemon and runner paths

* test: share loopback test helpers

* refactor: make daemon runtime importable

* fix: honor replay target metadata

* chore: tighten final device lab quality gates

* test: share device lab setup helpers

* test: remove generic apple lab fallback

* test: deduplicate device lab helpers

* chore: tighten fallow duplication signal

* refactor: share apple diagnostic helpers

* fix: detect active android ime during fill verification

* test: consolidate provider-backed integration suite

* ci: fix fallow and iOS smoke setup

* chore: consolidate cleanup after ci fixes

* test: split vitest unit and integration projects

* docs: mention MCP discovery metadata

* docs: add agent skills context pointers

* fix: close provider recording coverage gaps

* fix: restore mcp compatibility smoke

* test: cover provider edge regressions

* test: consolidate loopback helpers

* docs: remove stale provider routing reference

* fix: harden final provider review issues

* chore: defer mcp cleanup from provider refactor
2026-05-18 14:50:52 +02:00