Skip to content

MoSCoW Prioritization, Personal Training OS (v1 / race-week MVP)

Artifact: 1.2 (Phase 1, Planning) · Owner: Product Owner (Primary User) Version: v1.0, RATIFIED by PO 2026-07-04 · Date: 2026-07-04

MoSCoW sorts scope into Must (no v1 without it), Should (important, not vital), Could (nice, first to drop), Won't (explicitly out this release). Discipline rule: Must-haves should be a minority of effort; if everything is Must, nothing is prioritized. "Won't" is a real decision, carried from the Charter's out-of-scope.

Prioritized at capability level (not all 94 requirements). Note: creating the 15 database structures is itself a Must (requirement ARCH-001); what varies below is how far each is seeded, viewed, and automated for v1.

Must, the race-week MVP (usable for the target races, 25 to 26 Jul)

Capability Serves
All 15 DBs created with schema, relationships & automation-ready fields ARCH-001; foundation
People + Primary User & Secondary User as first-class SC3
Training Sessions core (log runs / races / workouts) core
Races DB + Example Half Marathon & Example 5K seeds race week
Historical run seeds (11-mi, 5-mi) continuity
Running Shoes + auto mileage rollup SC6 (gear)
Running Routes + generic seeds core
Hockey game sessions + attendance / counts-toward-training logic core rule
Dashboard + core views (This Week, Planned Runs, Races, Hockey both teams, Shoe Mileage) SC1
Calendar import for planned runs (low-effort capture) SC2
Core rollups (shoe mileage, hockey load) SC4

Should, valuable; do if time before race week, else fast-follow

Capability Serves
Metrics / Check-ins usable (manual daily) SC4
Nutrition Log usable (manual) future SC2
Goals + Training Blocks with views insight
Weekly Reviews (manual) habit/SC1
Exercise Library + Workout Templates populated SC5
≥1 running + 1 strength + 1 hockey plan (linked/embedded materials) SC5
Hockey Drills + Resources seeded SC5

Could, nice-to-have; first to drop under time pressure

Capability Serves
Richer insight dashboards (beyond mileage + load) SC4+
Embedded videos / extra plan materials SC5+
Equipment/balance-board nuance, extra routes polish

Won't (this release), deferred by Charter, revisit post-v1

