Skip to content

Warm ledger verification

Scope: the W10 acceptance record, amended with the shipped W11/W12/W13 dispositions and the W14 manual/device evidence for the Warm ledger UI review (#369, #392/#393). It records the pinned executable and later evidence heads, automated and manual evidence, the qualitative Material 3 audit, and every remaining limitation. It does not claim a signed Play release; #41 still owns that gate.

The code contract is ADR-0079; the screen/component descriptions are in ui.md; the contribution workflow is design-contribution.md.

Pinned candidate

Item Value
Source commit 49153ee1bbe0a44a5d557664bf21525e74b287c2 (main after W09 18fa308 and #400 8b08a15, release 0.22.1)
Branch reviewed ui-review/w10-final-evidence
Executable debug APK from that commit, sha256 19224996bb769f063cda7cf5e7b20019ea14aec983d3ebadee189a0f32126c81
Screenshot build same debug APK installed on the pinned docs-shots AVD
Manual/device build same debug APK on docs-shots (API 36); release behaviour is covered separately by the release smoke below

The documentation and screenshot commits that followed the W10 executable were docs-only at that point; the later W11 and W12 code commits are recorded in the amendment below, not folded into this historical candidate. Screenshots are debug-build captures with the deterministic DEBUG_SEED fixture, not release screenshots. Release builds never include the fixture receiver or the component gallery.

W14 acceptance candidate

W14 re-ran the remaining manual/device cases after the W13/#407 merge. It uses one executable and two device profiles; the automated gate logs are the W13 run at the same code tree.

Item Value
Source commit 40120ace6110a78aff72bf80c62aff76c2ec9fb0 (W13 #407 merged via #410)
Debug APK aa4cb8e66c56b08852dc268c7c06cad98724be5259d1637704cf8592fb7b7109 from ./gradlew assembleDebug (exit 0)
Phone device docs-shots, pixel_7, API 36, 1080×2400 @ 420 dpi (411×914 dp); TalkBack 16.0.0.738667889; debug.force_rtl=1 retained from W11
Foldable device w14-fold, Pixel 9 Pro Fold profile, API 36 google_apis x86_64; inner 2076×2152 @ 390 dpi, cover 1080×2424 @ 390 dpi; posture list CLOSED/HALF_OPENED/OPENED
Evidence /tmp/opencode/w14-evidence/ (run-local; not committed binaries)

w14-fold was created from the installed SDK for this run: avdmanager create avd -n w14-fold -k "system-images;android-36;google_apis;x86_64" -d pixel_9_pro_fold. git diff b0cf303 40120ac is CHANGELOG.md only, so the retained W13 gate logs exercise the same code and tests as the merged commit. All manual UI actions used the T3 device_open agent-device command; adb was used only for installs, logs, settings, display dumps and the TalkBack reboot.

W11/W12/W13/W14 amendment

The candidate table and gate log below are the historical W10 record at 49153ee. Later merged/shipped work changed Kotlin, tests and docs after it:

Wave Head Scope Evidence
W11 2917624 #405 signed-money direction (LTR money role in rows, day headers, Home statistics) RtlMoneyPolicyTest, RtlSignedMoneyOrderTest; ADR-0079 amendment
W12 cb5dcd2 (code/test/evidence head; a docs-only evidence commit follows on the PR branch) #406 measured whole-token Home statistics, measured section action and FAB-column clearance, plus the CI 320x640 viewport harness fix HomeStatLayoutTest, HomeHeroCardTest, HomeLargeTextRegressionTest, SectionHeaderTest, ShellChromeTest; ADR-0088
W13 40120ac (PR #410, merged 2026-11-03; branch head b0cf303) #407 measured 320x640 reset click delivery and repaired the three viewport assumptions in the existing editor/reset tests (test-only; production reset and picker code unchanged) TransactionsContentTest#filteredEmptyOffersResetThatClearsQueryAndFiltersTogether, TransactionDetailScreenTest#dateFieldAnnouncesTheValueOnceAndNamesTheChangeAction, TransactionDetailScreenTest#datePickerOpensOnTheLoadedTransactionDate
W14 evidence head 40120ac (no code change) #393 manual/device matrix: actual foldable postures, measured cutout geometry including the lock screen, TalkBack re-bind and speech attempt docs/quality/warm-ledger-verification.md manual matrix; /tmp/opencode/w14-evidence/

The W12 local gate log is retained in /tmp/opencode/w12-evidence for this run (run-local review artifacts, not committed binaries): the JVM/coverage/lint/ ktlint rerun and first-run flake note, docs/ui/supply-chain/QA-driver guard logs, the native API 36 XML (938 cases, 0 failures), the forced 320x640 API 36 XML (935 pass; only the three documented W08/W09/#407 editor-baseline cases fail), the API 26 smoke XML (15 cases, 0 failures), the release smoke log/PNG/crash log and the API 36 E2E journey/extras logs and captures.

CI at 9df87b0 failed 10 viewport-coordinate cases at 320x640/mdpi (8 Home shell-containment, 2 SectionHeader clearance). The fix keeps the logical 411x914/320x568/411x500 viewports but scales the simulation density so they fit the real physical px window, asserts the simulated viewport maps inside the physical px bounds and that the root keeps its requested logical size, and derives SectionHeader end/start expectations from the measured header root. Focused red/green at 320x640 and native 411 is 14/14; the native 411 full suite is 938/0. The forced local 320x640 full run leaves exactly the pre-existing editor-baseline cases (#407: date field, date picker, filtered reset); those are outside this change and are not among the 10 targeted failures. CI remains the authoritative 320 lane.

W13 (#407) classified the three pre-existing editor-baseline failures with measured evidence instead of asserting they were harmless:

  • Two different 320x640 configurations exist. CI creates AVD test with no hardware profile (320x640 px at 160 dpi; status bar 24 px + navigation bar 24 px). The local reproduction used wm size 320x640 && wm density 160 on the Pixel 9 Pro AVD, which keeps that profile's 52 px status bar and 24 px navigation bar — 28 dp less content height. The original three tests pass 3/3 on a locally created bare 320x640 profile (matching CI's 938/0 artifact) and fail 3/3 under the stricter Pixel override, so the override is a stress viewport rather than a CI clone. Both were made green.
  • filteredEmptyOffersResetThatClearsQueryAndFiltersTogether renders the real TransactionsContent at a 320x640 dp root. After performTextInput("xyz") the recovery column is taller than its result area, so Reset filters measured y 642..682 in a 640 dp root: clipped to zero bounds. The test's performClick() injected at that off-window point, the event was dropped, and the callbacks stayed query="xyz", direction=null, category=1. Invoking the button's SemanticsActions.OnClick from a fresh state, or dismissing the keyboard and scrolling first, cleared all three together, so the production reset was correct and the failure was the test's unstated "the action is on screen" assumption.
  • The two date tests place the editor in a 411 dp-wide box that the 320 dp parent coerces to the window width, and assumed the Date & time row was visible. At 320x640 the row measured y 573..637 below the editor body's scroll viewport (the Save footer is a sibling, not an overlay), so assertIsDisplayed failed and the tap never reached the field (the date-picker test then looked for a dialog that never opened). Scrolling the real editor to the row (y 488..552) restores both the announcement assertion and the picker OK path (OK at x 276..334, partially clipped but clickable).
  • The fix is test-only: dismiss the search keyboard where it is up, scroll the existing scrollable owner before acting, and keep every behavioural assertion, including "query AND filters clear together" plus newly asserted chip visibility before and after the tap; no production state, control or layout changed.

The current tree declares 1395 JVM test declarations and 760 instrumented test declarations at the time of this amendment. The first local JVM run at 5bc4d65 hit one unrelated flake in TransactionDetailDraftRecoveryTest.delete_cleansNewlyStagedFilesAndReleasesReservations; it passed alone and the full JVM/coverage/lint/ktlint rerun was green with no source change. The W10 table's 1388/899 counts describe that historical candidate only. Local API 37 remains under the standing before-app-assertion infrastructure exception; CI API 37 is mandatory.

Automated evidence

All commands below were run locally at the pinned candidate unless noted. Logs, JUnit XML and captures are retained in /tmp/opencode/w10-evidence/.

Gate Command Result
JVM + coverage + lint + ktlint cd android-app && ./gradlew test jacocoTestDebugUnitTestReport jacocoTestDebugUnitTestCoverage lint ktlintCheck 1388 tests, 0 failures, 0 errors, 0 skipped; line coverage 45.83 % (4204/9174); BUILD SUCCESSFUL
UI guard bash scripts/ui-guard.sh passes all rules and self-tests
Architecture guard bash scripts/arch-guard.sh passes
Docs guard bash scripts/docs-guard.sh passes links, paths, budgets, ADR parity, index/nav parity (124 Markdown files), version claims and count parity (62 production rules, 1388 JVM tests, 744 instrumented tests)
CI contract guards test-ci-hygiene.sh, test-ci-smoke-matrix.sh, test-workflow-paths.sh, test-lint-config.sh pass
Site build uvx zensical build (0.0.74) Build finished, no issues
Full instrumented, API 36 ANDROID_SERIAL=emulator-5554 ./gradlew connectedDebugAndroidTest 899 tests, 0 failures, 0 errors, 0 skipped; BUILD SUCCESSFUL in 18m29s
Minimum API smoke, API 26 the four CI-critical classes from android-tests.yml 15 tests, 0 failures, 0 errors, 0 skipped (emulator-5556, Android 8.0)
Release smoke ANDROID_SERIAL=emulator-5558 bash scripts/release-smoke.sh assembleReleaseLocal R8 APK installed, launched, topResumedActivity and no FATAL EXCEPTION (debug-key signed); evidence release-smoke.png, release-crash.log
End-to-end QA journeys python3 scripts/android_ui_qa.py onboarding/seed/journey/extras on API 36 pass; onboarding/seed/journey/extras reached journey-complete, extras-complete, capture dedupe and the PIN lifecycle; 66 settled captures retained
Focused W08/W09 editor baseline 3 original editor tests at native size and forced 320x640/160 dpi native 3/3 pass; forced 3/3 fail (date row/OK viewport assumptions; filtered reset tracked as #407) — see below; all three are green at both sizes after the W13 test-only repair

Local API 37 is governed by the standing policy: it may be skipped only when the pinned image fails before app assertions, with the exact head, image and logs. No API 37 attempt was made at the W12 code head 5bc4d65 or final head 18085df; there is no exact-head attempt to claim. W13 did attempt the smoke subset on its branch working tree (based on e04f575, before this evidence commit) and the failure is again before any app assertion: the first install attempt failed and a retry succeeded; two instrumentation runs then produced testRunFailed with INSTRUMENTATION_ABORTED: System has crashed / Instrumentation run failed due to Process crashed and zero executed tests. The emulator exited during the run, and the retained boot log shows cmd: Failure calling service activity: Broken pipe (32) while the system was still starting. The exception rests on the inherited image/host diagnosis:

  • Image system-images;android-37.0;google_apis_playstore;x86_64 (Pixel_9_Pro_API_37, API 37.0), emulator 37.2.13.0 build 16740729.
  • W10 attempt/retry logs: /tmp/opencode/w10-evidence/api37-smoke.log, api37-smoke-retry.log, api37-emulator.log; W11 logs: /tmp/opencode/w11-evidence/api37-smoke-final.log, api37-emulator-final.log.
  • Failure before any app assertion: adb install returned cmd: Can't find service: package/activity; the W11 device then failed to list additional_test_output with Transport endpoint is not connected.
  • The host, SDK image path/version, AVD definition and emulator binary are unchanged from those attempts (Linux alienware 7.3.1-pikaos, image revision 7, API 37.0, emulator 37.2.13.0 build 16740729); W13 installed no new image or toolchain. CI API 37 remains mandatory and validates the exact PR head.

Material 3 audit (qualitative scores)

Scores are a qualitative reading of the shipped code and evidence; they are not pass/fail acceptance and do not replace the manual matrix below. Intentional Warm ledger choices count in the score; the score does not ask the app to adopt stock M3 fonts, radii or a spring-only motion system.

Category Score Status Evidence
Color tokens 9/10 pass Semantic ColorScheme roles, one Warm palette owner in Color.kt, dynamic roles in Roles.kt; measured hero/dynamic pairs in HeroAccentContrastTest, HiddenRowContrastTest, BudgetContrastTest. Raw black/white remain only on the photographic viewer/cropper scrim (allowlisted).
Typography 9/10 pass DM Sans + Newsreader roles in Type.kt, tabular money features, no money truncation; WarmLedgerContractTest and DesignSystemMatrixTest read laid-out text. Deliberate local sizes are documented exceptions.
Shape 9/10 pass Named AppShape meanings over the 4/8/16/20/28 dp scale; fields, amount fields, grouping cards and chips compose one owner.
Elevation 8/10 pass Tonal surfaceContainerLow grouping, one strong hero surface, no decorative shadows. Material dialogs keep their standard tonal elevation.
Components 8/10 pass Material 3 composables plus shared ui/components/ owners; gallery inventory covers every shared control. One documented duplication remains: Activity builds an inline delete dialog instead of reusing TransactionDeleteConfirmDialog.
Layout 8/10 pass Window-size-driven bar/rail, adaptive 1200/600 dp content width, 320 dp and short-height coverage. The 200 % Home hero now measures its labels/amounts into three, two or one whole-token columns and keeps View all clear of the FAB (W12 #406).
Navigation 9/10 pass One NavHost, route table in ui.md, bounded scrolling compact bar and short-height rail with selection reveal, deep-link and back contracts tested.
Motion 9/10 pass One Motion owner, one easing curve, animator-scale-aware transitions, no infinite decorative motion; reduced motion settles at scale 0. Material MotionScheme/Expressive spring APIs are not required by the pinned BOM.
Accessibility 8/10 pass Named merged rows, 48 dp action targets, switch roles, live-region errors and measured contrast. Manual TalkBack focus rendering passed; W14 passed the foldable-posture case on an emulator AVD, while full explore-by-touch traversal and a visibly rendered cutout are still unavailable (recorded below). RTL money ordering is fixed by #405 (W11) and re-asserted in the W12 Home regression.
Theming 9/10 pass Warm static light/dark, opt-in dynamic colour on Android 12+, system/light/dark modes, and a dynamic fallback for every role; verified in both themes and a wallpaper-derived scheme.

Overall qualitative score: 86/100 (sum of the ten rows). The score is intentionally separate from the acceptance disposition: a high score cannot hide a failed or unrun mandatory manual case.

Priority finding dispositions

All twenty-two child findings (#370–#391) have a shipped disposition. The PR column is the merged wave that carried the fix; issue state is GitHub metadata, not evidence of a remaining code gap.

Issue Wave / PR Disposition
#370 W01 / #394 Fixed: password semantics, masked PIN, digit-count state. Closed.
#371 W01 / #394 Fixed: remaining-attempt feedback. Closed.
#372 W02 / #395 Fixed: Save grows with large text. Closed.
#373 W03 / #396 Fixed: hidden rows keep readable roles and a Hidden pill. Closed.
#374 W05 / #398 Fixed: Reports selection survives tooltip/month changes. Closed.
#375 W04 / #397 Fixed: review-card money is detected metadata only. Closed.
#376 W04 / #397 Fixed: debug copy/export hidden in release builds. Closed.
#377 W03 / #396 Fixed: one named switch row per immediate setting. Closed.
#378 W06 / #399 Fixed: invalid remove-limit swipe suppressed. Closed.
#379 W05 / #398 Fixed: no budget marker without a configured limit. Closed.
#380 W02 / #395 Fixed: unified money/status presentation. Closed.
#381 W05 / #398 Fixed: quiet Home supporting surfaces and hierarchy. Closed.
#382 W06 / #399 Fixed: one named budget-card edit/set-limit action. Closed.
#383 W07 / #401 Fixed: read-only attachment opening and failure feedback. Closed.
#384 W07 / #401 Fixed: named viewer controls and typed coordinates. Closed.
#385 W08 / #402 Fixed: month grid, short-height rail and RTL reveal. Closed.
#386 W03 / #396 Fixed: Activity filters, row actions and locale dates. Closed.
#387 W02 / #395 Fixed: editor field shapes and responsive form. Closed.
#388 W08 / #402 Shipped in the merged wave (settings/category width, onboarding viewport, lock insets, hero contrast). The issue stayed open because its closing link did not fire; no code gap found. Recommend closing.
#389 W08 / #402 Shipped in the merged wave (Motion.NAV_REVEAL_MILLIS, density-independent shake). The issue stayed open because its closing link did not fire; no code gap found. Recommend closing.
#390 W09 / #403 Fixed: cross-screen regression matrix. Closed.
#391 W09 / #403 Shipped in the merged wave (existing unfiltered API 36 suite plus summarize-instrumented-results.sh). The issue stayed open because its closing link did not fire; no code gap found. Recommend closing.

New findings raised by this final matrix (not silently absorbed into a closed issue):

Finding Severity Disposition
RTL money sign moves to the logical end (RM 500.00+) in rows, day headers and the hero. Medium (correctness/readability) Fixed — W11 / #405 (merged 2917624): signed money roles pin the authored left-to-right order; RtlMoneyPolicyTest, RtlSignedMoneyOrderTest and the W12 Home regression assert glyph order/structure.
At 200 % text the Home hero stat labels wrap mid-word and the FAB can cover part of View all. Low–Medium (visual) Fixed — W12 / #406: measured whole-token 3/2/1-column reflow, a measured section action that stacks or keeps the shell FAB column clear, and HomeLargeTextRegressionTest bounds/touch/navigation coverage. #393's tracker state must not be read as acceptance: W14 closes the foldable-posture case, but the full TalkBack traversal and rendered-cutout cases remain outstanding.
Original W08/W09 filtered-empty reset fails under forced 320×640. Medium (verification) Fixed — W13 / #407, merged as #410 at 40120ac: measured the recovery action at y 642..682 in a 640 dp root, showed the un-scrolled click is dropped, and repaired the tests (reset: dismiss the keyboard then performScrollTo; date rows: performScrollTo); production reset verified on device. #393 remains unaccepted for full TalkBack traversal and a rendered cutout; W14 adds the foldable-posture pass.

Manual and device acceptance

Device: pinned docs-shots AVD (pixel_7, API 36, build google/sdk_gphone64_x86_64/emu64xa:16/BE2A.250530.026.F3/13894323:userdebug/dev-keys), 1080×2400 px, density 420 (411×914 dp), font scale 1.0, locale en-US, light theme, gesture navigation, TalkBack 16.0.0.738667889 when enabled. Manual actions used the T3 device tools; keyboard injection (where the device command has no key-event primitive) is labelled. W14 added w14-fold (Pixel 9 Pro Fold profile, API 36) for posture and cutout checks; its device metadata, captured frames and a TalkBack log excerpt are in /tmp/opencode/w14-evidence/. Automated tests are listed separately above.

Case Result Evidence and exact limitation
TalkBack focus, speech and traversal Partial (W14 re-check) After a device reboot TalkBack bound (Service[label=TalkBack, feedbackType[FEEDBACK_SPOKEN, FEEDBACK_HAPTIC, FEEDBACK_AUDIBLE]…]) with touchExplorationEnabled=true and serviceHandlesDoubleTap=true; tb-bound-baseline.png shows the green focus ring on launch. A slow injected pan (gesture pan 300 500 0 500 2000) produced two GoogleTTSServiceImpl: Synthesis request for locale eng-USA TTS synthesis requests (talkback-log-excerpt.txt); the log proves synthesis/audio-focus activity, not audible output or the spoken text. A raw coordinate tap at the hero card left the ring on the banner (tb-tap-hero.png is byte-identical to the pre-tap tb-baseline.png), and a small pan over Review activated Review instead of exploring it (tb-pan-review.png). The device tools have no accessibility-focus injection and do not expose the spoken text, so full explore-by-touch/focus/action traversal is still unrun; no full pass is claimed.
Hardware keyboard + IME Next Pass D-pad/Tab focus reached the Budgets tab and Enter opened Budgets; the lock PIN was typed on the hardware keyboard (six dots rendered) and unlocked; the editor's IME Next moved focus from Amount to Merchant.
IME-open editor Pass Keyboard visible (Gboard, number input); Save transaction stayed fully visible above the keyboard and the form scrolled. Capture: ime-open-editor.png.
Display cutout Partial (W14 re-check) The foldable AVD exposes real framework cutouts: inner insets=Rect(0, 136 - 0, 0) with bounding top-right 1940..2076 × 0..136, cover insets=Rect(0, 152 - 0, 0) punch hole 484..596 × 20..152 (/tmp/opencode/w14-evidence/cutout-geometry.txt). App-lock content starts at y=386 (inner) / y=539 (cover), clear of both cutouts (07-open-lock.png, 08-closed-lock.png, JSON snapshots). The emulator framebuffer still does not paint the cutout black, so a rendered-cutout visual remains unverified; the lock still consumes system bars only and does not claim cutout avoidance (ADR-0087/0088).
Short landscape / short-height rail Pass 1280×320 dp (density 160): the rail scrolled to reveal Settings on selection; capture short-landscape-rail-scrolled.png and short-landscape-settings-rail.png.
Large text (200 %) Pass (W12 re-check) 411/320 dp: statistic labels and full amounts stay whole (two columns at 411, one at 320), and View all remains a 48 dp target clear of the FAB. fulltext-home-200.png is the W10 before capture; W12 manual captures and exact-viewport bounds are in the W12 evidence archive and HomeLargeTextRegressionTest.
Dynamic colour Pass (dark captured) Appearance > Dynamic color on, Dark selected: a wallpaper-derived blue scheme rendered on Home (dynamic-dark-home.png); static Warm light was restored afterwards. A dynamic-light capture was not retained; the role/contrast tests cover both dynamic schemes.
RTL Pass (W11 #405) debug.force_rtl=1 originally moved money signs to the logical end; the merged W11 money-direction role keeps +RM 500.00 authored. W12 re-asserts the role and labels/amounts in HomeLargeTextRegressionTest.rtlAtDoubleText...; the API 26 manual device kept an en-US runtime locale, so no new W12 RTL screenshot is claimed.
Reduced motion Pass settings animations off set all three scales to 0; the Activity tab settled immediately; the contract tests pin scale-0 behaviour.
Back / unsaved guard Pass System Back from an edited draft opened the shared Save / Discard / Keep editing dialog (back-unsaved-guard.png); Back from detail returns to the origin route.
Applicable foldable Pass (W14, emulator) w14-fold (Pixel 9 Pro Fold profile, API 36) accepted fold closed, fold half-open and fold open with hinge 0°/90°/180° and device states CLOSED/HALF_OPENED/OPENED (posture.log). Open (2076×2152) uses the rail and wide column; half-open keeps Home/Activity/Settings usable across the hinge plane (one blank frame during the window relaunch, no crash); closed (1080×2424) uses the bottom bar. 03-halfopen-home.png is the blank relaunch frame and 03-halfopen-home-retry.png is the settled capture described above. Captures 01-open-home.png…05-halfopen-settings.png; 06-open-settings.png is byte-identical to 05 because OPEN and HALF_OPENED use the same 2076×2152 window on this AVD, so it is not independent posture evidence. posture.log is a replay of the same pose sequence recorded after the captures (the 1080×2424 vs 2076×2152 frame sizes corroborate it). Limitation: emulator posture only; the app has no FoldingFeature/WindowLayoutInfo use, so hinge avoidance is not claimed.
External viewer opens Pass A saved text attachment opened in the system HTMLViewerActivity with the exact read-only content (external-viewer-html.png); Chrome's first-run setup was not a valid viewer path and was not counted.
External viewer return lock Pass Back from the viewer landed on the PIN lock screen (return-lock-from-htmlviewer.png); the PIN was then entered with the hardware keyboard.
Four-direction pan clamps Pass In-app receipt viewer at 225 %: right, left, up and down each reached its bound and disabled that control while the opposite direction stayed enabled. Captures viewer-pan-{right,left,up,down}-clamp.png.

W08/W09 320 dp editor baseline

W09 recorded three temporary transaction-editor failures under a forced 320×640 / 160 dpi display override. This pass reproduces the original three methods, not an unrelated sibling test:

  • Tests: TransactionDetailScreenTest#dateFieldAnnouncesTheValueOnceAndNamesTheChangeAction, TransactionDetailScreenTest#datePickerOpensOnTheLoadedTransactionDate, TransactionsContentTest#filteredEmptyOffersResetThatClearsQueryAndFiltersTogether.
  • Native baseline on API 36: 3 tests, 0 failures (all three pass; retained XML editor-320-original-native.xml).
  • Forced 320×640 / 160 dpi: 3 tests, 3 failures, 0 skipped (retained XML editor-320-original-override.xml). The date row failed assertIsDisplayed; the date picker failed to find its OK node; the original filtered-reset case failed with expected:<[]> but was:<[xyz]> — the query remained after Reset filters.
  • Manual check at the same 320×640 viewport: the Date & time row is reachable after one scroll, the date picker opens, and OK is visible at the bottom (date-picker-320.png). That supports a test-viewport explanation for the two date cases only.

W13 disposition (#407). The filtered-reset case was measured, not assumed: under the Pixel-profile 320×640 override the recovery action row measured y 642..682 in a 640 dp root, so the test's un-scrolled click was injected outside the window and dropped; the callbacks stayed query="xyz", direction=null, category=1. Invoking the button's semantics action from a fresh state, or dismissing the keyboard and scrolling first, cleared query and both filters. The same original tests pass 3/3 on a bare 320×640/160 dpi AVD profile (status bar 24 + navigation bar 24), which is what CI boots; the Pixel override is 28 dp shorter and is the stricter reproduction. A manual 320×640 journey on a seeded API 36 device reproduced the filtered-empty screen (query xyz, Expenses + Food chips) and its small scrollable recovery viewport, scrolled to Reset filters, and the tap restored the 14-row month with the query and both chips gone. The date row likewise sits below the editor body's scroll viewport until scrolled. W13 repairs the three tests only (the reset test dismisses the search keyboard and scrolls; the date tests scroll the editor body; every behavioural assertion is kept); production reset/picker code, layout, routes and money are unchanged. W13 gate results on the branch based on e04f575: JVM 1395/0 with lint/ktlint/coverage green, full API 36 938/0 at native 411x914, 938/0 on a bare CI-profile 320x640 AVD, and 938/0 at forced Pixel-profile 320x640, API 26 smoke 15/0, release smoke pass, and E2E seed/journey/extras pass. The repair is merged as

410 at 40120ac; the retained W13 logs are in /tmp/opencode/w13-evidence/.

W14 is the evidence-only follow-up and leaves #393 open for the two remaining manual cases.

Screenshots and fixture metadata

Regenerated with the repository tooling:

bash scripts/generate_screenshots.sh

It built assembleDebug, booted the pinned docs-shots AVD (pixel_7, API 36, 1080×2400, 420 dpi → 411×914 dp, font 1.0, en-US, light, gesture navigation), cleared only the debug package, launched the app, broadcast DEBUG_SEED, entered SysUI demo mode and captured the 11 routes. The run finished with done: 11 PNGs; each capture waited for a rendered, settled frame.

File sha256
budgets.png 22787ade5834f506283644ec1bebdc5a7c64d918b492b27eed5e745893eed406
home.png a58b7cfc6b5bda2630ce2500641fe173a291b03f458b52742530574032a9cd89
onboarding.png 56917afc97a9470d60dfa225988b4298bc1959142f757710f750ef8ba2d21977
reports.png af8a239eafd0dbba8f2af40e4f8c4749cd30636b913334d37cc0a6b78802193b
review-queue.png 3401f71d49827d80c68804c9ff4e46549fc7855564104c0ddcc0265046e6b8d0
security.png 8b7ccd6d3369e39a7dde39da40e5bc207709e482b2df27ad679d9ce7c95ec1c8
settings.png d8f82fbbed90916e40c1b7d1ca65830ab8f287e65539fd6a0ac18042b66fffb9
transaction-detail.png 5a01d7ff91a612034f1d8121b493c7158a61f7ff82a39cc22487395d09f5695f
transactions.png 9032c33a85be607439851e26e0a795d8f10cf0569c50d27513180d1128093538
troubleshooting.png 3eebc1e5b6e9439ca8c6918f0f9532cb0eaa5292706040add7c75531e5645de4
unsaved-changes.png 330df79c1dc5feb3aef4512163e90010ebdcf888a01ff45872169054304e6de1

The images are debug, seeded captures: home, transactions, budgets and reports use the demo month; review-queue is the fixed two-row sample. unsaved-changes and transaction-detail contain a focused text field, so their pixels are not byte-stable between runs. Recordings were not regenerated; the tour clips remain historical until the recording workflow runs on a host with ffmpeg and the pinned AVD.

Remaining limitations and #41 handoff

  • #393 is not accepted by this pass. W14 closed the foldable-posture gap on an actual foldable AVD, measured the real cutout geometry (including the lock screen) and re-bound TalkBack with observed TTS synthesis requests; the remaining mandatory gaps are a full TalkBack explore-by-touch/focus/action traversal and a visually rendered cutout. #393 therefore stays open for those two items and the #41 handoff must not treat it as accepted.
  • RTL money signs were fixed by W11 (2917624, #405); the W12 Home regression re-asserts the money role.
  • 200 % Home was fixed by W12 (#406): whole-token statistic columns and a FAB-safe View all action. The full TalkBack traversal and rendered-cutout cases still block #393 acceptance.
  • 320 dp filtered reset (#407) was fixed by W13 as a test-harness defect and merged as #410 at 40120ac: the three affected tests now scroll their existing scrollable owner before acting at 320×640, with every behaviour assertion retained. Production reset, date-picker and editor code did not change.
  • TalkBack: W14 rebound the service after a reboot and observed touchExplorationEnabled=true, a launch focus ring and real en-US TTS synthesis from a slow injected pan; injected taps still did not drive a reproducible explore-by-touch focus sequence and the spoken text is not exposed by the device tools. A human/physical-device traversal remains the gate.
  • Cutout / foldable: W14 passed the foldable posture cases on w14-fold (CLOSED/HALF_OPENED/OPENED; rail vs bottom bar; lock captured). The cutout remains partial: the foldable's framework cutout is real and the lock content clears it, but the emulator framebuffer does not paint the notch, so a rendered-cutout visual needs a physical device.
  • Release: the release smoke proves the minified APK installs, launches, resumes and does not crash; it does not prove signed-Play, 16 KB, pre-launch, soak or production gates. Those remain #41's scope.