Skip to content

fix(settle): compare post-action trees in one view across every route - #4500

Merged
thymikee merged 15 commits into
mainfrom
fix/settle-diff-view-baseline
Nov 13, 2026
Merged

thymikee merged 15 commits into
mainfrom
fix/settle-diff-view-baseline

Conversation

@thymikee

@thymikee thymikee commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Summary

Switching full and interactive snapshots produced false removals. One presentation rule covers settle, verification and snapshot diffs, including depth, scope, raw and custom actions.

Both settle routes select a baseline through capture-kit and reproduce its view. --verify reproduces its pre-action view; combined verification preserves known surface transitions. diff snapshot starts a baseline when the latest stored view differs. Missing presentation metadata means the default full tree.

18 files; includes verify/diff routes and tests. Fixes #4486.

Validation

Head 5b2c4cd685, pristine base efe6bb9eec. Independent findings fixed; seven new regression cases fail before these revisions and pass now. Focused: 962 passed; related integration: 406 passed; full unit: 19,726 passed, three skipped. Standalone smoke: 76 passed, six skipped.

check:affected --run --head HEAD receipt: failed, exactCommit=true (CLI smoke cleanup timeout). Base and head standalone smoke pass; cause unproven. CI must validate the full head.

Live Pixel 9a profile, Android 17/API 37, Settings Device name dialog; T3-bound command, source daemons, android-helper version 0.21.38-dev:

Same command sequence Base Head
snapshot -i; snapshot; press @e3 --settle +0 -10 +0 -0, 16 unchanged
snapshot -i; wait text "Device name"; scroll down --settle +0 -10 +0 -0, 6 unchanged
snapshot; diff snapshot -i 19 removals baseline initialized, zero removals
snapshot -i; press @e1 --settle --verify unchanged, false unchanged, false

Sessions closed; emulator shut down. No live iOS run.

After a full snapshot (no -i), the settle diff compared that tree with the
interactive view the settle loop reads, so every wrapper node the view omits
read as removed while nothing changed. The baseline now carries whether it is
a full view, and such a settle diffs from its own settled capture and says so
in its hint. Later settles diff interactive against interactive.

Fixes #4486

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 6.25 MB 6.25 MB +1.8 kB
Package (unpacked) 6.25 MB 6.25 MB +1.8 kB
Package (download) 1.90 MB 1.90 MB +580 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 22.9 ms 23.1 ms +0.2 ms
CLI --help 41.2 ms 44.2 ms +3.0 ms

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/capture-kit/src/snapshot-baseline.ts">

<violation number="1" location="packages/capture-kit/src/snapshot-baseline.ts:31">
P2: This skips full-tree baselines when `SnapshotState.presentation` is absent, even though the snapshot contract defines absence as the default full tree. Preserve the distinction for `undefined` snapshots, but mark an existing snapshot with no presentation as `fullView` so legacy or metadata-poor full snapshots do not reintroduce the false removals.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread website/docs/docs/commands.md Resolved
@apex-sentinel-staging

apex-sentinel-staging Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Apex Sentinel · ✅ Approve

Since the last review: 2 new · 0 still open · 1 no longer raised (1 marked fixed)

2 finding(s): 2 minor.

🟡 Minor (2)

Where Finding
packages/command-runtime/src/commands/capture/runtime/snapshot.ts:139 🆕 diff snapshot drops the stored baseline when the capture carries no presentation
packages/command-runtime/src/commands/interaction/runtime/post-action-observation.ts:91 🆕 --settle --verify loses changedFromBefore when preAction and frame views differ

Reviewed with this repository's own Sentinel configuration (efe6bb9eece4).

💬 Talking to Sentinel

In a finding's thread, reply with:

Command What it does
@apex-sentinel-staging note <context> Adds context; Sentinel re-checks the cited code
@apex-sentinel-staging pivot <why> Says the finding is wrong; Sentinel re-checks the cited code
@apex-sentinel-staging like Marks the finding as useful
@apex-sentinel-staging dislike <why> Marks it as not useful, so it is not raised again

On this conversation, comment @apex-sentinel-staging review to run a full review once again.

Earlier reviews

Review of 1f15eb0b · 13.11.2026 09:52 UTC

Apex Sentinel · ✅ Approve

Since the last review: 1 new · 0 still open · 0 no longer raised

1 finding(s): 1 minor.

