diff --git a/docs/history/DEVELOPMENT_LOG.md b/docs/history/DEVELOPMENT_LOG.md index 9ff152e..ca734db 100644 --- a/docs/history/DEVELOPMENT_LOG.md +++ b/docs/history/DEVELOPMENT_LOG.md @@ -32,6 +32,71 @@ written and stay true. It is exempt from review for the same reason a receipt is ## Entries +### 2026-08-18 — Batch 05 shipped, and the app got its real brand + +Reminders landed and the milestone closed. **Five of eight batches are done, and +exactly one issue is open in the whole tracker** — #9, the webhook, which needs a +person. + +**Notifications, and the two Android behaviours that leak if you trust the +docs.** `NotificationCopy` is a pure function, so every kind × every mode is +tested exhaustively without an emulator — including the action labels, which §31 +points out are visible text too. A perfectly discreet body under a button +reading "Started my period" leaks anyway. + +Then the device found what the unit tests could not: + +1. **A private notification with no public version does not blank the lock + screen — it shows the private text.** `NotificationText` therefore has no + nullable title, and an instrumented test asserts every kind attaches one. +2. **A notification channel is immutable after creation.** Importance and + lock-screen visibility cannot be changed, so one shared channel would have + kept whatever the user's first privacy mode set, forever. Switching from + Direct to Maximum privacy would have *appeared* to work and changed nothing. + One channel per mode now. + +**A third guard failed its first proof.** `checkPermissions` — new, and worth +having, because adding WorkManager silently brought four permissions that appear +in the Play listing — read a stale merged manifest because it did not depend on +the task that writes one. An injected `SCHEDULE_EXACT_ALARM` went unnoticed. +That is the schema guard, the boundary guard and now the permission guard: three +for three. **Assume a new guard is broken until it has been watched failing.** + +**And a mistake of mine worth keeping.** While proving the pre-commit fix I +committed a throwaway and ran `git reset --hard HEAD~1`, which did not undo the +push the post-commit hook had already made and silently discarded the +uncommitted fix I was mid-proof on. Reconciled forward rather than rewriting +published history. Commit the work before proving the guard. + +**The brand arrived mid-session.** The owner supplied a full visual guide and +artwork, which answers #8 — the three marks an agent must not fake now exist +because a person made them. Converted to the required webp with two things +handled rather than blindly transcoded: the sources render their rounded corners +against black, and the lockup is square so a 3:1 crop would have cut the wordmark +in half. + +The guide **supersedes §39's colour direction**, and one conflict is real: §39 +wants a muted teal fertile window and the guide is plum-and-rose throughout with +a pink for fertility. The guide wins, and it is safe for it to win *because the +calendar's states differ in shape rather than colour* — which is what §43 +actually requires. Written down in `docs/design/README.md` rather than left to be +found. + +- **Closed:** #8, #24, #25, #26, #27 — and the `Batch 05 — Notifications` + milestone. +- **Next action:** Batch 06 — Privacy and Security. File its issues first; the + milestone is empty. The work is biometric and PIN lock, export, irreversible + delete, the privacy promise in Settings, and making §45's logging rules true in + a release build. Much of the groundwork exists — `deleteAllHealthData` is + written and tested, backup is already excluded in the manifest — so this batch + is largely surfacing what the data layer can already do, plus the designed + Settings screen the Batch 05 working surface is standing in for. +- **Blockers:** One issue, and it needs a person: #9, the Command Center webhook. + Until it is registered an opened `P0` raises no alert at all. The QA gaps are + now the more pressing thing: **nobody has looked at an actual lock screen**, + TalkBack has never been run, text has never been scaled, and nothing has run + at `minSdk` 26. All four are cheap and none has ever been done. + ### 2026-08-18 — Batch 04 shipped: fertility that declines, and a hook that refused every deletion Three issues closed and the milestone with them. Four of the eight batches are diff --git a/docs/qa/ClaudeQACoverage.md b/docs/qa/ClaudeQACoverage.md index 72f722d..52b68a8 100644 --- a/docs/qa/ClaudeQACoverage.md +++ b/docs/qa/ClaudeQACoverage.md @@ -13,6 +13,42 @@ Review trigger: Any QA round run > like a pass that succeeded, and that is how untested code ships believing it > was tested. +## Round 3 — 2026-08-18 at `0451fbe`, partial + +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. + ## Round 2 — 2026-08-18 at `19edf4c`, partial Batch 03 built every screen the app has, and each was driven by hand on the @@ -108,6 +144,10 @@ at its own `minSdk`.** 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 lock screen has been looked at.** Pass F's instrumented tests assert the + notification object is built correctly, which is most of the risk and not all + of it. What the system actually draws on a locked device — including heads-up + behaviour and any launcher's own preview — has never been seen by anybody. - **TalkBack has never actually been run.** Content descriptions are written and were checked by reading the view hierarchy, which proves they exist and not that they make sense in sequence. Pass G is not complete until somebody diff --git a/docs/qa/ClaudeReport.md b/docs/qa/ClaudeReport.md index 611c6b5..77e6a25 100644 --- a/docs/qa/ClaudeReport.md +++ b/docs/qa/ClaudeReport.md @@ -19,22 +19,21 @@ Review trigger: Any QA round run ## Current run-state -- **Last QA round:** Round 2 — 2026-08-18, partial (A and B pass; C, D, E, G and H partial; F not applicable yet) -- **Last verified build SHA:** `19edf4c` +- **Last QA round:** Round 3 — 2026-08-18, partial (A and B pass; C, D, E, F, G and H partial) +- **Last verified build SHA:** `0451fbe` - **Last tested device / environment:** emulator `PeriodQA`, API 36, Pixel 6 profile, debug build -- **Overall status:** Three batches are done and the app is now a real product - you can use end to end: onboarding that ends in a forecast, a Today screen - whose six states each say something different and true, two-tap logging, a - calendar whose marks survive greyscale, and an Insights screen that mostly - declines to make claims it has not earned. The prediction engine is the one - §12 specifies and is measurably better than the prototype it replaced. What - the rounds keep showing is that this project's defects are found by opening - the app rather than by reading it — dark mode was broken for an entire batch - with 129 tests green, and the calendar's marks collided in a way only a - greyscale screenshot revealed. The gaps that matter now are the ones nothing - has touched: TalkBack has never been run, text has never been scaled up, and - nothing has run on a device at the minimum Android version this app claims to - support. +- **Overall status:** Five of eight batches are done and the app is a coherent + product: onboarding to a forecast, a Today screen with six honest states, + two-tap logging, a calendar readable in greyscale, insights that decline to + overstate, fertility estimates that refuse to appear when the forecast is too + vague to support them, and discreet reminders. It now wears its real brand, + supplied by the owner. Eight instrumented tests assert that nothing about a + period reaches a lock screen in either private mode — but **nobody has yet + looked at an actual locked screen**, and that last mile is the single most + valuable thing left to check, because a notification read over a shoulder is + the likeliest real privacy failure in this product. The other standing gaps + are of the same kind: TalkBack has never been run, text has never been scaled, + and nothing has run at the minimum Android version this app claims to support. ## Open defects