Seiten · Health Debug
Session Card — M3 GERD Window
Per-module session list for the GERD Window protocol engine (Module M3, row 3 of the module × surface grid in
docs/plan/13-execution-modules-and-sessions.md). Each row below is one build session — one (module × surface) cell. Open this card at the start of a GERD session, read the referenced plan docs, build exactly that cell, then close with a brain handoff (see the bottom of this file and doc 13 §6).
Purpose
The GERD Window engine protects the pre-sleep digestive window for GERD-prone users: during the 4 hours before sleep, the only protocol-compliant intake is an explicit closed whitelist — water, chamomile, anise. Anything else logged inside the window is a categorical violation (a sip of juice and a full meal are the same violation class — quantity is irrelevant, per Core Opinion 1). The engine is its own ToGO plugin (pure core/ state machine + plugin.go registration) and is the single source of truth: it computes window activation server-side from a sleep anchor, records violations, and exposes state. Every client surface only renders window_starts_at / window_active / allowed_items / violations and submits intake intents — no client ever computes the 4-hour window or the whitelist membership. The check is a categorical allowed-list membership test only; there is no quantitative math and no medical claim (the engine reports compliance, never "reflux occurred," and defers to "Consult your doctor").
Engine parameters (exact — from doc 03 §3; do not invent)
| Parameter | Value | Source |
|---|---|---|
| Window length | 4 hours before sleep | 03 §3.2 |
| Whitelist (ONLY items allowed) | water, chamomile, anise — a closed 3-item set | 03 §3.2 / §3.4 |
| Whitelist semantics | Set membership; no "small amounts are fine" carve-out (quantity irrelevant, Opinion 1) | 03 §3.4 |
| Window activation | Computed server-side from the sleep anchor; clients render only window_starts_at / window_active | 03 §3.4 |
| No-anchor behavior | Fail-safe — state: unanchored; engine does not guess a bedtime; no violations generated while unanchored | 03 §3.7 |
| Alert / violation color | #FF3333 red (dark: with glow; light: flat) | 03 §3.5, color spec |
| CarPlay/Auto pre-alert lead time | 30 minutes before window start ("GERD Window starting in 30 minutes; finish eating before driving.") — spec example; whether this offset is a general backend rule is PENDING DESIGN (see Notes) | 07 §241/§351, 08 §314 |
States (03 §3.3): unanchored → Open (daytime; catalog eval deferred to Engine 4) → WindowActive (inside the 4 h window; whitelist is the entire allowed set; non-whitelist log → violation recorded) → Sleeping (between sleep and wake events; logs store-and-flag-for-review — spec-undefined, see gotchas) → Open on wake (hands off to the Caffeine Block engine).
REST surface (names only, 03 §3.6): GET /v1/engines/gerd/state · PUT /v1/engines/gerd/sleep-anchor · POST /v1/engines/gerd/sleep · GET /v1/engines/gerd/violations. Intake is logged through the shared pipeline POST /v1/intake/logs, which fan-outs via Microkernel hooks to GERD, Caffeine, and Trigger Families evaluators — GERD records its own verdict independently (03 §9.1).
Sessions
Build order within the module (doc 13 §3/§4): backend → web → mcp → chrome → apple → android → desktop. The backend session MUST land before any client session for this module. Session ID pattern: S-<date>-M3-<surface>-NN (fill <date> = build date, NN = zero-padded ordinal at write time).
| Session ID | Surface | Scope (this one session) | Entry deps | Done criteria (doc 13 §5) | Plan docs to read |
|---|---|---|---|---|---|
S-<date>-M3-backend-NN | backend | The gerd ToGO plugin: pure core/ state machine (unanchored/Open/WindowActive/Sleeping) computing the 4 h pre-sleep window from the sleep anchor; closed-whitelist membership check {water, chamomile, anise}; violated recording on non-whitelist intake; warning-lead-time hook (fire "window starting" event ahead of window_starts_at). plugin.go registration on the kernel + hook-bus subscription to POST /v1/intake/logs fan-out. Expand-contract migration for sleep-anchor config + violations tables. Endpoints: state, sleep-anchor (PUT), sleep (POST), violations (GET). Fail-safe unanchored. Injected clock. | M0.1–M0.4 (kernel, auth, plugin framework, migration harness); M1 backend (reference engine pattern to copy). | Backend-engine template: plugin registered on kernel; migration expand-contract and every column NOT NULL with a default; endpoints return computed state (decisions, not raw params); engine unit tests encode every spec constant literally (4 h window, the exact 3-item whitelist, unanchored fail-safe) and pass; integration test against real Postgres passes — idempotency replay, plus GERD edge cases (unanchored → no violations, bedtime-moved recompute, Sleeping store-and-flag, seeded in-flight open window survives roll-forward/back); no protocol constant (4 h, whitelist items) appears outside the gerd core/ package. | 03 §3 (+§9.1), 04 (§ plugin layout, timezone/day-boundary open Q), 13 §5, 01 (NOT NULL + expand-contract; seed in-flight GERD window), 12 (legacy shutdown.go precedent) |
S-<date>-M3-web-NN | web | GERD Window timer card on the dashboard (/engines/gerd): renders server state only — window_starts_at countdown, window_active, allowed-items chips (water/chamomile/anise), violation list. Red #FF3333 on violation. unanchored state → prompt to configure sleep anchor. TanStack query key ['engine','gerd',date]; invalidated on food/drink log mutation. | M3 backend; M0.5–M0.7 (web shell, theme engine, i18n engine). | Client-engine template: card renders the engine endpoint state and submits log intents only; thin-client/SSOT audit passes (grep for 4h/window/whitelist logic in client code finds nothing); both dark-glow and light-flat themes render per the strict color spec; Arabic RTL mirrors correctly incl. the countdown/progress bar; all strings ICU Message Format, none concatenated. | 05 (§ query keys, engine status cards), 03 §3, 13 §5, 01 |
S-<date>-M3-mcp-NN | mcp | Surface the GERD countdown inside the today_status tool: state, window_starts_at, window_remaining, allowed_items, violations — passed through verbatim as part of the full computed day. No new write tool. | M3 backend; M0.8 (MCP server + CLI skeleton, PAT auth, transport). | 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; excluded tools stay excluded (no complete_break etc.). | 11 (today_status), 03 §3, 13 §5 |
S-<date>-M3-chrome-NN | chrome | MV3 surface: badge red bug icon while a GERD-window violation is active; GERD timer in the popup (4 h countdown/state, alert styling #FF3333 on violation). Reads the aggregate GET /protocol/state snapshot (badge/timer driven by server state); logging buttons submit intents only. | M3 backend; M1 chrome (reference MV3 shell: service worker, popup, badge, /protocol/state polling pattern). | Client-engine template: popup/worker render server snapshot and submit intents only; thin-client/SSOT audit passes (no window/whitelist logic in worker or popup — grep finds nothing; badge state derived from server verdict); both themes; RTL correct; ICU strings, none concatenated. Red-bug-icon asset is PENDING DESIGN — wire the state, use a placeholder if art not delivered. | 06 (popup, badge states, /protocol/state), 03 §3, 13 §5 |
S-<date>-M3-apple-NN | apple | iOS/macOS GERD card (render window state + permitted list exactly as returned); watchOS haptic at window start; CarPlay audio-first alert — voice "GERD Window starting in 30 minutes; finish eating before driving." Alert times come from the server-computed alert schedule; the client only schedules locally and voices. Widget content is a candidate — PENDING. | M3 backend; M1 apple (reference Swift shell: iOS/watch/CarPlay wiring); X3 sensors alongside (HealthKit sleep push may feed the anchor). | Client-engine template: every Apple surface renders engine state and submits intents only; thin-client/SSOT audit passes (no 4 h/window logic on device; alert times taken from the server schedule, not computed); both themes; Arabic RTL mirrors; ICU strings, none concatenated. Watch haptic/CarPlay copy voiced from localized ICU keys. | 07 (§ GERD row, CarPlay audio-first, watch haptic, alert schedule), 03 §3, 13 §5 |
S-<date>-M3-android-NN | android | Android Auto warning for the GERD window (approaching/active) with the allowed-items framing (only water, chamomile, anise) exactly as delivered by the backend; handheld GERD status tile; a GERD-Window notification channel fed by GET /v1/notifications/schedule. Renders server state; no local window math. | M3 backend; M1 android (reference Kotlin shell: phone/Auto/Glance wiring); X3 sensors alongside (Health Connect sleep push may feed the anchor). | Client-engine template: phone/Auto/tile render server state and submit intents only; thin-client/SSOT audit passes (no window/whitelist logic; allowed-items list rendered verbatim); both themes; Arabic RTL mirrors; ICU strings, none concatenated. | 08 (§ GERD row, Auto warning, notification schedule/channels), 03 §3, 13 §5 |
S-<date>-M3-desktop-NN | desktop | Electron GERD surface reusing the M3 web components: window card + tray/OS notification on GERD violation (#FF3333). Shows what the server said on rejection; never pre-computes it. | M3 backend; M3 web (reuses web components); M1 desktop (reference Electron shell/tray). | Client-engine template: tray/window render server state and submit intents only; thin-client/SSOT audit passes (no window/whitelist logic in Electron/main or renderer); both themes; Arabic RTL mirrors; ICU strings, none concatenated. | 09 (§ SSOT, tray rejection flow), 05, 03 §3, 13 §5 |
Session count: 7 (backend, web, mcp, chrome, apple, android, desktop).
Notes & gotchas
- Legacy precedent worth reusing (doc 12,
shutdown.go): window =shutdown_window_hoursbefore target sleep, default 4 h; allowed = water/chamomile/anise; "past sleep time rolls to tomorrow." Reuse the default-4h and roll-to-tomorrow anchoring logic. Legacynotify.gofired a shutdown warning at 30 min before the window — corroborates the CarPlay/Auto 30-minute pre-alert as a reasonable default. Do NOT port the legacy high-risk keyword blocklist (spicy, fried, dairy, chocolate, citrus, tomato, coffee, soda, alcohol, mint): the greenfield GERD engine is a closed whitelist membership check, not a keyword blocklist — that blocklist territory belongs to Trigger Families (Engine 4 / M4). - PENDING DESIGN — sleep-anchor source (primary open question, doc 03 §3.2/§11.4, doc 04 § Open Questions). The window is pre-sleep but the spec does not fix the anchor: configured bedtime vs. wearable-predicted sleep onset vs. explicit "going to sleep now" event, plus timezone/day-boundary/DST policy. The backend session must pick a workable default (configured bedtime, roll-to-tomorrow) behind the
sleep-anchor/sleependpoints and flag the choice in its handoff. Do not hardcode a bedtime. - PENDING DESIGN — recompute policy when bedtime moves after the window started (03 §3.7): whether already-flagged logs are re-evaluated is undefined. Choose store-and-annotate, do not silently rewrite violation history.
- PENDING DESIGN — logs during
Sleeping(03 §3.7): spec-undefined; proposed handling is store-and-flag-for-review, not auto-violation. Keep it out of the violation stream unless design says otherwise. - PENDING DESIGN — UI/asset items: window-countdown + whitelist-chip UI treatment (03 §3.5); chrome red bug icon asset (06 §70/§249); whether clients expose chamomile/anise quick-log buttons in addition to water (06 §159/§346, 09 rejection copy); Android notification-channel taxonomy/names (08 §222); whether the 30-minute pre-alert lead time is a general backend alerting rule or CarPlay/Auto-specific (07 §351, 08 §314). Wire the state and use placeholders where art/copy is not delivered.
- Liabilities to avoid: clients must NEVER compute the 4-hour window or whitelist membership (SSOT — the API returns decisions/state, not raw parameters). The whitelist is closed — resist any "a little is fine" carve-out. A state row reading
NULLis an undefined engine state — every column NOT NULL with a default; migrations expand-contract only; roll-forward/back tests must seed an in-flight open GERD window and assert it survives (01 §expand-contract). - Cross-engine coupling: GERD, Caffeine Block, and Trigger Families all evaluate the same intake event via the
POST /v1/intake/logsfan-out; each records an independent categorical verdict (a 10 p.m. cola can be caffeine-compliant, a GERD violation, and a trigger exposure at once — 03 §9.1). The sleep/wake anchor is shared with Caffeine Block — GERD'swaketransition hands off to the Caffeine Block engine. - Catalog dependency gotcha: whitelist membership needs stable identifiers for water/chamomile/anise. The shared categorical catalog is largely M4 (Trigger Families) territory, which is built after M3. Because the GERD whitelist is a closed 3-item set, keep those allowed identifiers in the
gerdcore/package (or seed a minimal 3-item allowed-list) so the backend session is not blocked on M4; reconcile with the shared catalog when M4 lands. Flag this in the handoff.
Handoff reminder
At the end of every M3 session: write one session-handoff memory to the cabrain healthdebug brain — retain the content in the doc 13 §6 structure, then memory/edit to attach metadata (retain cannot set metadata). Use source_ref: handoff/M3-gerd-window/<surface>/<n> (unique — never reuse) and metadata {project:"healthdebug", category:"session-handoff", era:"greenfield", status:"current", surface:"<surface>", module:"M3", title:"Handoff <session-id>", 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 resolved/added open question also gets its own classified memory and, if it changes the plan, an edit to the relevant plan doc. See doc 13 §6 and docs/brain/BRAIN-INDEX.md.