Skip to content

feat(android): bound snapshot presentation quality - #1972

Open
thymikee wants to merge 4 commits into
fix/android-snapshot-engine-contractsfrom
fix/android-snapshot-quality-contracts
Open

feat(android): bound snapshot presentation quality#1972
thymikee wants to merge 4 commits into
fix/android-snapshot-engine-contractsfrom
fix/android-snapshot-quality-contracts

Conversation

@thymikee

@thymikee thymikee commented Aug 22, 2026

Copy link
Copy Markdown
Member

Summary

Bound Android snapshot presentation with one typed work/time budget, including scope selection and reindexing, and return a typed presentation-failed sparse result when the budget is exhausted.

The scope path now uses a single document-order pass plus bottom-up subtree collection. It no longer rescans a subtree for every scope candidate, so hostile nested trees remain linear while every traversal and reindex operation is charged to the same owner budget.

This completes #1832 C5 and C6. C4/C1 ownership remains in #1968; drawing-order pruning is unchanged.

Validation

A hostile nested-scope regression proves the same tree succeeds unscoped but is refused with the typed complexity/presentation failure when scoped work exceeds its budget. Existing equal-order, one-axis, dialog, quality-verdict, and latch cases remain green.

Exact-head pnpm check:affected --run passed at d6cd3d1: 632 files / 5,027 tests plus format, lint, typecheck, layering, fallow, and build.

The complete stack was exercised live at c772c16. Android Settings produced a healthy android-helper 0.20.10 capture across two windows in 142 ms, with the nested scroll hierarchy intact. The verification session was closed.

19 files changed, +930/-106 against #1968. The stack through this PR is 23 files, +1,683/-441 against main. Scope stayed within Android snapshot presentation/quality and its contracts. CI on this published head is authoritative before merge.

@github-actions

github-actions Bot commented Aug 22, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
JS raw 2.37 MB 2.37 MB +3.6 kB
JS gzip 795.6 kB 796.4 kB +869 B
npm tarball 917.4 kB 918.2 kB +735 B
npm unpacked 3.18 MB 3.18 MB +3.7 kB

npm unpacked components

Component Base Current Diff
JS / dist source 2.52 MB 2.52 MB +3.7 kB
Apple runner source/project 564.2 kB 564.2 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 26.1 ms 26.3 ms +0.2 ms
CLI --help 77.8 ms 78.0 ms +0.2 ms

Top changed chunks:

Chunk Raw diff Gzip diff
dist/src/src2.js +48.7 kB +14.6 kB
dist/src/snapshot.js +3.6 kB +1.1 kB
dist/src/runtime.js +253 B +103 B
dist/src/session2.js -15 B -19 B
dist/src/runtime2.js -7 B -8 B

Top changed packed files

Packed file Base Current Diff
dist/src/src2.js 19.2 kB 48.7 kB +29.5 kB
dist/src/src3.js 48.7 kB 19.2 kB -29.5 kB
dist/src/snapshot.js 27.6 kB 31.2 kB +3.6 kB
dist/src/apple-multitouch-support.js 982 B 0 B -982 B
dist/src/interactor-types.js 245 B 1.2 kB +974 B
dist/src/android-snapshot-quality.js 422 B 0 B -422 B
dist/src/runtime.js 63.9 kB 64.2 kB +253 B
dist/src/audio-probe-support.js 236 B 0 B -236 B
dist/src/verdict.js 1.9 kB 2.1 kB +195 B
dist/src/snapshot-clickability.js 0 B 164 B +164 B

@thymikee

Copy link
Copy Markdown
Member Author

Not ready at 34bed0fa2:

  1. Exact-head Coverage deterministically fails because src/platforms/android/__tests__/snapshot.test.ts grew to 1,695 lines over its 1,658-line pin. Extract the relevant test module; do not raise the ratchet.
  2. The claimed linear hostile-tree gate is vacuous for the known worst case: its 240-deep one-child chain returns before unionCoverage at every level. The real broad-sibling path can allocate Uint8Array((xs.length - 1) * rows) and scan row cells without metering/preflighting that work, so rawNodeCount * 64 does not prove a linear bound or guaranteed typed failure. Add a broad-sibling/descendant-footprint regression observed red without enforcement, then meter/preflight allocation and inner-cell work or replace it with a genuinely bounded algorithm.
  3. CI reports npm unpacked +3.5 kB, crossing the size scrutiny threshold. Itemize the justified growth and record why a smaller design was rejected.

The stack dependency on clean #1968 is valid and Android smoke is green, but it does not exercise this failure/complexity path.

@thymikee
thymikee force-pushed the fix/android-snapshot-quality-contracts branch from 34bed0f to b9b997a Compare August 22, 2026 13:53
@thymikee

Copy link
Copy Markdown
Member Author

