# Claude QA Coverage — Period ``` Status: Current Owner: _null Last reviewed: 2026-08-18 Governs: what each QA pass actually reached Review trigger: Any QA round run ``` > Pass by pass, what was reached and what was not. The point of this file is the > **Blocked** and **Not run** rows: a pass left out of a report reads exactly > like a pass that succeeded, and that is how untested code ships believing it > was tested. ## Round 1 — 2026-08-18 at `adc5075`, partial Not a full round. Batch 01 produced the first build, and this covered the two passes that build could support. Recorded as partial rather than left out, because a pass omitted from a report reads exactly like a pass that succeeded. **Environment:** emulator `PeriodQA`, API 36 (`sdk_gphone64_x86_64`), Pixel 6 profile, debug build. | Pass | Result | Notes | | --- | --- | --- | | A — First run | **Pass** | Clean install, cold start, empty state reads correctly ("No forecast yet", "No periods logged yet"), all four tabs reachable. No notification permission prompt yet — none is requested until Batch 05. | | B — Core loop | **Pass** | Logged a period; cycle day, countdown, window and confidence appeared. Edited the start date twice; forecast moved from 15 Sep to 13 Sep and the record was marked `edited`. Deletion covered by instrumented test rather than by hand. | | C — Failure paths | **Partial** | Only one path exercised, and it found a crash — see below. Airplane mode, denied permissions and a killed process mid-entry were not tried. | | D — Persistence and migration | **Partial** | Covered by an instrumented test that closes and reopens a file-backed database, which is what a force-stop does. A real force-stop, a reboot and an update-over-install were not tried. | | E — Forecast under hard histories | **Not run** | The §51 cases pass as unit tests; none has been driven through the UI, which is what this pass is for. | | F — Notification privacy on a lock screen | **Not run** | Nothing sends a notification yet — Batch 05. | | G — Accessibility | **Not run** | TalkBack, font scaling and greyscale legibility untried. The working surface is not the designed screen, so this is worth deferring to Batch 03 rather than testing a screen that is about to be replaced. | | H — Data ownership and leakage | **Partial** | Delete-all covered by an instrumented test. Export, app lock and the built-artifact inspection do not exist yet. | ### What pass C found Tapping **Started today** twice on the same day killed the app: ```text FATAL EXCEPTION: main android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: period_records.startDate ``` Not filed as an issue: it was found and fixed inside the same batch, before any build left this repository, and a tracker issue closed by the commit that introduced the code would be bookkeeping rather than a record. It is written down here, in the commit that fixed it, and in [`../architecture/README.md`](../architecture/README.md), with four regression tests pinning the behaviour. The interesting part is not the crash. It is that **the first thing tried by hand broke immediately**, on the app's primary button, with 70 unit tests green — which is the argument for pass C existing at all. ### What lint found, that no pass would have Wiring the boundary guard into `./gradlew check` ran Android lint for the first time, on `f5e9fbe`: ```text NewApi: java.time.LocalDate#ofInstant requires API 34 (minSdk is 26) NewApi: java.time.LocalDate#EPOCH requires API 34 (minSdk is 26) ``` Both on the recalculation path — a crash on every device below Android 14. Invisible to the unit tests and invisible to an API 36 emulator. Fixed, and worth recording as a standing gap below: **this project has no test on a device at its own `minSdk`.** ## Standing gaps Things no round has ever covered, carried forward until they are. This list existing is not a failure; it not existing while the gaps do is. - **No device at `minSdk`.** Everything so far ran on API 36. The two NewApi bugs above would have crashed on Android 8 through 13 and nothing except lint could see them. Lint is a good guard and it is not a substitute for one run on an old API level. - **Physical-device coverage is undecided.** Passes F and G need a real device with a lock screen and TalkBack; which device that is has not been chosen, and an emulator is not a substitute for either. - **Long-horizon accuracy** — whether predictions measurably improve at 3, 6 and 12 confirmed cycles — cannot be reached by a QA round at all. It needs either a simulated history harness or real elapsed time, and until one exists the product's headline claim is tested only at the unit level.