🟡 Minor (1)

Where Finding
packages/command-runtime/src/commands/capture/runtime/snapshot.ts:139 🆕 diff snapshot can now self-compare a ref frame and always report no change

Reviewed with this repository's own Sentinel configuration (efe6bb9eece4).

Review of 0149a53b · 12.11.2026 21:16 UTC

Apex Sentinel

Verdict: approve

Since the last review: 0 new · 0 still open · 1 no longer raised (1 marked fixed)

No findings.

Reviewed with this repository's own Sentinel configuration (d2426fffdf78).

Review of 2e941c2a · 12.11.2026 21:01 UTC

Apex Sentinel

Verdict: approve

Since the last review: 0 new · 1 still open · 3 no longer raised (1 marked fixed)

1 finding(s): 1 minor.

🟡 Minor (1)

Where Finding
packages/command-runtime/src/commands/interaction/runtime/settle.ts:270 fullView mark ignores customActions, so --actions ref frames still false-diff

Reviewed with this repository's own Sentinel configuration (d2426fffdf78).

Review of 3b6a9f7d · 12.11.2026 20:43 UTC

Apex Sentinel

Verdict: approve

Since the last review: 4 new · 0 still open · 1 no longer raised

4 finding(s): 3 minor, 1 nit.

🟡 Minor (3)

Where Finding
packages/command-runtime/src/commands/interaction/runtime/settle.ts:268 🆕 A ref frame with no presentation (documented as the default full tree) is not marked, so false removals remain
packages/command-runtime/src/commands/interaction/runtime/settle.ts:281 🆕 scroll/back --settle now reads the full tree, contradicting the PR scope
packages/command-runtime/src/commands/interaction/runtime/settle.ts:268 🆕 Any non-interactive ref frame is marked fullView, so scoped/depth-limited frames diff against the whole screen
🔵 Nit (1)
Where Finding
packages/command-runtime/src/commands/interaction/runtime/settle.ts:281 🆕 Session-snapshot branch does not carry the fullView marking

1 finding below minor not shown (user_settings.min_severity).

Reviewed with this repository's own Sentinel configuration (0495ee1bb3ae).

Review of 6e5ada80 · 12.11.2026 19:06 UTC

Apex Sentinel

Verdict: approve

Since the last review: 1 new · 0 still open · 0 no longer raised

1 finding(s): 1 minor.

🟡 Minor (1)

Where Finding
packages/command-runtime/src/commands/interaction/runtime/settle.ts:313 🆕 Truncation is measured after removals are dropped, so the line cap silently shrinks

2 findings below minor not shown (user_settings.min_severity).

Reviewed with this repository's own Sentinel configuration (9676eedac5b0).

Review of 9a623dc6 · 12.11.2026 18:56 UTC

Apex Sentinel

Verdict: approve

Since the last review: 0 new · 0 still open · 1 no longer raised (1 marked fixed)

No findings.

1 new finding away from what changed since a79152d not shown. Comment @apex-sentinel-staging review for a full review.

Reviewed with this repository's own Sentinel configuration (9676eedac5b0).

Review of a79152d9 · 12.11.2026 18:45 UTC

Apex Sentinel

Verdict: approve

Since the last review: 1 new · 0 still open · 2 no longer raised (2 marked fixed)

1 finding(s): 1 minor.

🟡 Minor (1)

Where Finding
packages/command-runtime/src/commands/interaction/runtime/settle.ts:199 🆕 A same-surface screen transition after a full snapshot now reports +0 -0 with no additions

1 finding below minor not shown (user_settings.min_severity).

Reviewed with this repository's own Sentinel configuration (9676eedac5b0).

Review of a8995d3b · 12.11.2026 18:18 UTC

Apex Sentinel

Verdict: approve

2 finding(s): 2 minor.

🟡 Minor (2)

Where Finding
packages/capture-kit/src/snapshot-baseline.ts:31 Selector-targeted --settle always reports +0 -0: preAction tree is a full capture
packages/command-runtime/src/commands/interaction/runtime/settle.ts:221 Full-tree hint replaces the tiny-tree and loop hints on the fullView route

Reviewed with this repository's own Sentinel configuration (9676eedac5b0).

@apex-sentinel-staging apex-sentinel-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apex Sentinel: 2 new findings on a8995d3. The verdict and the full list are in the summary comment.