Addressed on b9b997a5f.

  • Extracted the two Android quality/deadline tests; snapshot.test.ts is back at the pinned 1,658 lines.
  • Added the broad-sibling/descendant-footprint regression. It was observed red before enforcement: the old counter stayed under 1,024 units while the grid exceeded 2,000 cells.
  • Preflighted compressed-cell allocation and charged fill/scan work through the typed presentation budget, so the case now fails before allocation with phase: complexity.
  • Final local affected gate passed: 635 files and 5,039 tests; provider integration was covered by related tests. Coverage and device lanes remain GitHub-authoritative.
  • The size rationale is now itemized in the PR description: the +3.5 kB unpacked growth is the typed presentation/quality safety contract; message sniffing, backend-name branching, and uncapped coverage would be smaller but violate the issue contracts.

@thymikee

Copy link
Copy Markdown
Member Author

Not ready at b9b997a5. The file-size and size-rationale findings are addressed, and the new footprint allocation preflight is a valid planted-red for that subcase. But the claimed linear gate remains bypassable: isCoveredByHigherDrawingOrderSibling scans all lower/equal covering candidates without charging budget (~N²/2 comparisons for ascending same-rect siblings), and markCells performs four unmetered linear indexOf searches per rect. Meter/preflight those operations or use ordered/indexed structures, and add planted-red broad-candidate/one-axis cases. Current Android Smoke is also an owner-action failure after the changed snapshot route (alert wait times out after readable captures); diagnose it and obtain exact-head green. Finally replace the malformed, pasted-gate-output PR body with concise Markdown and the current size figure.

@thymikee
thymikee force-pushed the fix/android-snapshot-quality-contracts branch from b9b997a to 6943369 Compare August 22, 2026 14:49
@thymikee

Copy link
Copy Markdown
Member Author

Addressed on 6943369b9da57260ae6da71c4e1161e82afdbbb4 (base 52242d7c38bcc292b459b6e7ea24c9db052d68c4 / #1968).

  • Metered every broad candidate comparison and replaced the four per-rect indexOf scans with charged edge indexes.
  • Added planted-red hostile equal-order and one-axis fixtures; both fail with typed phase: complexity when their enforcement charge is removed.
  • Extracted the remaining builder publication seam; the affected gate now passes cleanly: 636 files and 5,043 tests.
  • Diagnosed the Android Smoke artifact: 22 readable captures, then the alert wait timed out; no hierarchy or typed presentation detail was retained. A synthetic native-dialog presentation/alert fixture is green, but no local emulator is available (adb devices is blocked by Operation not permitted), so exact-head Android Smoke remains GitHub-authoritative and no 33-screen corpus is claimed.
  • Replaced the malformed pasted-gate body with concise exact-head/base, size, evidence, and risk details.

@thymikee

Copy link
Copy Markdown
Member Author

C5 does not yet cover the full Android presentation route. In ui-hierarchy-builder.ts, the budgeted/typed try ends before scopePresentedAndroidSnapshot; scoped projection then traverses/reindexes without charging the same deadline/work budget. findAndroidScopeRoot can also rescan a subtree for each matching-but-unpresented candidate, making a hostile scoped tree quadratic and able to escape both the 250 ms deadline and required typed presentation-failed whole-output discard. Pass the same budget through scope/reindexing, keep that phase inside the typed failure boundary, and add a planted-red hostile scoped-tree regression.

The declared base #1968 is also currently conflicting with main, exact-head #1972 has only CodeQL (no required suite/Android Smoke), and the PR body’s ‘5 files, +190/−27’ delta is stale versus GitHub’s 16 files, +826/−72.

@thymikee
thymikee force-pushed the fix/android-snapshot-quality-contracts branch from 6943369 to d6cd3d1 Compare August 22, 2026 16:45
@thymikee

Copy link
Copy Markdown
Member Author

Addressed on d6cd3d1.

  • scope selection and reindexing now share the same typed presentation budget and failure boundary
  • scope discovery uses one document-order pass and bottom-up subtree collection instead of per-candidate rescans
  • added the hostile scoped-tree budget regression
  • exact-head affected gate passed (632 files / 5,027 tests)
  • refreshed the body with exact stack deltas and live full-stack Android evidence

The published branch is mergeable; required CI is running.

@thymikee

Copy link
Copy Markdown
Member Author

Exact-head Android Smoke is an owner-action regression, not infrastructure. The current run resolves and clicks automation-open-alert at (540,1169), then times out after 20 readable helper captures with typed wait_target_absent; the exact #1968 base passed the same API-36 flow and identical coordinate, while #1972's b9b997a5 head failed at this same alert wait after 22 readable captures. A rerun alone is insufficient. Preserve a post-click artifact containing regular nodes, raw window facts, android-helper quality/reasonCode, and presentation failure phase/work units; fix the presentation path if it sparsifies/omits the dialog; then obtain exact-head green Android Smoke through alert get/dismiss/reopen/accept. All other checks are green; do not apply ready-for-human.

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