Files
callstack__agent-device/test/integration/interaction-contract/native-ref.coverage.ts
Michał Pierzchała c93dcdbc90 feat: disclose selector resolution in interaction responses (#1193)
* feat: disclose selector resolution in interaction responses

Implements ADR-0012 migration step 1 (decision 2). Adds an additive
`resolution` field to press/click/fill/longpress responses: runtime-selector
carries the full pre-action diagnostic shape (unique or disambiguated with
matchCount/winnerDiagnostic/tiebreak/bounded alternatives), runtime-ref and
native-ref carry the exact ref-provenance shape, direct-ios-selector carries
the explicit not-observed marker, and coordinate/maestro-non-hittable-fallback
stay inapplicable (no field). The comparator in selectors-resolve.ts now
records which criterion (visible/deepest/smallest-area) decided each
disambiguation without changing resolveSelectorChain's winner.

Extends the ADR-0011 guarantee matrix with the resolutionDisclosure guarantee
across all six dispatch paths, wires the shared response builder and MCP
output schema, adds digest-level trimming (drops alternatives, keeps the
verdict/counts), and proves via contract tests that resolution diagnostics
are never ref-issued or MCP-pinned and cannot be reused as @ref targets.

* fix: address resolution disclosure review findings

* refactor: make resolution-disclosure choices self-evident

Replace the direct-iOS/maestro message-sniffing (and its justification
paragraph) with an explicit maestroFallback flag passed from the dispatch
site that already owns the path decision, and shrink every why-this-is-OK
paragraph to one-line constraint statements per the maintainer directive.

* fix: usage-based maestro fallback disclosure + spec label-fallback

Blocker 1: the runner-payload source now carries maestroFallbackUsed derived
from the runner's actual execution outcome (the usedNonHittableFallback
message bit RunnerTests+CommandExecution.swift reports, the same signal
directIosSelectorFallbackDetails already keys on) instead of the permission
flag. A fallback-allowed dispatch that hit its element normally discloses
direct-ios/not-observed; only an actually-executed coordinate fallback is the
inapplicable maestro cell. Contract tests cover both sides.

Blocker 2: ADR-0012 decision 2 now defines the ref/label-fallback disclosure
(runtime-ref trailing-label recovery via tryResolveRefNode's fallbackLabel;
native-ref stays exact because the backend receives only the ref handle),
amends the matrix-cell enumeration, layer-3 coverage list, and validation
bullet, and the runtime-ref contract suite proves the label-fallback shape.

* fix: honest runtime-ref registry cells for label recovery

The disambiguation cell no longer claims refs identify exactly one node by
construction — trailing-label recovery is a first-match lookup without the
ranking, now an intentional waiver whose outcome the label-fallback
disclosure surfaces per-response. resolutionDisclosure.via points at
tryResolveRefNode (now exported), the resolver producing both exact and
label-fallback, with direct unit coverage of both outcomes.

* docs: correct native-ref exactness rationale and tiebreak doc

Native-ref forwards fallbackLabel to the backend; exact is justified by
non-observability of any backend-side label recovery, not by non-forwarding.
The tiebreak doc now states the derived winner-vs-runner-up decisive margin.

* fix: disclose Maestro fill fallback usage
2026-07-11 09:09:44 +02:00

22 lines
1.2 KiB
TypeScript

import { definePathCoverage } from './coverage-manifest.ts';
export const NATIVE_REF_COVERAGE = definePathCoverage('native-ref', {
occlusion: 'native-ref occlusion: preflight refuses a covered ref before the backend call',
offscreen: 'native-ref offscreen: preflight refuses an off-screen ref before the backend call',
nonHittable:
'native-ref nonHittable: preflight annotates a non-hittable ref and still calls the backend',
responseConstruction:
'native-ref responseConstruction: fast-path result carries the canonical ref field set',
responseIdentity:
'native-ref responseIdentity: fast-path result echoes the ref target and backend result',
verifyEvidence: 'native-ref verifyEvidence: --verify skips the fast path and returns evidence',
settleObservation:
'native-ref settleObservation: --settle skips the fast path and returns the settled diff',
// The preflight raises the runtime path's exact offscreen_ref shape (code,
// reason, hint), which is the shared taxonomy on this path.
errorTaxonomy:
'native-ref offscreen: preflight refuses an off-screen ref before the backend call',
resolutionDisclosure:
'native-ref resolutionDisclosure: fast-path result discloses the exact ref-provenance shape',
});