Address review: the full-view hint replaced the loop hint (such as the
tiny-tree readiness hint) instead of joining it, the wording could read as
diffing against the full view, and the interactive-baseline test used a tree
that held the full-view wrapper.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

thymikee and others added 2 commits November 12, 2026 19:25
Address review: selector resolution captures are full trees and fed the
settle baseline through preAction, so marking every non-interactive
presentation reset every selector-targeted settle to +0 -0. Only the ref
frame the agent read as a full snapshot is marked now; selector and
generic-route baselines keep their diff.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Address review: the new hint helper sat between resolveSettleHint and its
JSDoc.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

@apex-sentinel-staging apex-sentinel-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apex Sentinel: 1 new finding on a79152d. The verdict and the full list are in the summary comment.

Address review: resetting the baseline to the settled capture made every
settle after a full snapshot report +0 -0, even when the press navigated.
The diff now runs against the full ref frame and lists only added lines: the
interactive view adds no node of its own, so additions are evidence, while
removals of nodes that view never reads are not.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Address review: the every() check passed on an empty line list. The settle
comment now states that only Android's interactive view adds no node of its
own; an iOS row rewrite can still read as added, as before.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

@apex-sentinel-staging apex-sentinel-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apex Sentinel: 1 new finding on 6e5ada8. The verdict and the full list are in the summary comment.

@thymikee

Copy link
Copy Markdown
Member Author

CI is green on 6e5ada8 (22 checks, none failing), and there are no conflicts. The fix still needs a live Android run before merge.

