fix(daemon): surface proven no-effect gestures to the agent - #1601
Conversation
The #1542 post-gesture stabilization loop already PROVES when a scroll, swipe, or pan moved nothing: its accept-stale verdict fires only when the quiet post-gesture capture still equals the pre-gesture baseline after the distrust cap. But the verdict went to the diagnostics stream only — the agent-facing response reported plain success, and the benchmark showed the cost: element-18 burned ~40 tool calls re-issuing scrolls the daemon knew did nothing ("Scrolled up by 1200px" fifteen times over a byte-identical tree) before stumbling onto raw swipe. The stabilization loop now returns the verdict alongside the capture, and the snapshot handler appends a warning through the existing annotations channel: it names the exact gesture, admits the at-edge ambiguity the platform cannot resolve, and hands over the raw-drag escape hatch that moved the stuck list in the field. Live-verified on the seeded Bluesky feed: scroll up at top warns, scroll down with real room moves silently, a fling at the bottom edge warns — all three truthful.
Size Report
Startup median (7 runs, lower is better):
Top changed chunks:
|
|
P1: Do not present |
…review P1) accept-stale alone is subset-tolerant by design: a successful scroll that replaced every list cell under fixed chrome still classifies 'unchanged' on the shared chrome alone, and #1573 has live evidence of that shape. The agent-facing claim now additionally requires every discriminating entry of the quiet capture to match the baseline exactly, in both directions (haveIdenticalDiscriminatingSurfaces): any appeared or vanished real element — including scope drift — vetoes the warning. Silence is the safe failure mode for a message that steers the agent's next move. Red evidence: the new fixed-chrome + replaced-list regression test fails on the previous PR commit (gestureNoEffect wrongly present), passes with the gate.
|
Addressed in 7af45ba — the P1 was correct, and the fix follows the "stronger full-surface evidence" option:
Trade-off accepted: the warning becomes rarer (scope-drift no-ops now stay silent), which is the right direction for a message that steers the agent's next gesture. The live-verified cases from the PR body (top-edge scroll, bottom-edge fling on the seeded feed) still warn — identical presentations on both sides. 🤖 Addressed by Claude Code |
capturePostGestureStabilizedResult crossed the complexity threshold (14 cyclomatic) after the #1601 review gate; the accept/veto construction now lives in buildAcceptedStabilizedResult, which also keeps the corroboration rule stated in one place.
|
Re-review at Not ready on exact-head evidence: Fallow deterministically rejects |
|
Re-review at |
|
Fixes #1600.
What
The #1542 post-gesture stabilization loop already proves when a scroll/swipe/pan moved nothing: its
accept-staleverdict fires only when the quiet post-gesture capture still equals the pre-gesture baseline after the 3.5s distrust cap — with scope-drift and root/keyboard-chrome subtleties already handled byclassifyBaselineSurfaceEvidence. But the verdict only reached the diagnostics stream; the agent-facing response reported plain success.This PR returns the verdict from
capturePostGestureStabilizedResultalongside the capture value, and the snapshot handler appends a warning through the existingannotations.warningschannel (already rendered by every client path — zero new plumbing):The wording deliberately admits the at-edge ambiguity: iOS has no authoritative can-scroll signal (Android does), so "at edge" vs "container ignores synthesized scrolls" cannot be distinguished platform-side — but either way the agent's next move is informed instead of blind.
Why
AppControlBench element-18 (gpt_high): reaching "Manage sessions" in Element's settings table cost 433s / 80 tool calls, ~40 of which were scroll/fling/pan attempts that all reported success over a byte-identical tree — only a raw
swipemoved the list. The daemon's stabilization loop (post-#1542) detects exactly this condition; it just never told the agent.Red evidence
Both new tests fail on base
3696f338b/ current main pre-fix:Live verification (seeded bench Bluesky feed, worktree build)
scroll up 1at feed topscroll down --pixels 600mid-feedNotes
positionalsstored on the stabilization marker feed the wording only (numeric args filtered out); nothing is re-dispatched.