You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 2149096
Browse filesBrowse the repository at this point in the historyBrowse files
feat: --settle returns the settled diff in the interaction response (#1101)
press/click/fill/longpress --settle executes the action, waits for the UI
to go quiet (wait stable's loop, shared via stable-capture.ts), and returns
the settled diff vs the pre-action tree in the same response — one round
trip instead of the interact -> observe pair.
- payload: changed lines only (bounded), summary counts, added-line refs,
refsGeneration; best-effort (settled:false + hint on never-quiet content,
never an action failure); --verify shares the settle captures
- ref issuance: the settled tree becomes the session snapshot; a
diff-carrying settle response clears snapshotRefsStale and the MCP layer
merge-only re-pins added-line refs at the settle generation
- grammar: --settle + --settle-quiet <ms> + --timeout <ms> (flag-sourced
descriptor budget with new envelope:'widen' semantics mirroring wait)
- ADR 0011: new settleObservation guarantee classified on every path with
contract scenarios per enforced/delegated cell
Copy file name to clipboardExpand all lines: CONTEXT.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -49,6 +49,7 @@
49
49
- Coverage manifest: `CONTRACT_COVERAGE` export beside each interaction contract test file claiming which matrix cells it proves; the coverage gate requires every enforced/delegated cell to be claimed and rejects overclaims of waived cells.
50
50
- Delegation-on-error: a fast path falling back to the runtime path on semantic failure shapes. It closes failure-side guarantee cells only — never success-path parity.
51
51
- Ref generation pin: optional `~s<n>` suffix on an @ref carrying the snapshot generation it was minted from. Accepted as input everywhere, emitted by no tree output (snapshot token budget), auto-appended by the MCP layer, stripped and ignored by replay.
52
+
- Settled observation: opt-in (`--settle`) post-action payload on press/click/fill/longpress — the quiet-window stable loop re-captures until the UI settles, and the response carries the diff vs the pre-action tree (changed lines only, added lines with fresh refs, `refsGeneration` when the settled tree was stored). Best-effort: never fails the action; `settled: false` plus a hint on never-quiet content.
52
53
- Snapshot capture plan: per-strategy ordered chain of iOS snapshot capture backends (recursive tree, query sweep, private AX) run by one plan runner under a shared wall-clock budget; recovery ordering is declared data, never a per-call-site branch.
53
54
- Snapshot quality verdict: structured outcome (state, backend, reason code, effective depth, collapsed leaves) computed once by the plan runner and shipped with every planned snapshot payload; the daemon and CLI render it instead of re-deriving degradation from node shapes.
54
55
- AX-unavailable target invalidation: iOS/macOS runner behavior where a root accessibility snapshot failure such as `kAXErrorIllegalArgument` marks the cached `XCUIApplication` target handle suspect. The runner fails closed for degraded interactive snapshots, clears the cached target, and lets the next command reacquire the app through normal activation.
'Capture cheap post-action evidence (AX digest, node counts, changedFromBefore) instead of a follow-up snapshot',
850
856
},
857
+
{
858
+
key: 'settle',
859
+
names: ['--settle'],
860
+
type: 'boolean',
861
+
usageLabel: '--settle',
862
+
usageDescription:
863
+
'After the action, wait for the UI to go quiet and return the settled diff vs the pre-action tree in the same response (best-effort; never fails the action)',
864
+
},
865
+
{
866
+
key: 'settleQuietMs',
867
+
names: ['--settle-quiet'],
868
+
type: 'int',
869
+
min: 0,
870
+
usageLabel: '--settle-quiet <ms>',
871
+
usageDescription: 'Settle: quiet window the UI must hold to count as settled (default 500ms)',
'Planning output contract: when asked to plan commands, output command lines only: no prose, numbering, Markdown fences, pipes, or shell helpers.',
62
62
'Default loop: devices/apps -> open -> snapshot -i -> press/fill/get/is/wait/find -> verify with diff snapshot -> close.',
63
63
'Verify a mutation with diff snapshot (or diff snapshot -i), not a full snapshot: it prints only the added/removed/changed lines since the last snapshot in this session, so confirming an action costs a few lines instead of the whole tree.',
64
+
'Collapse act+observe into one call with --settle on press/click/fill/longpress: the response waits for the UI to go quiet and carries the settled diff with fresh refs (settled: false plus a hint on never-quiet content; the action itself never fails). Tune with --settle-quiet <ms> and --timeout <ms>.',
64
65
'Use selectors or refs as positional targets: id="submit", label="Allow", or @e12 from snapshot -i.',
65
66
'Pin a ref to the snapshot that minted it with ~s<n> (n = refsGeneration in the snapshot response): press @e12~s4. Pinned refs get exact staleness warnings instead of the coarse tree-changed one; plain refs stay valid input.',
'Short press a semantic UI target by ref, selector, or point. For native context menus or hold gestures, use longpress <target> <durationMs> instead of press --hold-ms.',
'Open native context menus or long-press targets by ref, selector, or point. Duration is positional, for example longpress @e12 800 or longpress 300 500 800.',
Copy file name to clipboardExpand all lines: src/commands/interaction/metadata.ts
+12Lines changed: 12 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -71,19 +71,29 @@ const verifyField = () =>
71
71
'Capture cheap post-action evidence (AX digest, node counts, changedFromBefore) instead of a follow-up snapshot.',
72
72
);
73
73
74
+
constsettleFields=()=>({
75
+
settle: booleanField(
76
+
'After the action, wait for the UI to go quiet and return the settled diff vs the pre-action tree in the same response. Best-effort; never fails the action.',
77
+
),
78
+
settleQuietMs: integerField('Settle: quiet window in milliseconds (default 500).',{min: 0}),
79
+
timeoutMs: integerField('Settle: wait deadline in milliseconds (default 10000).',{min: 1}),
80
+
});
81
+
74
82
constclickFields={
75
83
target: requiredField(interactionTargetField()),
76
84
button: enumField(CLICK_BUTTONS,'Pointer button for platforms that support mouse buttons.'),
77
85
...selectorSnapshotFields(),
78
86
...repeatedFields(),
79
87
verify: verifyField(),
88
+
...settleFields(),
80
89
};
81
90
82
91
constpressFields={
83
92
target: requiredField(interactionTargetField()),
84
93
...selectorSnapshotFields(),
85
94
...repeatedFields(),
86
95
verify: verifyField(),
96
+
...settleFields(),
87
97
};
88
98
89
99
constfillFields={
@@ -92,12 +102,14 @@ const fillFields = {
92
102
delayMs: integerField('Delay between typed characters.',{min: 0}),
93
103
...selectorSnapshotFields(),
94
104
verify: verifyField(),
105
+
...settleFields(),
95
106
};
96
107
97
108
constlongPressFields={
98
109
target: requiredField(interactionTargetField()),
99
110
durationMs: integerField('Long press duration in milliseconds.',{min: 0}),
0 commit comments