Deferred Why / status
~~Garmin live sync~~ PROMOTED → SHIPPED as Increment 2 (2026-07-05). Was deferred for time; time recovered (ahead of schedule) → built. Increment 2 delivered both Garmin activities to Training Sessions (2a) and Garmin daily wellness metrics to Metrics/Check-ins (2b), plus the Withings weight sync to Metrics/Check-ins (2c, weight only). All live daily 06:00; operational evidence only (formal V&V outstanding).
Strava live sync Scaffolded / prepped, BLOCKED on a paid Strava subscription (distinct from un-built deferrals: the integration is staged, see STRAVA-SETUP.md, and only the paid subscription gates go-live; no secrets configured yet).
~~MyFitnessPal (nutrition)~~ PROMOTED → SHIPPED as Increment 4 (2026-07-09), see Amendment v1.4 below. The compliant path identified here was taken = MFP Premium emailed CSV export ("Download Your Data" / "Meal Level Nutrition Details"), user-initiated and ToS-clean; automation/mfp_email_to_notion.py ingests it into the Nutrition Log at per-meal grain with every column. The export is one row per logged food (several per meal, no food-name column), so foods are summed into per-meal totals (nothing dropped). It stays true that MFP has no open API (partner-only) and scraping is ToS-barred (the scraper also broke on MFP's Dec-2025 SPA rewrite) and the Withings API does not expose nutrition/macros: that is exactly why the export route was used. The Gmail-relay auto-trigger (--gmail, IMAP + a Gmail App Password) is live and verified 2026-07-09: Primary User provisioned the GMAIL_APP_PASSWORD secret and the relay ran end-to-end (found the export email, downloaded it, aggregated + wrote the 71 meal rows, labeled the email PTOS-Nutrition-Ingested; a re-run finds 0 unprocessed), fully hands-off once the operator taps MFP "Download Your Data" (a manual --zip <export.zip> fallback also exists, and the graceful-skip when the secret is absent remains in code as a safety net).
Apple Health live sync Deferred. No cloud API; needs an on-device Health Auto Export bridge, and is largely redundant with Garmin.
RAG / AI-insight capability Charter §5. Candidate for a post-race-week Increment 4 (payoff grows with logged data).
Other life domains ("everything eventually") Charter §5. Mission boundary, not a schedule call. Keep out.
Users beyond Primary User + Secondary User (family/friends/kids) Charter §5. Keep out unless a real need appears.
~~Auto-schedule hockey games into Training Sessions~~ PROMOTED → SHIPPED as Increment 3 (2026-07-05). Upcoming games auto-create Planned Hockey sessions linked to the game; TBD bracket placeholders are filtered (team must be a named participant); the plan-vs-actual reconciler flips the row to Attended when the Garmin skate lands. Built to ADR-0003 (game DBs stay source-of-truth).

PO ratification: ✅ 2026-07-04, accepted as drafted. SC5 (training-plan materials) accepted as Should / fast-follow: go-live (G6) may precede SC5, with materials landing shortly after race week.

Amendment v1.1 (2026-07-05): added one Won't-this-release item (auto-schedule hockey games) from UAT validation. Verification passed (built to ADR-0003) but validation flagged an expectation gap; PO disposition = accept MVP as-is, deferred automation logged above. No change to Must/Should/Could.

Amendment v1.3 (2026-07-05): re-triage after finishing Must+Should+Could ahead of schedule (build complete ~3 weeks before race week 25 to 26 Jul). "Won't" is a time-boxed decision, so two items were promoted out of Won't and shipped: (1) Garmin live sync → Increment 2, which delivered both Garmin activities (2a) and Garmin daily wellness metrics (2b), plus the Withings weight sync (2c, weight only); (2) auto-schedule hockey games → Increment 3 (this change). Also corrected drift: the Won't list had still shown Garmin as deferred after it shipped. Discovery run on the remaining integrations (MyFitnessPal, Apple Health) with findings folded into the Won't table above; Strava broken out as scaffolded-but-blocked (paid subscription). No change to Must/Should/Could scope. Change driver = capacity, logged in RAID.

Amendment v1.4 (2026-07-09): promoted MyFitnessPal (nutrition) out of Won't and shipped it as Increment 4. The compliant export path already identified in the Won't table was built: automation/mfp_email_to_notion.py ingests the MFP Premium emailed CSV export into the Nutrition Log at per-meal grain, capturing every column (all macros incl. fat sub-types, plus micronutrients and per-meal Time). The export is one row per logged food (several per meal, no food-name column), so foods are summed into per-meal totals (nothing dropped). Schema extended per ADR-0007 (14 new Nutrition Log properties). Automating the export trigger (headless browser) is ToS-barred, so the operator taps MFP "Download Your Data"; everything after that tap is automated. The Gmail-relay auto-trigger (--gmail, IMAP + a Gmail App Password) is live and verified 2026-07-09: Primary User provisioned the GMAIL_APP_PASSWORD secret and the relay ran end-to-end (found the export email, downloaded it, aggregated + wrote the meal rows, labeled the email done; a re-run finds 0 unprocessed), fully hands-off; a manual --zip <export.zip> fallback also exists, and the graceful-skip when the secret is absent remains in code as a safety net. First ingest 2026-07-09: 24 days, 71 meal rows aggregated from 115 food-level export rows, idempotent. Operational evidence only; not yet covered by the formal V&V suite (increment verification is a G7 / follow-up item). No change to Must/Should/Could scope.