88 lines
4.6 KiB
Markdown
88 lines
4.6 KiB
Markdown
# 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.
|