Extracts a single resolve_within_deadline poll-resolve helper shared by ref_action_wait's auto-wait loop and wait_element's element wait loop (F13), so the 750ms per-attempt cap and deadline math has one owner; each caller keeps its own retry classification and side effects (LatestRefCache refresh, ElementNotFound retry) as before. Deletes classify_query_result/ambiguous_candidate_summaries/ QueryCandidateSummary from locator.rs (zero callers) and simplifies find.rs's materialize_match to its snapshot-clone, dropping the index/tree/query params it silently discarded. Chosen over wiring the live path to build responses from live handles, which would change find's --count/--last semantics. Role::is_interactive now delegates to roles::INTERACTIVE_ROLES instead of re-encoding the 16 role names (F22). Consolidates three byte-identical NoopAdapter/StubSystemOps blanket test doubles (src/batch/tests.rs, src/dispatch/notifications.rs, tests/conformance/window_identity_contract.rs) into one file at tests/support/noop_ops.rs, included via #[path] since the binary's own unit tests and the standalone conformance integration crate cannot share a Rust module across the crate boundary. Extracts locate_verified_record in window_resolve.rs (parse -> find -> verify, previously duplicated by resolve_window_strict and resolve_window_element_strict) and compute_readonly in element.rs (previously duplicated identically by fetch_node_attrs and fetch_node_attrs_slow). Hoists element.rs's 18-entry CFString attribute-name array behind a thread-local cache (CFString/CFArray aren't Send+Sync so a process-wide LazyLock isn't viable) instead of rebuilding it on every node. Makes query.rs's collect_matches short-circuit on the cheap role check before building live-tree state/children context for elements that can never match. |
||
|---|---|---|
| .. | ||
| README.md | ||
| ref_action_contract.rs | ||
| window_identity_contract.rs | ||
Adapter Reliability Conformance
Every platform adapter must satisfy the same ref/action contract. The macOS
adapter is the first implementation, but the tests are written against
PlatformAdapter semantics so Windows UIA and Linux AT-SPI can reuse the same
expectations.
The reusable command-path helper lives in tests/conformance/ref_action_contract.rs.
The executable smoke harness in src/tests/conformance.rs uses it with a mock
adapter; future Windows and Linux fixtures can call the same helper with real
adapter-provided refs.
Required Gates
| Area | Required behavior |
|---|---|
| Snapshot refs | Refs are depth-first, snapshot-scoped, and explicit snapshot IDs resolve directly |
| Strict resolve | A ref resolves only when identity still matches; stale refs return STALE_REF |
| Ambiguity | Multiple plausible matches return AMBIGUOUS_TARGET, never an arbitrary click |
| Actionability | Ref actions check live visibility, stability, enabled state, supported action, policy, and editability before dispatch |
| Wait recovery | wait --element can poll the latest session refmap when no snapshot is pinned, honors the caller timeout while resolving, and reports the last observed predicate state |
| Session latest scope | Commands that omit --snapshot read and write only the active session's latest refmap |
| Explicit snapshot scope | Passing --snapshot <id> resolves that pinned snapshot even when the caller omits the original session |
| Trace | With a trace: on session manifest (from session start), commands write per-process JSONL segments under the session directory; --trace <path> overrides to one file. Best-effort unless --trace-strict. |
| Session lifecycle | session start/end/list/gc manage manifests, the current-session pointer, and trace directories |
| FFI parity | FFI ref actions use strict resolve and actionability checks before adapter dispatch |
Platform Matrix
| Fixture | macOS AX | Windows UIA | Linux AT-SPI |
|---|---|---|---|
| Two identical buttons produce ambiguity | Required | Required | Required |
| Ref disappears after snapshot | Required | Required | Required |
| Disabled button blocks click before dispatch | Required | Required | Required |
| Text field supports value/type actionability | Required | Required | Required |
| Session A latest refmap is invisible to Session B | Required | Required | Required |
| Batch item session overrides inherited session | Required | Required | Required |
FFI AdRefEntry preserves full identity envelope |
Required | Required | Required |
Adding Windows or Linux
Add adapter-specific integration fixtures, but keep expected errors and JSON
shapes identical. Prefer semantic platform actions first (AXPress, UIA
Invoke/Value/Selection patterns, AT-SPI actions). Coordinate input is a lower
confidence fallback and must remain explicit in policy or command choice.