The round-4 algorithm lists added lines from a full-tree baseline against the settled interactive view (settle.ts#L316). That is only sound if the Android interactive view adds no node of its own, and no device run shows this. The unchanged-dialog run in the PR body used a79152d, the discarded round-1 algorithm. The head run is a navigating sequence (+5 -0), and the later Back run is a selector press that never carries fullView. If full and interactive nodes differ in any compared attribute (text, flags, rect rounding), an unchanged dialog will still print false +N lines with refs. The headline behavior is therefore unobserved at this SHA. Please run this on the Android emulator at 6e5ada8: open Settings > Device name, run snapshot -i, then snapshot, then press @eN --settle on a ref that does not dismiss the dialog (the status-bar clock, as in the issue). Report the exact settle line, diff.lines and hint. Expected: +0 -0 (or explain any added lines), the full-tree hint, and no wrapper removals. Then press a second @ref right after to show the flag cleared (no hint). That second press must be a @ref press, not a selector. Please record the SHA, device and commands in the PR body.

Not blocking, take or leave: (1) the same full-vs-interactive mismatch has two more baseline producers that are not marked, selector preAction (captured with interactiveOnly false in selector-read-shared.ts:86) and the daemon generic-settle storedTreeBaseline for scroll/back, so both still print wrapper nodes as removed, and test 4 only asserts removals > 0, which holds for false and genuine removals alike; either derive fullView once from snapshot.presentation in surfaceScopedNodes so every producer is covered, or note that selector and scroll/back stay open and file a follow-up. (2) The PR body says commands.md documents the iOS row-rewrite limit, but the paragraph at website/docs/docs/commands.md:497 does not, so please add one sentence that iOS may still list rewritten rows as added, or fix the PR body; issue #4486 lists an iOS 27.2 Simulator and no iOS run is reported. (3) Forcing summary.removals to 0 prints -0 and reads as a fact to JSON/MCP consumers, so a typed removalsOmitted field would be clearer, and baseline.fullView is checked truthy in buildSettleDiff but === true in readSettledOutcome. (4) FULL_VIEW_BASELINE_HINT says later settles diff against the settled interactive view, but the ref frame only advances when a settle issues at least one ref, so a settle with an empty diff leaves the full tree as the baseline; consider softening the wording.

For the open inline threads: the iOS row-rewrite one still applies as a non-blocking note (#4500 (comment)). The other review threads are fixed at this head or benign, so the author can resolve them: #4500 (comment) (production always sets presentation, only fixtures omit it), #4500 (comment), #4500 (comment), #4500 (comment), #4500 (comment), #4500 (comment), #4500 (comment), #4500 (comment), #4500 (comment) (all fixed at head), and #4500 (comment) (truncated is measured after removals are dropped, by design).

This review read the code only. I did not run the unit tests or any device, and the live table in the PR body was not reproduced. The SHA attribution of its rows is taken from the PR text, and the iOS behavior is taken from the code comment and the thread.

thymikee and others added 2 commits November 12, 2026 21:28
Address review: a forced removals count of 0 read as a fact. The settle diff
now carries removalsOmitted, the text verdict prints "removals not listed",
the hint no longer promises a baseline the ref frame may not advance to, and
the docs note the iOS row-rewrite limit.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Address review: listing only additions against a full-tree baseline still
reported the keyboard window as added, because the interactive view reads
windows the full tree does not. A settle on refs from a full snapshot now
captures the full tree too, so its diff compares one view and issues
full-tree refs. The removals flag, hint and formatter change are gone.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@thymikee

Copy link
Copy Markdown
Member Author

Thanks, the live run was the right ask: it disproved round 4.

Live run at 54438311cb (round 4, additions only). Pixel 9a API 37 emulator, Settings › About › Device name dialog. Commands: snapshot -i, snapshot --force-full, press @e3 --settle (status-bar clock). With the keyboard up, the settle reported +43 -0: every IME key read as added. The interactive capture reads the input-method window, and the full capture does not, so additions against a full tree are not sound. Your premise check was correct.

New design at 3b6a9f7d5a. When the ref frame was read as a full tree, the settle loop captures the full tree too. Both diff sides use one view, and the issued refs are full-tree refs, matching what the agent last read. Interactive ref frames and selector presses keep the interactive view. The additions-only filter, the removalsOmitted flag, the formatter change and the full-view hint are all gone, which also settles (3) and (4).

Live at head, same dialog with the keyboard up:

  • press @e3 --settle → settled after …: +0 -0 (~17 unchanged), diff.lines: [], no hint, tail of 16 full-tree refs.
  • press @e142~s972613 --settle (dialog title, pinned from that response) → +0 -0 (~17 unchanged), diff.lines: [], no hint. The stored settle capture is itself a full tree, so later ref settles stay full against full.

Non-blocking notes:

  1. The selector preAction and generic scroll/back baselines are unchanged and noted as open in the PR body. I tried to file a follow-up issue, but the tool permissions in this session blocked it, so please file one or ask me once allowed. Test 4 now asserts that the genuine Device name removal is listed and that the loop stayed interactive.
  2. The iOS row-rewrite caveat no longer applies to this route, which compares full against full. The PR body no longer claims it.
  3. Moot: no forced removals: 0 remains.
  4. Moot: the hint is removed.

Tests: settle-view-baseline.test.ts (both full-frame cases fail on base). The interaction, command-output and capture-kit suites pass (1837 tests), and typecheck and check:quick pass. The PR body has the device, SHA and commands.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

@apex-sentinel-staging apex-sentinel-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apex Sentinel: 4 new findings on 3b6a9f7. The verdict and the full list are in the summary comment.

@thymikee

Copy link
Copy Markdown
Member Author

I reviewed 3b6a9f7 against the earlier findings. The dropped settle hint, the truncated count after removals, and the additions-only filter with the iOS row-rewrite caveat are all fixed at this head. Three open review threads still apply and should be fixed before merge (below).

Not blocking, and you can take or leave these: the sentence at commands.md:497 says a --settle action after a full snapshot compares one view, but snapshot --depth, --scope and --raw frames take the same route and still diff against a different projection, so either qualify the sentence or carry the frame's presentation into the settle capture. Also, the "Still open" paragraph in the PR body says selector presses resolve on a full capture, but press and click request the interactive tree first and fall back to full only when the node is missing, so please reword it and file the follow-up issue for the selector fallback and the scroll/back baselines.

On the open inline threads: these three should be fixed before merge: the selector test premise, the settle tail comment and depth/scope/raw frames. The two comment-drift threads also still apply. These three no longer apply and can be resolved: row-rewrite caveat (full is now diffed against full), truncated count (removals are no longer dropped), and dropped hint (the hint is spread directly).

I did not run a device or the tests. The Android live table, the 1837-test pass and the typecheck come from the PR body and author comment, and the regression reasoning comes from reading the base code. Nothing covers iOS, where the loop now captures a full tree per poll after a full snapshot, or --settle --verify on a full ref frame. After a full snapshot, a --settle on Android also no longer shows keyboard chrome in the diff.

CI shows 21 of 22 checks passing, and the remaining one is an external review check, still in progress. Before merge, please fix the three threads above and file the follow-up issue.

thymikee and others added 3 commits November 12, 2026 21:51
Address review: a scoped, depth-limited or raw frame is a projection the
settle capture does not reproduce, so only an unprojected full snapshot is
marked fullView. Point taps keep the session baseline unmarked. A full-tree
settle carries no tail, because the tail names interactive targets. Comments
now describe the full-tree path.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
An unchanged full-tree settle without a tail handed back no refs, so the next
@ref press hit an expired frame. The tail stays, listing addressable refs from
the full-tree view the agent chose.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Address review: custom actions are another projection the settle capture does
not reproduce, like scope, depth and raw.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@thymikee

Copy link
Copy Markdown
Member Author

This PR is ready at 0149a53. The two problems from the earlier review (#4500 (comment)) are fixed: the full-view check now excludes -s and --actions frames, and the tests cover both. All 22 checks pass at this commit. There are no conflicts, and nothing else must happen before merge.

Not blocking, and you can take or leave it: the wholeFullTree predicate at https://github.com/callstack/agent-device/blob/0149a53/packages/command-runtime/src/commands/interaction/runtime/settle.ts#L271 spells out the five presentation option keys by hand, while SNAPSHOT_PRESENTATION_OPTION_KEYS and buildSnapshotPresentationKey in kernel/snapshot.ts already own that list. A sixth presentation key would then wrongly count as a whole full tree. Comparing snapshot.presentationKey with buildSnapshotPresentationKey(undefined) would avoid that, if the fixtures set presentationKey.

Of the earlier inline threads, the five earlier review threads and the two at #4500 (comment) and #4500 (comment) are fixed at this head, so you can resolve them. These two do not apply, so please resolve them too: #4500 (comment) describes an earlier head, and the stored snapshot baseline is now the plain one as on main. #4500 (comment) is a limit the PR body already documents (point taps and scroll/back --settle stay open), not a regression.

I did not re-run the Pixel 9a live runs, and I did not run the new tests locally. The live runs in the PR body are at earlier commits, and this change only narrows which frames get the full view. -d and --raw are not parametrized in the tests and rely on the shared predicate.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Nov 13, 2026
thymikee and others added 2 commits November 13, 2026 10:31
…baseline

* origin/main:
  ci: use smaller runners for control and publishing jobs (#4492)
  docs(help): point verification at read-only commands, not bare find (#4497)
  fix(android): let open --relaunch accept a package Android restarts at once (#4498)
  fix(snapshot): name the captured Android app in the snapshot header (#4499)
  feat(proxy): configure trusted public upload origins (#4501)
  fix(android): restore screenshot demo permission state (#4477)
  feat(harmonyos): support app uninstall beside deploy (#4292)
  fix(ios): confirm foldable rotation from the lit panel in either simulator set (#4343) (#4440)
  chore: mark 0.21.37 as released
  fix(ios): make back the verified left-edge swipe (#4460)
  fix(ios): mark zero-area nodes unmeasured and point their press refusal at scroll --until (#4495)
  fix(ios): never repeat a synthesized gesture that may have run (#4474)
  fix(capture): publish cropped screenshots atomically after scaling (#4478)
  ci(android): reuse cached system images across emulator workflows (#4490)
A settle diff compared whatever pre-action tree it found with an
interactive settle capture, so a full snapshot, a selector fallback or a
full tree a selector read stored showed up as false removals (#4486).

One rule now owns every post-action comparison: two trees are compared
only when they were read in the same presentation. capture-kit's
postActionBaseline picks the baseline in the agent's view, the
presentation of the ref frame it last read, and SurfaceScopedNodes carries
that presentation. The settle loop captures in it for press, click, fill,
longpress, scroll and back, on refs, selectors and coordinates. --verify
captures in the pre-action tree's view, and diff snapshot starts a new
baseline when the stored tree was read in another view.

Fixes #4486

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@thymikee thymikee changed the title fix(settle): never diff a settle against a full-tree snapshot fix(settle): compare post-action trees in one view across every route Nov 13, 2026
@thymikee

Copy link
Copy Markdown
Member Author

I redid this PR as you suggested, so the view rule is consistent across every post-action route instead of only ref presses.

Rule. Compare two trees only when they were read in the same presentation (-i, -d, -s, --raw, --actions).

  • isSameSnapshotPresentation (kernel) states it.
  • SurfaceScopedNodes.presentation carries each baseline's view.
  • postActionBaseline in capture-kit/snapshot-baseline.ts, already the single owner of settle baselines for both routes, picks the baseline in the agent's view, which is the presentation of the ref frame it last read. A candidate read in another view is skipped, and the frame answers.

Routes.

  • Touch commands (refs, selectors, coordinates) and the daemon's scroll/back route pick their baseline through postActionBaseline, keeping main's order of preference. The settle loop captures in that baseline's presentation.
  • --verify captures in the pre-action tree's view. With --settle --verify, it compares only trees from one view.
  • diff snapshot diffs against the stored tree or the ref frame read in the requested view, else it initializes the baseline.

Live, Pixel 9a API 37, at 1f15eb0b4b.

Scenario base head
A: press after full snapshot +0 -10 +0 -0
B: scroll --settle after a wait that stored a full tree +0 -10 +0 -0
C: diff snapshot -i after a full snapshot 19 removals baselineInitialized: true
D (control) unchanged unchanged

Production diff: 10 files, +170 −60. The earlier ref-only marking, the tail and hint special cases, and the fullView flag are all gone.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 14 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread website/docs/docs/commands.md Resolved

@apex-sentinel-staging apex-sentinel-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apex Sentinel: 1 new finding on 1f15eb0. The verdict and the full list are in the summary comment.

@thymikee

Copy link
Copy Markdown
Member Author

The review findings are fixed at 5b2c4cd685:

  • Baseline selection loads the presentation comparator on demand, preserving the existing eager closure budget.
  • Settle fixtures preserve depth/raw/custom-action options and assert the complete unchanged summary.
  • wait stable keeps its requested scope/depth/raw options.
  • A ref frame reused by the generic route drops unverified presented-surface facts.
  • diff snapshot compares only with the latest stored snapshot; a different view initializes a baseline. The proxy and Android provider scenarios now assert this behavior.
  • An absent presentation means the default full tree, including public backends that omit this optional metadata.
  • Verification retains known surface transitions even when node presentations differ. The docs distinguish standalone verification from settle plus verification.

Independent review completed; all three findings are fixed. In an isolated checkout of 1f15eb0b4b, the extended tests produce seven intended failures (52 pass). At head they pass; the focused suite including eager closure guards passes 962 tests. Both formerly failing provider scenario files pass (13 tests). The disposable checkout is removed.

The four live sequences in the PR body were repeated on exact base efe6bb9eec and head 5b2c4cd685, using separate source daemons and the T3-bound command. Base reports 10 false removals for both press and scroll, and 19 for the snapshot view switch. Head reports zero, with diff.lines: [] for both settles; the unchanged verification control remains false. Both captures use android-helper 0.21.38-dev. Sessions and daemons are closed, the emulator is shut down, and the comparison checkout is removed.

The previous Android smoke failure was selector_not_found while reading field-email after typing. Its subsequent failure snapshot contains that field. That alone does not establish an infrastructure cause; the new head must pass the Android lane.

Local validation at 5b2c4cd685:

  • The first affected receipt (exactCommit: true, checkoutChanged: false) failed in three subprocess timing cases: Apple teardown timeout; helper-exit privacy timeout; missing helper status after a 600 ms executor timeout.
  • The same pnpm run check:unit on pristine base efe6bb9eec failed in a different five-second subprocess timeout (platform-runtime-android-adb-host.test.ts:106). This does not prove the cause of the head failures.
  • The same three affected test files pass on both commits: 88 tests each.
  • One fresh affected attempt passed the full unit suite (2,099 files; 19,726 passed, three skipped) and leak check, then failed smoke-daemon-clean.test.ts:30 when the cleanup subprocess exceeded 5,000 ms. Its receipt remains failed, with exactCommit: true and checkoutChanged: false.
  • Standalone pnpm run test:smoke passes on both pristine base and head (76 passed, six skipped each). Cause remains unproven; no timeouts, worker settings, skips, or test selection were changed.
  • Related integration passes 88 files / 406 tests at head. CI must validate the complete pushed head before merge readiness; no whole-gate local pass is claimed.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 15 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/command-runtime/src/commands/interaction/runtime/post-action-surface.test.ts">

<violation number="1" location="packages/command-runtime/src/commands/interaction/runtime/post-action-surface.test.ts:122">
P2: This fixture does not actually exercise the claimed selector-versus-frame view mismatch: the first selector capture overwrites `session.snapshot`, and no `refFrameSnapshot` is initialized. Preserve `frame` as `refFrameSnapshot` (or configure the helper to do so) so the test verifies the frame fallback and presentation selection rather than only repeating the existing cross-surface case.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

const sheet = webSignInSheetSnapshot(WEB_SIGN_IN_SHEET_LABELS);
test('press --settle --verify reports a surface change even when the selector and frame views differ', async () => {
const before = { ...buttonSnapshot(), presentation: { interactiveOnly: true } };
const frame = { ...before, presentation: {} };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This fixture does not actually exercise the claimed selector-versus-frame view mismatch: the first selector capture overwrites session.snapshot, and no refFrameSnapshot is initialized. Preserve frame as refFrameSnapshot (or configure the helper to do so) so the test verifies the frame fallback and presentation selection rather than only repeating the existing cross-surface case.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/command-runtime/src/commands/interaction/runtime/post-action-surface.test.ts, line 122:

<comment>This fixture does not actually exercise the claimed selector-versus-frame view mismatch: the first selector capture overwrites `session.snapshot`, and no `refFrameSnapshot` is initialized. Preserve `frame` as `refFrameSnapshot` (or configure the helper to do so) so the test verifies the frame fallback and presentation selection rather than only repeating the existing cross-surface case.</comment>

<file context>
@@ -117,12 +117,13 @@ test('press --settle attaches no diff across a sheet-to-app surface change and d
-  const sheet = webSignInSheetSnapshot(WEB_SIGN_IN_SHEET_LABELS);
+test('press --settle --verify reports a surface change even when the selector and frame views differ', async () => {
+  const before = { ...buttonSnapshot(), presentation: { interactiveOnly: true } };
+  const frame = { ...before, presentation: {} };
+  const sheet = { ...webSignInSheetSnapshot(WEB_SIGN_IN_SHEET_LABELS), presentation: {} };
   let captures = 0;
</file context>

@apex-sentinel-staging apex-sentinel-staging Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apex Sentinel: 2 new findings on 5b2c4cd. The verdict and the full list are in the summary comment.

Comment on lines +91 to +101
// A surface transition is evidence in every view; node digests compare only within one view.
const baseline =
outcome.settledCapture &&
(resolvePostActionSurfaceChange(resolved.preAction, outcome.settledCapture) ||
isSameSnapshotPresentation(
resolved.preAction?.presentation,
outcome.settledCapture.presentation,
))
? resolved.preAction
: undefined;
const evidence = params.verify ? settleEvidence(outcome.settledCapture, baseline) : undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🆕 🟡 Minor · --settle --verify loses changedFromBefore when preAction and frame views differ

press label="Back" --settle --verify after a full-frame snapshot produces no evidence at all (changedFromBefore, digest, nodeCount all absent) when selector resolution reads an interactive tree as resolved.preAction. The new gate at lines 92–100 compares resolved.preAction against the settled capture, but the settle engine diffed against a different, view-matched baseline (postActionBaseline's frame).

Suggested change

Feed settleEvidence the baseline the settle loop actually diffed against (the postActionBaseline result on outcome) rather than gating resolved.preAction on its view; keep the surface-change escape hatch.

Details

persona: senior-developer, javascript

Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.

Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if it is wrong — I will re-check the cited code.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially valid at merged head 5b2c4cd: when selector preAction is interactive but settle substitutes a full ref-frame baseline, changedFromBefore is omitted. The claim that all evidence disappears is inaccurate: settleEvidence receives an undefined baseline and summarizePostActionEvidence still returns digest and node counts. Known surface transitions retain their verdict.

Local revision ed9ffd13a4277e507e73770621e82c23f3662e8f addresses the underlying substitution by keeping fresh selector pre-action captures and the latest stored observation for scroll/back, then reproducing that baseline presentation. It was not pushed before merge. The user then requested cleanup, which is complete. No worktree or follow-up PR has been recreated. Leaving this finding open for follow-up instead of marking an unmerged fix as resolved.

@thymikee
thymikee merged commit d387a45 into main Nov 13, 2026
22 checks passed
@thymikee
thymikee deleted the fix/settle-diff-view-baseline branch November 13, 2026 10:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android] After switching between snapshot and snapshot -i, the settle diff compares different views

1 participant