feat(app): Plan, Referral and Feedback back on the Settings sheet; one visual-audit tool
Plan, Referral and Feedback back on the Settings sheet; Permissions under Device; one visual-audit tool
1. Settings follow-up (David, 2026-09-24)
- Plan & Usage (still shows Pro on paid plans) and Referral Program (still tagged New) are their
own rows on the first page of the Settings sheet again. They are no longer on Account. - Feedback / Bug is its own row on the sheet, next to Help & About, and still only where Intercom is supported.
It is no longer on Help & About. - Permissions moved from Data & Privacy to Device (after Phone Calls). It appears in one place only, and
search still finds it and opens Device. - Developer Settings stays last.
The top level now reads: Account · Plan & Usage · Referral Program · Device · Recording & Transcription ·
Notifications & Display · Integrations · Data & Privacy · Help & About · Feedback · Developer Settings.
The sheet shows five visual groups: [Account] [Plan & Usage, Referral] [Device … Data & Privacy]
[Help & About, Feedback] [Developer Settings].
Mapping (changes since #18618)
Depth is the number of taps from the open Settings sheet until the row is visible (0 = on the sheet).
test/widgets/settings/settings_structure_test.dart pumps the real sheet, walks every page and pins every row
below plus the unchanged rows from #18618.
| Row | #18618 location | New location | Depth, #18618 → now (before #18618) |
|---|---|---|---|
| Plan & Usage (Pro value) | Account | Sheet, 2nd group | 1 → 0 (0) |
| Referral Program (New tag) | Account | Sheet, 2nd group | 1 → 0 (0) |
| Feedback / Bug (Intercom only) | Help & About | Sheet, next to Help & About | 1 → 0 (0) |
| Permissions | Data & Privacy | Device, after Phone Calls | 1 → 1 (0) |
| All other rows | unchanged from #18618 | unchanged | unchanged |
Pages now hold:
- Account: Name, Email, User ID · Sign Out, Delete Account.
- Device: Device Settings (while connected), Offline Sync, Phone Calls, Permissions.
- Data & Privacy: Data Protection, Memories, Export All Data, Import Data.
- Help & About: Help Center (Intercom only), What's New, version.
Search, routes and analytics:
settings_search_index.dartpoints Plan, Referral and Feedback at the sheet and Permissions at Device. The index
test checks that each entry's row file draws its title.- Routes and deep links are unchanged, and analytics events and names are unchanged.
- The sheet rows keep their
settings_row_<destination>keys;app/e2e/SKILL.md's settings map is updated. - No l10n change.
2. One maintained visual-audit tool
This week's before/after screenshots came from 16 throwaway copies of a capture harness. They are now one tool:
app/scripts/visual_audit.sh --base <rev> --head <rev> [--only id,id] [--out DIR]
app/scripts/visual_audit.sh --list
-
Harness and registry.
app/integration_test/visual_audit/harness.dartis the harness:- real fonts from FontManifest plus Roboto from the pinned SDK, and
buildOmiTheme(); - 390×844 logical px at 2× through a RepaintBoundary, with adaptive full-scroll capture;
- HTTP allowed only to loopback, against the hermetic fixture backend;
- output directory from
OMI_AUDIT_OUTPUT.
registry.dartandscenarios/<area>.darthold 63 scenarios. Each has an id, a title, the page it
pumps and the seeded state. They are this week's variants plus the original harness, minus the per-round hacks. - real fonts from FontManifest plus Roboto from the pinned SDK, and
-
Command.
app/scripts/visual_audit.shchecks out each revision in a temporary detached worktree (under
$OMI_WORKTREES, or the temp dir by default) and prepares it the way CI does. It copies one snapshot of the
harness over both sides, captures, and then removes the worktrees. It writes:before/andafter/PNGs;INDEX.mdwith both SHAs and the capture times;- a static
gallery.html.
The output directory must be empty and outside the repo; screenshots are never committed. A scenario that throws
on one side is marked failed there, and the other scenarios still capture. -
CI smoke test.
app/test/visual_audit/visual_audit_smoke_test.dartruns in the ordinaryapp/test.shsuite.
It renders every registered scenario without writing images (about 70 s locally, alongside the rest of the suite) and checks that ids are unique
and well formed. -
Docs.
app/e2e/SKILL.mdhas a new section, "Visual audit (before/after screenshots without a device)". It
covers when to use the tool rather than agent-flutter or flow-walker, how to run it and how to add a scenario. -
The old
capture.shandREADME.mdare removed; the section above replaces them.
Screenshots (dogfood: produced by the command above)
app/scripts/visual_audit.sh --base 4ec7cb461b --head 8cab0e011c --only settings-sheet,settings-account,settings-device,settings-privacy,settings-help,settings-search
- Before: main
4ec7cb461b, captured 16:59:44–17:00:08 UTC (Sep 24). - After: this PR at
8cab0e011c, captured 17:00:36–17:01:00 UTC. - The run took 6 min 18 s end to end, and the temporary worktrees were removed.
The gallery has a new top section with the Settings sheet, Account, Device, Data & Privacy, Help & About and search:
https://claude.ai/artifact/GTzdUJ5hfwXLcFZse6Eq7v. The INDEX.md for that run records both SHAs and the capture times.
Verification (hermetic, on this Mac, Flutter 3.44.5, TZ=UTC)
bash app/test.sh: 3017 tests passed, including the smoke test's 63 scenarios; about 4 min wall time.- Analyzer ratchet passes, and
dart analyzeon the new files is clean. - These checks pass:
l10n.py check(49 locales);- INV-UI-3 and INV-UI-1;
- line-count ratchet;
- dead-code (flutter);
- app addressability;
- event registry;
- mobile changelog;
- agent doc references and claims.
- The helper's full capture of all 63 scenarios wrote 99 PNGs with no failures.
Also fixed
- In debug and profile builds, the start-up failure screen printed a literal
nullwhen there was no stack trace.
It now shows only the error. Test:test/unit/startup_failure_app_test.dart. Release builds never showed the
stack.
Product invariants affected
- INV-UI-1: no purple added.
- INV-UI-3: the touched files stay within the mobile UX contract ratchet.
Failure class (fixes)
Failure-Class: none
🤖 Generated with Claude Code