Skip to content

fix(android): publish covered state from exact order evidence - #1981

Open
thymikee wants to merge 3 commits into
mainfrom
fix/android-occlusion-single-owner
Open

fix(android): publish covered state from exact order evidence#1981
thymikee wants to merge 3 commits into
mainfrom
fix/android-occlusion-single-owner

Conversation

@thymikee

@thymikee thymikee commented Aug 23, 2026

Copy link
Copy Markdown
Member

Summary

Centralize Android covered-state publication without guessing z-order.

  • Keep nodes in regular snapshots and make buildSnapshotState the sole owner of daemon-only interactionBlocked: "covered" publication.
  • Carry API 24+ sibling group and drawing order through a private evidence sidecar; no ordering evidence is added to public snapshot metadata.
  • Classify replacement surfaces with bounded multi-rect union coverage, so several higher-order actionable descendants may collectively cover a stale surface while sparse overlays remain actionable.
  • Fail conservative when exact order evidence or work budget is unavailable. API 23 retains androidSnapshot.occlusionScanUnavailable: true and publishes no covered verdict.
  • Preserve the consumer contract: interaction targeting and settle refuse covered targets, response refs omit them, and replay divergence excludes them unless the whole meaningful screen is covered.

This advances #1832 but does not claim API-level neutrality: API 23 cannot provide the exact sibling order required for a reliable covered-state verdict.

Validation

  • Planted red/green: two higher-order actionable descendants covering separate halves of a stale surface were previously reduced to one rect and left the stale action hittable; bounded union coverage now classifies it.
  • Focused classifier, union, public-route, replay, and size-ratchet suites: 5 files / 19 tests passed.
  • pnpm check:affected --run on Node 24: all runnable checks passed, including 556 related test files / 4,484 tests.
  • Test-size ratchets restored: snapshot.test.ts is 1,495 lines; session-replay-divergence.test.ts is reduced to 1,137 lines, with the new cases in focused sibling owners.
  • Historical live corpus inventory from fix(android): stop empty focusable overlays from hiding app content #1737: 33 API 36/37 screens across Telegram, the repository fixture, Bluesky/dev launcher, Settings, Clock, Files, Messages, Play Store, Photos, Chrome, Calendar, Contacts, alerts, and permission dialogs. The retired pruner fired on 4/33: three Telegram false positives and one legitimate Google Messages stale-surface prune; the other 30 screens preserved identical output. The original raw captures were not retained, so this is inventory evidence rather than a reproducible artifact corpus.
  • Fresh Pixel API 36 exact-route verification on Pixel_9_Pro_XL: a lower actionable 1128x720 sibling covered by two exact-higher-order actionable 1128x360 descendants remained present but published hittable: false, interactionBlocked: "covered", and presentationHints: ["covered"]; the two foreground actions remained hittable, and no sibling/order evidence leaked publicly.
  • Fresh Settings, Google Messages, and repository-fixture routes produced no false covered verdicts. Current Google Messages no longer reproduced the historical stale-tree transition, so it is not claimed as a fresh true positive.
  • API 23 conservative behavior is covered deterministically with API-23-shaped captures that omit drawing order. No API 23 device is available locally, so live API 23 verification remains unavailable.

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 2.39 MB 2.39 MB +1.5 kB
JS gzip 801.1 kB 801.7 kB +597 B
npm tarball 923.3 kB 923.9 kB +518 B
npm unpacked 3.20 MB 3.20 MB +1.5 kB

npm unpacked components

Component Base Current Diff
JS / dist source 2.54 MB 2.54 MB +1.5 kB
Apple runner source/project 564.3 kB 564.3 kB 0 B
macOS helper source 54.5 kB 54.5 kB 0 B
Android helper artifacts 0 B 0 B 0 B
Other package files 44.5 kB 44.5 kB 0 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 29.4 ms 29.7 ms +0.2 ms
CLI --help 82.3 ms 81.7 ms -0.5 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/session-snapshot.js +3.7 kB +1.2 kB
dist/src/snapshot.js -2.5 kB -772 B
dist/src/runtime.js +4 B +7 B
dist/src/session2.js +4 B +5 B
dist/src/internal/daemon.js 0 B +2 B

Top changed packed files

Packed file Base Current Diff
dist/src/session-snapshot.js 34.1 kB 37.8 kB +3.7 kB
dist/src/snapshot.js 31.8 kB 29.2 kB -2.5 kB
dist/src/snapshot-private-evidence.js 0 B 425 B +425 B
dist/src/snapshot-clickability.js 164 B 0 B -164 B
dist/src/snapshot-chrome.js 7.9 kB 8.0 kB +124 B
dist/src/sdk-selectors.d.ts 28.6 kB 28.6 kB -8 B
dist/src/android.js 16.9 kB 16.9 kB +4 B
dist/src/device-claim-conflict.js 87.8 kB 87.8 kB +4 B
dist/src/runtime.js 64.2 kB 64.2 kB +4 B
dist/src/session2.js 233.2 kB 233.2 kB +4 B

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://callstack.github.io/agent-device/pr-preview/pr-1981/

Built to branch gh-pages at 2026-08-24 10:16 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@thymikee thymikee changed the title fix(android): unify snapshot occlusion across API levels fix(android): publish covered state from exact order evidence Aug 23, 2026
@thymikee

Copy link
Copy Markdown
Member Author

Not ready at 91281d2c:

  1. The migration drops the old classifier’s multi-rect union semantics. android-replacement-surface-occlusion.ts reduces a covering subtree to one strongestPaint rect, whereas the prior owner measured the union of every paint rect. Two higher-order actionable descendants can collectively cover a stale surface >=90% while each alone covers <90%, leaving the stale action hittable. Restore bounded union coverage and add a planted regression for collective descendant coverage.
  2. Coverage is deterministically red: the test-file-size ratchet reports growth in src/platforms/android/__tests__/snapshot.test.ts (1495→1542) and src/daemon/handlers/__tests__/session-replay-divergence.test.ts (1215→1218). Move the new scoped evidence/publication case to a focused sibling test owner and avoid growing the replay aggregation.
  3. Before readiness, attach the Android native-a11y → snapshot: conform to the acquire/present engine contracts (sibling of #1797) #1832-required 33-screen true-positive corpus/consumer inventory and live Pixel evidence for this changed path. Current fixture evidence is insufficient for removing the platform pruner.

The private evidence route and size impact otherwise look sound.

@thymikee
thymikee force-pushed the fix/android-occlusion-single-owner branch from 91281d2 to 4275009 Compare August 24, 2026 10:15
@thymikee

Copy link
Copy Markdown
Member Author

Not ready at 42750091b: the previous union, ratchet, exact-order, API 23, and Pixel-evidence findings are resolved, but two shipped consumers still bypass the sole-owner occlusion publication. android-system-dialog.ts rebuilds { nodes, backend } from snapshotAndroid, dropping the private WeakMap sidecar before buildSnapshotState, so covered replacement actions are never classified there. platforms/android/alert.ts passes raw pre-publication nodes directly to findAndroidAlertCandidate, losing the retired platform prune without gaining daemon classification. Route both through an evidence-preserving publication seam (or explicitly prove/remove their dependency) and add regressions that fail when the sidecar is dropped. The red iOS smoke is unrelated to this Android diff and also fails on current main; it is not this blocker.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant