# M7 — Contraceptive Security — Session Card

> **Planning artifact.** A future build session opens this file to know exactly what to build for the Contraceptive Security module, in what order, with what entry dependencies and done criteria. No production code lives here. Read alongside `docs/plan/13-execution-modules-and-sessions.md` (the execution framework), `docs/plan/03-protocol-engines.md` §7 (the engine spec), and `docs/plan/04-backend-togo.md` (schema/migration/plugin rules).

## Purpose

The Contraceptive Security engine tracks contraceptive-method adherence with **per-method state machines**, because a daily pill, a monthly injection, and a long-term implant have fundamentally different schedules and failure modes. Like every Health Debug engine it lives **only** in the ToGO backend (the Single Source of Truth); every client renders server state and submits log intents. The engine is strictly categorical — it branches on *what* the method is, never on hormone dosage or brand pharmacology — and it never states protection status ("you are/aren't protected"): every consequence-shaped question terminates in **"Consult your doctor."** This module ships on **backend, web, mcp, apple, android, desktop** — **no chrome surface** (a browser popup is the wrong place for contraceptive tracking; matches M6 Cycle).

## Engine parameters (exact — from `03-protocol-engines.md` §7 / shared context)

| Parameter | Value | Notes |
|---|---|---|
| Differentiated method types | **daily pills**, **monthly injections**, **implants** | Closed enum: `daily_pill \| monthly_injection \| implant`. The engine's logic branches on the method type (categorical), never on dosage. |
| Per-type schedule / validity rules | **UNDEFINED BY SPEC — OPEN QUESTION** | Pill day-window/grace, injection due-date tolerance, implant validity duration + expiry-reminder lead time are **not** in the spec. Do **not** invent numbers. See Notes & gotchas / `03` §7.2, §11 Q7. |
| Cycle Engine (M6) interaction | **UNDEFINED BY SPEC — OPEN QUESTION** | Whether an active method suspends Cycle Engine predictions is not in the spec. Fail-safe posture *suggests* suspension, but this is a product/clinical decision, never an engine guess. |
| Guidance on any missed/overdue/expiring state | **"Consult your doctor."** | The engine reports the *logging fact* only. It never states protection status, never advises doubling/skipping. (Core Opinion 2.) |
| Fail-safe | Report `unconfigured/ambiguous` and ask the user | When due-date math is ambiguous (e.g. missing injection date) the engine never assumes protection continuity. |

**Note on "constants":** unlike Hydration (250ml/5000ml/30s) or Caffeine (90min), M7 has **no spec-fixed numeric protocol constant**. The only fixed protocol facts are the three method-type enum values and the fail-safe/no-certainty posture. The per-type windows that *would* be the numeric constants are exactly the OPEN QUESTIONS above — so the SSOT/thin-client audit for M7 targets **due-date math, protection-status logic, and local schedule computation**, not literal magic numbers.

## Proposed REST surface (names only — from `03` §7.6; reconcile against the frozen Phase 1 contract)

| Endpoint | Purpose |
|---|---|
| `POST /v1/engines/contraceptive/methods` | Register a method (typed) |
| `GET  /v1/engines/contraceptive/state` | Current per-method snapshot |
| `POST /v1/engines/contraceptive/events` | Log dose / injection / replacement |
| `GET  /v1/engines/contraceptive/history` | Adherence-to-logging history |

## Session table

Surfaces are executed in the fixed order **backend → web → mcp → apple → android → desktop** (chrome omitted). The backend session MUST land before any client session. `<date>` = ISO build date; `NN` = zero-padded sequence — leave both as placeholders until the session runs.

| Session ID | Surface | Scope (what this one session builds) | Entry deps | Done criteria (doc 13 §5) | Plan docs to read |
|---|---|---|---|---|---|
| `S-<date>-M7-backend-NN` | backend | The `contraceptive` ToGO plugin: pure `core/` state machine with the three per-method sub-machines (`DailyTrack` / `MonthlyTrack` / `LongTermTrack` per `03` §7.3); `plugin.go` kernel registration (routes, config, hook subscriptions, migration manifest); expand-contract migration for method + event tables; the four endpoints returning **computed** per-method state; fail-safe `unconfigured/ambiguous` handling; engine unit tests encoding the categorical differentiation as executable spec; integration test against real Postgres. Rule sets are read through the Microkernel config/hook layer (future doctor "Medical Restrictions" overlay), never hardcoded. Per-type window rules and Cycle-suspension behavior land as **explicitly-flagged sentinels/config**, not invented numbers (see gotchas). | M0.1–M0.4 (kernel, TOGO auth, plugin framework, migration harness); **coordinate with `S-<date>-M6-backend` (Cycle)** — the "does an active method suspend Cycle predictions?" open question spans both engines, so M6 backend should exist first or the decision be recorded jointly | **Backend-engine template:** plugin registered on the kernel; migration is expand-contract and **every column NOT NULL with a defined default** (unconfigured/ambiguous modeled as a sentinel enum state, never SQL NULL); endpoints return computed state; engine unit tests encode the spec facts literally (daily pill vs monthly injection vs implant follow distinct machines; missed/overdue reports logging fact only; no protection-status output) and pass; integration test against real Postgres passes (idempotency replay on `events`, concurrent-log race); **no protocol/schedule constant appears outside the engine's `core/` package** | `13` (§3, §5, §6); `03` §7 + §0 + §9.2 + §10; `04` §4 (NOT NULL rule), §5 (expand-contract), §8 (plugin purity), §9 (testing) |
| `S-<date>-M7-web-NN` | web | Contraceptive tracking screen at `/engines/contraceptive`: register a typed method, log dose/injection/replacement events, and render the server's per-method snapshot + upcoming due items + missed/late history verbatim. All three method-type UIs render from server state; the screen computes no schedule and shows no protection verdict. Categorical method picker only. | M0.5–M0.7 (web shell, theme engine, i18n/RTL); `S-<date>-M7-backend`; **M1 web** as the reference-engine pattern to copy | **Client-engine template:** the screen renders `/v1/engines/contraceptive/state` (+ history) and submits register/log intents only; **thin-client/SSOT audit passes** — no due-date math, no schedule computation, no "protected/not protected" logic in client code (grep finds no per-type window logic); both dark-glow and light-flat themes render per the strict color spec; Arabic RTL mirrors correctly (incl. any progress/countdown for an expiring implant); all strings ICU, none concatenated; every AI-adjacent/consequence surface carries "Consult your doctor." | `13` (§3, §5); `05` §1, §3.1 (`/engines/contraceptive` route), §3.2 (`['engine','contraceptive']` query), §4 (theme), §5/§5b (i18n/RTL), §7 (Log Entry Controls); `03` §7 |
| `S-<date>-M7-mcp-NN` | mcp | A **read-only** status tool (e.g. `contraceptive_status`) that calls `GET /v1/engines/contraceptive/state` and returns the server snapshot verbatim (per method: type, upcoming due, missed/late — no protection claim). Register the CLI equivalent (`healthdebug contraceptive status`). Logging/write tools are **out of M7 mcp scope** (brief = "status read"). | M0.8 (MCP server + CLI skeleton); `S-<date>-M7-backend` | **MCP template:** the tool calls the real API with personal-access-token auth, returns server state verbatim, **holds no protocol logic and no AI keys**; it adds no interpretation and emits no medical-certainty text; deliberately-excluded surfaces stay excluded (no prediction/diagnosis passthrough). Whether MCP should also allow *logging* contraceptive events is flagged **PENDING DESIGN**, not built here | `13` (§5); `11` (Architecture, Planned tools table, Core Opinions, "Tool list grows with the engines"); `03` §7 |
| `S-<date>-M7-apple-NN` | apple | iOS Contraceptive Security screen (part of Divergence #1 "Meds & Cycle Tracking on iOS"): render the server's differentiation of daily pills / monthly injections / implants and log adherence events against it. Reminder scheduling fires at **server-provided** instants only. Privacy-discreet presentation (lock-screen / complication discretion) is a first-class concern here. No HealthKit cycle-tracking data is used as input or output. | `S-<date>-M7-backend`; **M1 apple** (workspace + `HDAPIClient`/`HDDesignSystem`/`HDLocalization` scaffold); logically grouped with `S-<date>-M6-apple` (Cycle) under Divergence #1 | **Client-engine template:** iOS surface renders API state and logs intents only; **SSOT audit** — no regimen/schedule math on device (no per-type window constants embedded); both themes exact per §10.1 color spec (glow vs flat); full Arabic RTL mirroring incl. progress/ring direction; ICU strings, no concatenation; medical-certainty copy audit passes ("Consult your doctor.", no protection claims) | `13` (§5); `07` §1, §3.1 (client/backend line), §4 (Contraceptive row), §10 (theming/RTL), **§11 (Closing Divergence #1 — Meds & Cycle)**; `03` §7 |
| `S-<date>-M7-android-NN` | android | Handheld Kotlin/Compose Contraceptive Security screen: collect method + log intents, render the server's regimen differentiation and history. Reminders fire at server-scheduled instants via `core/notifications` (Divergence #3 layer); channel taxonomy includes cycle/contraceptive reminders. Wear/Auto/Glance parity for this engine is **not required** (it is not a companion-surface engine like Hydration/Pomodoro) unless design says otherwise. | `S-<date>-M7-backend`; **M1 android** (`core/network`, `core/model`, `core/designsystem`, `core/i18n` scaffold); logically alongside `S-<date>-M6-android` (Cycle) | **Client-engine template:** the screen POSTs method/log intents and renders API state only; **thin-client architecture test** — `core/model` stays data-only, no engine outcome computed anywhere (no per-type window rules in Kotlin); both palettes exact per §7.1; full `LayoutDirection.Rtl` Arabic pass incl. mirrored progress; ICU/`values-ar`, no concatenation; behavioral-only copy, "Consult your doctor." | `13` (§5); `08` §2 (thin-client matrix, Contraceptive row), §3 (layout), §7.1 (theme), §8 (notifications), §9 (RTL); `03` §7 |
| `S-<date>-M7-desktop-NN` | desktop | Electron desktop Contraceptive Security view: reuse the shared `packages/ui` React components from the M7 web session inside the desktop shell; render server state, log via the same `packages/api-client`. No desktop-specific protocol logic; tray/quick-action involvement is optional and **PENDING DESIGN** (contraceptive logging may be intentionally kept to the full window for privacy). | `S-<date>-M7-backend`; **`S-<date>-M7-web`** (shared components + api-client hooks); **M1 desktop** (Electron shell scaffold, Phases 1–2 stable) | **Client-engine template:** renderer reuses shared components and renders API state only; **SSOT conformance gate** — no protocol/schedule constants in `apps/desktop` or `packages/*` (only server-provided display strings); both themes exact per §9 palette; Arabic RTL incl. mirrored progress across window/popover; ICU catalogs shared, no concatenation; AI/consequence copy defers to "Consult your doctor." | `13` (§5); `09` §3 (architectural rules), §4 (code sharing with web), §9 (theme), §11 (i18n/RTL); `05` (shared component contracts); `03` §7 |

## Notes & gotchas

- **Reuse the reference-engine pattern.** M1 (Hydration) is built end-to-end first as the reference; every M7 per-surface session should copy its established shape (plugin `core/`+`plugin.go` layout, web engine-card/route pattern, MCP tool wiring, native screen scaffold) so these sessions go faster. M6 (Cycle) is the closest sibling — same "not on chrome," same Divergence #1 grouping on Apple, same fail-safe/no-certainty posture — reuse its decisions where they transfer.
- **No invented numbers — this is the headline liability.** Per-type window/validity rules (pill day-window/grace, injection due tolerance, implant validity duration, expiry-reminder lead time) are **PENDING DESIGN / OPEN QUESTION** (`03` §7.2, §11 Q7). The backend must model these as loaded config/sentinels behind the Microkernel config-hook layer (so a future doctor "Medical Restrictions" overlay can set them without an engine rewrite — `03` §10, `04` §8), **not** as constants baked into `core/`. If a session needs a concrete window to proceed, it stops and records the open question — it does not guess.
- **Cycle interaction is cross-engine and clinical (PENDING DESIGN).** "Does an active contraceptive method suspend Cycle Engine (M6) predictions?" is unresolved (`03` §7.7, §11 Q7). Fail-safe posture suggests suspension, but it must be a product/clinical decision. Coordinate the M7 and M6 backend sessions; whichever lands second must reconcile the interaction and record the decision as a classified `architecture-decision`/`open-question` memory and (if it changes behavior) an edit to `03`.
- **Never emit protection status.** On any missed/overdue/expiring state the engine reports only the logging fact; it must never render "you are protected / not protected," efficacy percentages, or dosing advice. Every such surface terminates in "Consult your doctor." (Core Opinion 2 — strict here.) Copy audits are a client-session done-criterion.
- **Privacy/discretion is a real requirement, and PENDING DESIGN.** Reminder surfaces and privacy presentation — lock-screen discretion, watch complications, whether contraceptive logging appears in tray/widgets at all — are **PENDING DESIGN** (`03` §7.4). Treat contraceptive data as sensitive; default to discreet.
- **Method switching / archival.** Overlap semantics when switching method (pill → injection: archive old machine, instantiate new) are an **open question** (`03` §7.7). Model archival explicitly; do not silently drop history.
- **Schema discipline (backend).** Every column NOT NULL with a defined default; the `unconfigured/ambiguous` fail-safe is a sentinel enum state, never SQL NULL; all changes strictly expand-contract with `atlas migrate lint` as the CI gate (`04` §4, §5). Method type is a closed enum; events are append-only with an idempotency key (`04` §7) so an AI/watch retry cannot double-log.
- **MCP is read-only for M7.** The brief scopes MCP to a status read. No `log`/write tool and no prediction/diagnosis passthrough. Keep the deliberately-excluded posture; revisit only if a later product decision opens it (PENDING DESIGN).
- **No chrome cell exists for M7.** Do not create one; the module grid intentionally has no `chrome` column here (matches M6).

## Handoff reminder

At session end, follow the Brain Handoff Protocol (`docs/plan/13-execution-modules-and-sessions.md` §6): write **one** `session-handoff` memory to the `healthdebug` cabrain brain — `retain` the content in the §6 structure, then `memory/edit` to attach metadata — with a unique `source_ref: handoff/M7-contraceptive-security/<surface>/<n>` (never reuse a ref) and metadata `{project:"healthdebug", category:"session-handoff", era:"greenfield", status:"current", surface:"<surface>", module:"M7", title:"Handoff <session-id>", tags:[...], next:"<module+surface>"}`. Then **update the single `build-ledger` memory** (`source_ref: build-ledger`, edited in place) so one recall shows the whole frontier and the recommended next session. Any new architectural decision or open question (e.g. the Cycle-suspension resolution, a chosen per-type window rule) also gets its own classified memory and, if it changes the plan, an edit to the relevant plan doc.
