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
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.
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.
thymikee
changed the title
fix(android): unify snapshot occlusion across API levels
fix(android): publish covered state from exact order evidence
Aug 23, 2026
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.
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.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Centralize Android covered-state publication without guessing z-order.
buildSnapshotStatethe sole owner of daemon-onlyinteractionBlocked: "covered"publication.androidSnapshot.occlusionScanUnavailable: trueand publishes no covered verdict.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
pnpm check:affected --runon Node 24: all runnable checks passed, including 556 related test files / 4,484 tests.snapshot.test.tsis 1,495 lines;session-replay-divergence.test.tsis reduced to 1,137 lines, with the new cases in focused sibling owners.Pixel_9_Pro_XL: a lower actionable 1128x720 sibling covered by two exact-higher-order actionable 1128x360 descendants remained present but publishedhittable: false,interactionBlocked: "covered", andpresentationHints: ["covered"]; the two foreground actions remained hittable, and no sibling/order evidence leaked publicly.