Batches 04 and 05 landed: fertility estimates and the reminder system. Pass F
became runnable for the first time.
**Environment:** emulator `PeriodQA`, API 36, Pixel 6 profile, debug build, plus
8 instrumented tests on the same device.
| Pass | Result | Notes |
| --- | --- | --- |
| A — First run | **Pass** | Re-run after the brand change; onboarding reaches a forecast, relaunch skips it. |
| B — Core loop | **Pass** | Unchanged and re-driven. Fertility appears on Today and the calendar once the forecast is tight enough. |
| C — Failure paths | **Partial** | As Round 2. Airplane mode, denied notification permission and a killed process still untried. |
| D — Persistence | **Partial** | As Round 2. Reboot and update-over-install untried — the second matters more now that WorkManager holds scheduled work. |
| E — Forecast under hard histories | **Partial** | Unit-tested against both engines; the §51 histories still have not been entered by hand. |
| F — Notification privacy | **Partial, and this is the important row** | Eight instrumented tests on a device assert what a lock screen *would* render: every kind × both private modes attaches a public version, is marked `VISIBILITY_PRIVATE`, and leaks no health word — including the action labels. **Nobody has yet looked at an actual locked screen.** That is a real gap: the tests check the notification object, and the last mile is what the system chooses to draw. |
| G — Accessibility | **Partial** | Unchanged. Calendar verified in real greyscale again after the palette change. TalkBack and font scaling still never run. |
| H — Data ownership | **Partial** | Unchanged. |
### What this round found
Two defects, both in how Android behaves rather than in the app's logic, and
both found by running on a device:
1.**A notification channel is immutable after creation.** Importance and
lock-screen visibility cannot be changed once set, so a single shared channel
would have kept whatever the user's first privacy mode chose — switching from
Direct to Maximum privacy would have appeared to work and changed nothing.
One channel per mode now.
2.**`checkPermissions` was green over its own target**, reading a stale merged
manifest because it did not depend on the task that writes one. The third
guard in this project to fail its first proof.
Also confirmed: a seventeen-day "fertile window" was on screen for a user one
cycle in. Arithmetically correct, useless, and only visible by looking.
Batch 03 built every screen the app has, and each was driven by hand on the
emulator as it landed rather than in one pass at the end. Same environment:
`PeriodQA`, API 36, Pixel 6 profile, debug build.
| Pass | Result | Notes |
| --- | --- | --- |
| A — First run | **Pass** | Clean install reaches onboarding; all seven screens walked; the flow produces a forecast and a relaunch goes straight to Today. |
| B — Core loop | **Pass** | Two-tap logging confirmed on the device: "Started period" → "Yes — today" → "Logged ✓". Editing, ending, and spotting reclassification all exercised. |
| C — Failure paths | **Partial** | Duplicate-date logging, an end date before a start, and a future date in the picker all handled. Airplane mode, denied permissions and a process killed mid-write still untried. |
| D — Persistence | **Partial** | Onboarding completion, records and settings all survive force-stop and relaunch. Reboot and update-over-install untried. |
| E — Forecast under hard histories | **Partial** | The §51 cases pass as unit tests against both engines, and the not-yet path was driven through the UI. The variable and outlier histories have still not been entered by hand. |
| F — Notification privacy | **Not run** | Nothing sends a notification yet — Batch 05. The onboarding *choice* was verified: Discreet is selected before the user touches anything. |
| G — Accessibility | **Partial** | Every calendar day, the confidence indicator and the hero countdown carry content descriptions, checked by reading the view hierarchy. **The calendar was verified in actual greyscale** and all five marks remain distinguishable. TalkBack itself, and font scaling, still untried. |
| H — Data ownership | **Partial** | Delete-all covered by an instrumented test. Export, app lock and artifact inspection do not exist yet. |
### What driving it found that tests did not
Three defects, none of which any unit test would have caught:
1.**Dark mode was broken for the whole of Batch 01.**`PeriodTheme` never
wrapped its content in a `Surface`, so text without an explicit colour
inherited black and the app background never painted. Light mode looked
correct by accident.
2.**"Period ended" appeared to do nothing.** The logic was right — a period
ending today still includes today — but the screen was identical afterwards,
so the button read as broken.
3.**Today's underline collided with the spotting dot**, on the one day that was
both. Invisible in the colour screenshot, obvious in greyscale.
The pattern is now four rounds old and worth stating as a rule: **the defects in
this project are found by opening it, not by reading it.**
| 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: