| Background work | WorkManager 2.11.2 | reminders must survive process death; **no exact-alarm permission** — a period reminder does not need alarm-clock precision |
| DI | Hilt 2.60.1 | wired at the skeleton stage; retrofitting DI across modules later is the expensive order |
| Prediction engine | pure Kotlin JVM module | testable without an emulator, which is the only way it gets the test coverage §50 asks for |
| Target | `compileSdk`/`targetSdk` 36, `minSdk` 26 | Play requires API 36 for new apps and updates from **2026-08-31** |
## Success looks like
Observable, from [`PRODUCT_PLAN.md` §60](PRODUCT_PLAN.md) — the primary metrics
are about the forecast, not about engagement:
- mean absolute next-period prediction error, falling as confirmed cycles accrue
- share of predictions within ±1 and ±2 days
- measurable accuracy improvement at 3, 6 and 12 confirmed cycles
- a user with a stable 35-day cycle is never predicted at 28
And one qualitative test that decides the rest: **a first-time user enters their
last period and immediately sees a forecast they believe.**
Deliberately not optimised for: time in app, ads viewed, feed engagement. A good
period tracker helps in seconds and gets out of the way.
## Known risks
Written now, while it is still cheap to be honest.
| Risk | What it would look like | What is done about it |
| --- | --- | --- |
| The engine falls back to a global average | a 35-day user predicted at 28 — the specification calls this a core product defect | the acceptance tests in §51 are written before the engine, and run in a module with no Android dependency so they always run |
| Confidence becomes decoration | "High" shown because there is a lot of data rather than because the data agrees | confidence is derived from variability and historical error, and §15's two worked examples are test cases |
| Health data leaks into ad requests | a cycle-state string in an ad extra, or an ads SDK initialised with user properties | a module-boundary guard: `ads` may not depend on the cycle database or the prediction domain, and the guard is proved to fail before it is trusted |
| A notification exposes cycle state on a lock screen | Discreet mode showing the private text publicly | notification privacy modes are a QA pass of their own, tested at every mode |
| Play health-app policy changes before launch | a submission rejected on Data Safety or a medical-claim reading | policy verified immediately before submission, never from memory; the target API deadline is already in the table above |
| A keystore or Play service-account JSON gets committed | a signing key in the history, which deleting the file does not undo | `scripts/secrets.sh` runs before every commit; `local.properties`, `*.jks` and `*.keystore` are ignored from the first commit |