Pages · Health Debug
M8 — Kinetic Pomodoro — Session Card
Planning artifact. A future build session opens this to know exactly what its cell is, what must be done first, and when it is done. Read alongside
docs/plan/13-execution-modules-and-sessions.md(the framework),docs/plan/03-protocol-engines.md §8(the engine spec),docs/plan/04-backend-togo.md(plugin / migration / test conventions), and the relevant platform PRD (05 web, 06 chrome, 07 apple, 08 android, 09 desktop, 11 mcp).
1. Purpose
Kinetic Pomodoro is a desk-work focus timer for the core audience (programmers/engineers) whose defining, non-negotiable rule is that a break registers only when a wearable detects physical movement away from the screen — sitting through the break with the timer running does not count, and the absence of motion data is never treated as movement (fail-safe: under-credit, never over-credit). As with every engine, the ToGO backend is the Single Source of Truth: the pomodoro plugin owns the work/break state machine and the verification decision; watchOS (CoreMotion) and WearOS clients are pure sensor-collection layers that push motion evidence; and every desk-side surface (web, chrome, apple menu-bar/overlay, android, desktop) only renders server state and reports evidence. Because the whole point of the module is wearable-validated breaks, the watch and Wear motion sub-sessions are mandatory — apple and android cannot be marked done without them.
2. Engine / feature parameters (exact — do not invent)
| Parameter | Value / status |
|---|---|
| Break validation | Break registers only if wearable motion data shows physical movement away from the screen. |
| No-evidence rule (fail-safe) | Absence of wearable data ⇒ BreakNotRegistered (unverified). Absence is never movement. All ambiguity resolves to "break not registered"; the engine under-credits. |
| Verification authority | The verification decision is made only on the backend. watchOS (CoreMotion) / WearOS sensors collect and push evidence; the watch/phone/extension/desktop never mark a break complete. |
| Break state (categorical) | A break is Registered or Not Registered — binary. No "70% of a break," no movement-quality score surfaced to the user. |
| Motion ingest | Evidence arrives via shared sensor ingest (POST /v1/sensors/motion/batches), consumed by the pomodoro engine. |
| Interval lengths | PENDING RATIFICATION — not spec-fixed. Legacy precedent (also PENDING ratification): 25 min work / 5 min short break / 15 min long break, long break every 4 cycles, daily target 8. These are config values read through the Microkernel config/hook layer, never hardcoded in core/. |
| Qualifying-motion threshold | The quantitative signature of "movement away from the workstation" (steps/distance/duration/sensor-fusion recipe) is PENDING DESIGN — backend-owned; clients must not embed it. |
| Late-sync re-evaluation | Retroactive BreakNotRegistered → BreakRegistered on late-arriving evidence is allowed in principle; the exact re-evaluation window is PENDING DESIGN. |
| No-wearable degraded mode | Whether an honor-system mode exists is PENDING DESIGN; spec default is breaks simply do not register without wearable evidence. |
| Opinion 1 (categorical, not quantitative) | Binary break outcome only; no motion arithmetic surfaced. |
| Opinion 2 (no invented medical certainty) | No musculoskeletal/cardiovascular claims. AI does behavioral pattern analysis of sitting/break patterns only and always defers to "Consult your doctor." |
| Colors — Dark | #1A1A1A bg · #00FF33 neon-green glow for the active timer · #00CCFF cyan buttons · #FF3333 red alerts (glow effects). |
| Colors — Light | #FFFFFF bg · #20A060 teal · #0070A0 deep cyan (flat). |
| i18n | ICU Message Format, en/ar catalogs, full Arabic RTL with mirrored progress/countdown; no string concatenation. |
3. Session table
One row per session. <date> = ISO date the session runs; <NN> = zero-padded sequence. Surface order follows doc 13 §3/§4: backend → web → mcp → chrome → apple → android → desktop. The two shaded sub-sessions (apple-watch, android-wear) are mandatory gates on their parent surface.
| Session ID | Surface | Scope (what this one session builds) | Entry deps | Done criteria (doc 13 §5) | Plan docs to read |
|---|---|---|---|---|---|
S-<date>-M8-backend-<NN> | backend | Pomodoro engine as its own ToGO plugin: pure core/ state machine (Idle → Working → BreakPending → BreakVerifying → BreakRegistered / BreakNotRegistered → Working), plugin.go kernel registration (routes, hook subscriptions, config for interval lengths, migration manifest), expand-contract migration for session + break-verification tables, endpoints POST /v1/engines/pomodoro/sessions, POST /v1/engines/pomodoro/sessions/{id}/stop, GET /v1/engines/pomodoro/state, GET /v1/engines/pomodoro/history, plus consumption of POST /v1/sensors/motion/batches. Break verification consumes motion evidence only; no evidence ⇒ BreakNotRegistered. Interval lengths read from config (PENDING ratification), not hardcoded. | M0.1–M0.4 (kernel boot, TOGO auth + user isolation, plugin framework, migration harness). Shared sensor/motion ingest boundary (/v1/sensors/...) — build here or depend on X3 sensors ingest; resolve before starting. | Backend-engine template: plugin registered on kernel; migration expand-contract, every column NOT NULL with a default; endpoints return computed state; unit tests encode the one spec-fixed rule literally (break registers only on wearable movement; absence ≠ movement) and the config-driven interval values as parameters; integration test vs. real Postgres passes (idempotency replay, no-evidence ⇒ not registered, late-sync re-evaluation, break-window race); no protocol constant appears outside the engine's core/ package (and interval numbers live in config, not core/). | 03 §8, §9.3; 04 §2–§9; 13 §3, §5 |
S-<date>-M8-web-<NN> | web | Pomodoro focus card on the web dashboard (/engines/pomodoro, query key ['engine','pomodoro','current']): renders server state (work/break-pending/verifying/registered/not-registered + today's registered breaks); start/stop mutations; countdown animates toward the server-provided deadline only and re-syncs on server response. Displays break outcome; never claims a break "counts." | M0.5–M0.7 (web shell + auth, theme engine, i18n engine); M8 backend. | Client-engine template: renders /state and submits start/stop intents only; thin-client/SSOT audit passes (no timer/interval/verification logic in client — grep finds no protocol constants; countdown is display-only against the server deadline); both themes render per the strict color spec (neon-green glow timer in dark); Arabic RTL mirrors correctly incl. progress/countdown; all strings ICU, none concatenated. | 05 §1, §3 (query keys/endpoints), §5 (Pomodoro Card); 03 §8; 13 §5 |
S-<date>-M8-mcp-<NN> | mcp | pomodoro_status tool: read-only current work/break snapshot from GET /v1/engines/pomodoro/state via personal-access-token auth. Verify the deliberately excluded complete_break tool stays excluded — an AI must not fake a break. | M0.8 (MCP server + CLI skeleton); M8 backend. | MCP template: the tool calls the real API with PAT auth, returns server state verbatim, holds no protocol logic and no AI keys; the excluded complete_break (and any break-marking tool) stays excluded; tool schema description states outputs are behavioral tracking, not medical advice. | 11 (tool table + exclusions); 03 §8; 13 §5 |
S-<date>-M8-chrome-<NN> | chrome | Active Pomodoro Guard (MV3, content-script-free): background worker mirrors work/break state to the toolbar badge from the aggregate snapshot poll; during a server-declared forced break it intercepts continuous browser activity (via chosen activity signal — chrome.idle vs. tab events, permission tradeoff PENDING) and reports that activity to POST /pomodoro/events as sensor evidence only. Never marks a break complete. | Chrome extension shell (auth/background worker/snapshot poll from the chrome foundation / M1 chrome session); M8 backend; motion+activity ingest live. | Client-engine template: badge renders server snapshot state; activity is reported as evidence, never a completion verdict; thin-client/SSOT audit passes (no interval/verification logic; the extension "never decides a break was completed"); both themes per color spec (alert #FF3333 family while user keeps browsing during a break); Arabic RTL; ICU strings, none concatenated; permission set stays minimal unless the activity-signal decision explicitly widens it. | 06 §5 (Active Pomodoro Guard), §2.4 (permissions), §3.2; 03 §8; 13 §5 |
S-<date>-M8-apple-<NN> | apple | iOS focus-timer screen; macOS Workstation Guard optional full-screen break overlay (reflects backend break state; lifts on server verdict; dismiss semantics PENDING DESIGN); macOS menu-bar timer (MenuBarExtra) rendering state + countdown from server timestamps. Renders server state only. Marking this surface done requires the apple-watch sub-session below. | Apple app shell + HDAPIClient + auth (apple foundation / M1 apple); M8 backend. | Client-engine template + M8 gate: surfaces render /state and submit start/stop only; thin-client/SSOT audit passes (no interval/verification logic; overlay never validates the break — closing it does not register one); both themes per color spec (glow timer; Metal-glow escalation is PENDING DESIGN); Arabic RTL incl. mirrored progress; ICU strings. Not done until apple-watch sub-session is done (doc 13 §4). | 07 §6–§7 (watchOS, menu bar, Workstation Guard); 03 §8; 13 §4–§5 |
S-<date>-M8-apple-watch-<NN> | apple (watchOS) | MANDATORY sub-session. watchOS CoreMotion movement-evidence session: during a backend-declared break window, sample accelerometer/gyroscope, package as an evidence payload, and push to the ToGO API (via paired iPhone or direct — transport decision at build). Watch renders backend-returned state and never self-completes a break. | S-<date>-M8-apple-<NN>; M8 backend; the qualifying-movement evidence contract (backend-owned, PENDING DESIGN — payload = raw vs. featurized). | Client-engine template (sensor-collection variant): watch pushes evidence only and renders both BreakRegistered / BreakNotRegistered outcomes from the server; SSOT audit passes (no threshold/verification logic on-device); recorded-CoreMotion-trace test (movement vs. stationary) replayed vs. a mock API proves it reports evidence, renders both outcomes, and never self-completes; haptics timing originates from the server schedule; Arabic RTL on watch surfaces. Completing this unblocks marking apple done. | 07 §6.1 (CoreMotion break validation), §11 (Pomodoro test), Open Q #4; 03 §8; 13 §4 |
S-<date>-M8-android-<NN> | android | Android phone focus-timer screen; Android Auto constraint-awareness surface for pomodoro state (display/voice per Auto affordances, backend-served ICU strings). Renders server state only. Marking this surface done requires the android-wear sub-session below. | Android app shell + core modules + auth (android foundation / M1 android); M8 backend. | Client-engine template + M8 gate: phone/Auto render engine-status snapshot and submit start/stop only; thin-client/SSOT audit passes (no interval/verification logic); both themes per color spec (Glance/Tile glow approximation PENDING DESIGN); full LayoutDirection.Rtl incl. mirrored progress; ICU strings shared with web catalogs, none concatenated. Not done until android-wear sub-session is done (doc 13 §4). | 08 §5–§6 (WearOS, Auto), §9 (RTL); 03 §8; 13 §4–§5 |
S-<date>-M8-android-wear-<NN> | android (Wear) | MANDATORY sub-session. WearOS sensor movement-evidence session: during a backend-declared break window, sample the watch's motion/step sensors, transmit evidence to POST /v1/engines/pomodoro/movement (or the shared motion ingest); sense only inside break windows (battery). Backend decides; the Wear client never registers a break and embeds no threshold. | S-<date>-M8-android-<NN>; M8 backend; the movement evidence contract / Wear transport (backend-owned + phone-relay-vs-direct, PENDING). | Client-engine template (sensor-collection variant): Wear pushes evidence only, renders BreakRegistered / BreakNotRegistered as received; SSOT audit passes (no threshold/verification logic — the "engine decides" rule holds); test proves evidence is sent only during backend break windows and both verdicts render as received; no-wearable path leaves the break unregistered; Arabic RTL on Tiles/Wear surfaces. Completing this unblocks marking android done. | 08 §5.2 (Kinetic Pomodoro movement detection), §11, Open Q #3–#4; 03 §8; 13 §4 |
S-<date>-M8-desktop-<NN> | desktop | Electron surface: Workstation Lock / Break Enforcer optional always-on-top overlay (one per connected display) driven by server break state, with a dismiss escape hatch (friction PENDING DESIGN); system-tray live pomodoro countdown (ticks locally against server anchors, re-anchors on sync) + quick-action menu; global hotkey for start/quick-log wired to API. Reuses the web focus card; has no movement-sensor role. | Desktop Electron shell + tray + hotkey + vault infra (desktop foundation / M1 desktop); M8 backend; web pomodoro card (S-<date>-M8-web-<NN>). | Client-engine template: overlay/tray/hotkey render server break state and submit intents only; thin-client/SSOT audit passes (overlay never validates a break — closing it, mouse, or keypress does not register one; only the server, on wearable movement, registers; no protocol constants in client code); both themes per color spec (#00FF33 glow active timer, #FF3333 alerts); Arabic RTL incl. mirrored progress in overlay + popover; ICU strings shared with web catalogs. | 09 §5 (tray), §7 (Break Enforcer), §8 (hotkeys), §10 (i18n/RTL); 03 §8; 13 §5 |
4. Notes & gotchas
- Only one rule is spec-fixed. "A break registers only on wearable-detected movement away from the screen, and absence of data never counts" is the whole spec (03 §8.2). Everything quantitative — interval lengths, break lengths, the motion threshold, long-break cadence, daily target — is an open question / PENDING DESIGN. Encode only the fail-safe rule as an engine invariant.
- Interval lengths are PENDING RATIFICATION, not spec constants. The legacy 25 min work / 5 min short / 15 min long / long break every 4 cycles / daily target 8 is a precedent to reuse pending ratification, not a value to hardcode. Keep it in Microkernel config/hook layer so a future doctor "Medical Restrictions" overlay (03 §10) can alter break policy without an engine rewrite. Do not let interval numbers leak into
core/or any client (they would fail the thin-client / SSOT grep audit). - The watch/Wear sub-sessions are gates, not extras. apple and android are not done until
apple-watch(CoreMotion) andandroid-wear(Wear sensors) are done (doc 13 §4, §5). The phone/menu-bar/overlay/extension/desktop must never fabricate a break; a break with no motion evidence isBreakNotRegistered. - Fail-safe direction is under-credit. Late-syncing evidence may upgrade
NotRegistered → Registered; borderline/at-desk motion should not credit. All ambiguity resolves to "not registered." - Chrome liability. The extension is content-script-free — it cannot draw in-page overlays and must intercept forced breaks via extension-owned surfaces (badge/notifications/side panel). Its activity signal is evidence only; the activity-signal mechanism (
chrome.idlevs. tab events) and its permission tradeoff are PENDING (06 §5.2, §12). - Desktop liability. The Break Enforcer is a full-screen always-on-top app window, not an OS lock; it must offer a dismiss path and has no sensor role. Multi-monitor coverage is first-class; Wayland global-hotkey and Linux tray support are open questions (09 §6–§8).
- PENDING DESIGN carried by this module: timer/overlay visuals and glow radii/intensities; how an unregistered break is communicated without shaming; Workstation Guard dismissal semantics (apple + desktop); chrome interception aggressiveness; the backend qualifying-movement evidence contract and re-evaluation window; watch↔phone transport for evidence; no-wearable degraded mode.
- Motion ingest ordering. The engine depends on the shared
/v1/sensors/...motion ingest boundary. Confirm whether it is built inside the M8 backend session or supplied by X3 (sensors/biometrics) before starting backend; the watch/Wear sub-sessions cannot report evidence until it exists.
5. Handoff reminder
At the end of every M8 session, per doc 13 §6: write one session-handoff memory to the cabrain healthdebug brain (retain, then memory/edit to attach metadata — retain cannot set metadata) using the exact handoff content structure, with source_ref: handoff/M8-kinetic-pomodoro/<surface>/<n> (unique per session — never reuse) and metadata {project:"healthdebug", category:"session-handoff", era:"greenfield", status:"current", surface:"<surface>", module:"M8", 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. <surface> values for this module: backend, web, mcp, chrome, apple, apple-watch, android, android-wear, desktop.