Files
HealthLog/docs/audit/v1425-summary.md
T

28 KiB
Raw Blame History

HealthLog v1.4.25 — release summary

Release brief

v1.4.25 is the largest feature delta in the v1.4.x line and the first time the loud / polish / foundation three-beat ran through a multi-cluster expansion on top of the v1.4.20-introduced develop-to-main release-merge model. Insights expands from a single mother page into seven dedicated metric sub-pages with a shared tab strip; GLP-1 medication tracking lands end-to-end across the dashboard tile, the weight-chart marker overlay, the therapy timeline, the plateau-detection rule in the daily briefing, the dedicated doctor-report section, a Research-Mode drug-level chart behind an MDR acknowledgment dialog, an EMA-sourced drug knowledge layer, the EMA titration ladder, cadence visualisation, compliance chips, a 21-entry by 5-category side-effect taxonomy, and a pen-and-vial inventory with a 30-day in-use clock; the cross-source priority resolver becomes a two-axis metric × deviceType lookup with a per-user Settings surface; per-user timezone threads through ten analytics and presentation surfaces; Withings coverage roughly doubles with twelve new measurement types, webhook-driven BP / temperature ingestion, plus the new Activity sync (steps + distance + active-energy) and Sleep v2 sync (stage-level segments); the onboarding flow rebuilds as a nested-route wizard with a welcome carousel, goals chip-picker, source selection grid, baseline form, and a welcome-back resume banner; Personal Records ship end-to-end with a pg-boss detection worker, push opt-in, and a metric-trend badge; Health Score gains a per-component provenance accordion; the Coach runs on native first-party prompts across all six locales bound by a 1800-assertion refusal-probe matrix on every push; the OpenAPI drift gate flips to hard-fail so the v1.5 iOS DTO codegen can rely on docs/api/openapi.yaml being authoritative; and the GHCR image is now multi-arch so Apple Silicon Macs and arm64 clouds pull native. Migrations 0043–0060 are additive and forward-only. PROMPT_VERSION 4.24.0 → 4.25.0 carries GROUND RULE 9 (Coach refuses GLP-1 dose recommendations) and GROUND RULE 15 (Coach refuses drug-level estimates with explicit EU MDR 2017/745 + MDCG 2021-24 cites in the refusal copy).

Live state

Field Value
URL https://healthlog.bombeck.io
/api/version 1.4.25
GH release https://github.com/MBombeck/HealthLog/releases/tag/v1.4.25
Branch model develop → main release-merge model, sixth tag through it (v1.4.20 onwards)
Tag commit 17b8d8d2 chore(release): v1.4.25
Predecessor v1.4.24 at ca03c609

What shipped

Insights expansion — seven dedicated metric sub-pages

/insights becomes a navigation hub. /insights/blutdruck, /insights/gewicht, /insights/puls, /insights/stimmung, /insights/medikamente, /insights/bmi and /insights/schlaf each render the metric's full chart, range bands, trend annotations and correlation rows beneath the mother-page hero. Tab strip lifts above each chart for cross-metric scanning. Targets (/insights/zielwerte) redesigns around a new <TargetCard> primitive with a conditional Coach-handoff card that hides cleanly in rule-based mode. Sleep sub-page renders awake / REM / core / deep as a stacked column over the last 7 / 14 / 30 nights, sourced from Measurement.sleepStage.

GLP-1 medication tracking — end-to-end across ten surfaces

Medication.treatmentClass enum (GLP1, STANDARD), MedicationDoseChange history table, an InjectionSite enum with eight site values, and a body-map picker that proposes the next rotation site from the last fourteen days. Dashboard tile carries next-injection schedule plus week-over-week weight delta. Weight chart gains vertical injection markers. Therapy timeline plots titration alongside the weight trace. Plateau-detection in /api/insights/briefing flags four-week stalls with referral framing. Doctor-report PDF gains a dedicated GLP-1 section. Drug-level chart on the medication detail page renders behind a Research-Mode gate; the acknowledgment dialog cites EU MDR 2017/745 + MDCG 2021-24, EMA EPAR and Schneck / Urva 2024 before the user can opt in. EMA titration ladder helpers walk the sourced schedule and frame as reference-not-advice. Cadence + compliance helpers expand the schedule into expected slots, pair each with the closest actual intake, and render a timeline + chip strip; honour per-user timezone so cross-midnight doses bucket correctly regardless of locale. Side-effect taxonomy (Migration 0059) covers 21 entries × 5 categories, severity Likert 1-5, with category derived server-side so the taxonomy cannot drift between client and server. Pen-and-vial inventory (Migration 0056) carries a SEALED → IN_USE → EXPIRED state machine with a 30-day in-use clock from markAsFirstUseAt; a daily 03:00 cron flips expired in-use items in one updateMany. State machine re-runs on every PATCH so a back-dated first-use immediately moves a stale pen to EXPIRED.

Cross-source priority — two-axis architecture

User.sourcePriorityJson (Migration 0048) stores the per-user resolver: a single-axis ladder by metric type plus an optional per-device-type override. pickCanonicalSource() walks the metric axis first; a per-device override (e.g. "BP from Withings BPM Connect, weight from Withings Body+") wins within that ladder. Defaults: cumulative + sleep + HRV + RHR favour Apple Health → Withings → manual; point measurements favour Withings → Apple Health → manual. The __default__ sentinel is retired in favour of a null bucket. Settings → Sources screen exposes the ladder for drag-reorder per metric and per-device override picker.

Per-user timezone — Option B threaded through ten surfaces

New User.timezone column defaults to Europe/Berlin. CSV exporter emits ISO-8601 with offset; formatters honour the user's tz; Profile picker covers all IANA zones; admin sets the default for new accounts; signup detects the browser tz; doctor-report PDF dates use the user's tz; chart x-axes take a timezone prop; Coach snapshot timestamps land in the user's tz; MoodEntry.tz records local-day grouping for weekday correlation (Migration 0044); the weight-weekday correlator buckets in the user's tz. Cadence + compliance helpers honour the same argument.

Withings — expanded coverage + Activity + Sleep v2

Twelve new MeasurementType values (HRV, body temperature, SpO2 v2, VO2 max, fat-free mass, fat mass, muscle mass, skin temperature, pulse-wave velocity, vascular age, visceral fat — Migration 0049). Webhook coverage extended to BP and temperature so the latency collapses from ~1 h polling to seconds. OAuth scope upgraded to include user.activity with an in-app reconnect banner. Activity sync calls getactivity, ingests one row per day, anchors at noon UTC so positive-offset users bucket cleanly into their local day. Sleep v2 sync calls sleepv2_get and writes per-night stage segments through the new sleepStage composite (Migration 0055 widens the Measurement unique index to include sleep_stage with NULLS NOT DISTINCT). Backed by pg-boss activity-sync and sleep-v2-sync queues plus webhook enqueue hooks on the new subscription channels.

Onboarding rebuild — six-step nested-route wizard

/onboarding/[step] powered by a new <OnboardingShell> primitive: value-prop carousel, goals chip-picker, source 4-card selection grid (Apple Health marked coming-soon), baseline form, source-connect step, done step. User.onboardingStep (Migration 0057, with Migration 0060 backfilling and flipping the column to NOT NULL DEFAULT 0) drives resume-state. A welcome-back banner surfaces on the entry page when an in-progress wizard is detected. POST /api/onboarding/step conditions the update on { id, onboardingStep: current, onboardingCompletedAt: null } and returns 409 on concurrent advance to close the read-then-write race.

Personal Records — schema, worker, badge, push opt-in

Migration 0054 introduces the PersonalRecord table + PersonalRecordDirection helper. GET /api/personal-records clamps ?limit (default twenty-five, max two hundred). A pg-boss worker sweeps MAX / MIN per metric and the workout slots on every batch-ingest plus a thirty-minute fallback cron (concurrency five; warmup gate so the very first datapoint per metric does not promote itself). Metric-trend tiles render a PR badge when the record landed in the last thirty days, with WCAG-AA contrast in dark mode. A per-user push opt-in toggle (default off) wires into the existing dispatcher cascade.

Workouts — schema + typed batch-ingest endpoint

Migration 0053 introduces Workout + WorkoutRoute tables; the Zod boundary in src/lib/validations/workout.ts covers a twenty-member sport-type union and a GeoJSON LineString route column in JSONB. POST /api/workouts/batch accepts up to five hundred rows per call, wraps withIdempotency(), returns the same inserted | duplicate | skipped envelope as the measurements batch, and reconciles inserted vs duplicate counts correctly under contention. Rate-limited, size-capped.

Coach — native first-party prompts across six locales

Coach + insights system prompts move from EN body + REPLY LANGUAGE footer to native per-locale bodies. The safety contract matrix lives as YAML per locale (single source of truth across drafting + tests). GROUND RULE 9 forbids GLP-1 dose recommendations; GROUND RULE 15 forbids drug-level estimates and cites EU MDR 2017/745 + MDCG 2021-24 in the refusal copy. The refusal-probe matrix in CI exercises 15 GROUND RULES across six locales with 20+ adversarial paraphrasings each — 1800+ assertions on every push. Drift-guard tests pin the YAML matrix in lockstep with the validator-derived enums.

OpenAPI drift gate — hard-fail flip

pnpm openapi:check CI step now red-bars a PR on any drift between the Zod registry and docs/api/openapi.yaml. The v1.4.23 warn-only window closes; iOS DTO codegen can rely on the spec being authoritative.

Multi-arch GHCR image + Coolify auto-deploy toggle

GHCR publish workflow builds linux/amd64 on ubuntu-latest plus linux/arm64 on ubuntu-24.04-arm and merges the manifest. Apple Silicon Macs and arm64 clouds pull native. The Coolify auto-deploy gate is now an explicit vars.COOLIFY_AUTO_DEPLOY=true|false maintainer toggle in the deploy workflow instead of the implicit secret-presence gate that silently no-op'd in v1.4.21-23.

Security cluster

WITHINGS_WEBHOOK_SECRET no longer lands as a URL path-segment in http.path on every Wide Event. The logging stack now carries a parameterised PATH_SECRET_PATHS registry seeded with the /api/withings/webhook/[token] shape; WideEventBuilder.setHttp rewrites path + route segments to [REDACTED] before they reach stdout / the in-memory ring buffer / Loki. Existing query-string redaction is unaffected. POST /api/medications/[id]/glp1 now parses through bounded Zod schemas, enforces length caps on notes, finite-number guards on dose value, bounded effectiveFrom, writes an auditLog row on every change and inherits the 30-per-minute-per- user rate limit from the rest of the medication surface. Batch-ingest endpoints (POST /api/measurements/batch, POST /api/workouts/batch, DELETE /api/measurements/by-external-ids) carry a sixty-per-minute-per-user token-bucket rate limit. Source- priority and doctor-report-prefs PUTs emit AuditLog rows.

Migrations

Migration Purpose
0051 measurement_device_type Adds deviceType enum + column to Measurement for the two-axis source-priority resolver.
0052 apple_health_enum_extensions Adds ENVIRONMENT_AUDIO_EXPOSURE, HEADPHONE_AUDIO_EXPOSURE and TIME_IN_DAYLIGHT to MeasurementType.
0053 workout_and_route Introduces Workout and WorkoutRoute tables for the typed workout-batch ingest endpoint and the v1.5 iOS workout sync.
0054 personal_record PersonalRecord table + PersonalRecordDirection helper. Unique index is NULLS DISTINCT by convention; the detection worker carries the application-level idempotency guard.
0055 measurement_sleepstage_composite Widens the Measurement unique index to include sleep_stage with NULLS NOT DISTINCT (Postgres 16 native) so Withings sleep v2 segments dedup correctly.
0056 medication_inventory_item MedicationInventoryItem table for the GLP-1 pen/vial inventory with the SEALED → IN_USE → EXPIRED state machine.
0057 user_onboarding_step Adds onboardingStep nullable to User for the wizard resume-state. Originally nullable; superseded by Migration 0060.
0058 user_research_mode Adds researchModeAck* columns to User for the GLP-1 Research-Mode MDR acknowledgment.
0059 medication_side_effect MedicationSideEffect table for the 21-entry × 5-category taxonomy.
0060 onboarding_step_not_null Backfills existing User.onboardingStep rows to 0 and flips the column to NOT NULL DEFAULT 0. Closes the tri-state ambiguity left by 0057.

All ten are additive and forward-only. Migration 0057's comment was rewritten to match PG11+ fast-path ADD COLUMN DEFAULT semantics during the reconcile pass.

Test coverage delta

Suite v1.4.24 v1.4.25 Delta
Unit 2 244 3 828 (across 344 files) +1 584
Integration 140 ~170 (across 11 files) +30

The unit-test growth is dominated by the Coach refusal-probe matrix (1800+ assertions across 15 GROUND RULES × 6 locales × 20+ paraphrasings) plus the feature-cluster helper suites: GLP-1 plateau-detection text formatter; two-axis source-priority resolution; source-priority Settings reducer; medication-card GLP-1 variant + injection-site-picker; doctor-report prefs PUT contract; personal-records pagination clamp; berlinIsoWeekday timezone-aware suite; sleep-stage chart i18n drift-guard; Health-Score provenance i18n drift-guard; api-handler private-field crash regression; pure cadence + compliance helpers with TZ assertions across UTC+0, UTC+9, UTC-8; side-effect taxonomy drift-guard; EMA titration ladder helpers; pen-inventory state-machine + 30-day clock helpers; PR detection worker (MAX / MIN per metric + workout slots + warmup gate

  • null-slot dup regression + zero-duration guard); Withings activity TZ regression across Berlin / Los Angeles / Tokyo / Auckland; Withings sleep v2 segment ingest; log-redaction path-segment rule + setHttp rewrite; GLP-1 endpoint Zod + audit + rate-limit; onboarding step concurrent-advance regression; inventory PATCH state-machine back-dated first-use regression; bulk-update contract for the expire-stale cron; brand-name guard + sentinel-preservation + safety-contract parity for the YAML matrix; locale auto-discovery + fallback-chain runtime guard.

Integration: two-axis canonical-source resolution end-to-end; requireAuth() narrow-scope on unscoped route; batch-ingest race reconciliation under contention; workout-batch race + size-cap + ingest end-to-end; PR-detection end-to-end; cross-source priority for Withings Activity + Apple Health; Withings sleep-stage composite ingest; per-user timezone end-to-end (Pacific/Auckland).

e2e green on the W2 CI fix (coach-prefs URL mock + Pixel-5 selector hardening) plus the Fix-I hot-fix that re-anchored the dashboard insight-card and the mobile x-axis tick locators class-independently. Typecheck clean. Lint baseline carried (no new warnings). OpenAPI drift-check clean against the regenerated spec.

Code quality gates

The W21 review ran eight read-only reviewers in parallel: code, security, design, senior-dev, simplifier, product-lead, dead-code, i18n-runtime. Combined output was 103 findings (2 Critical, 20 High, 41 Medium, 40 Low) plus a strategic product-lead assessment.

Critical (2 / 2 applied): sec-C1 (Withings webhook secret leaking into http.path on every Wide Event) and product-lead-C1 (CHANGELOG frozen at the initial release-prep surface, omitting the bulk of the later feature work). Both closed before tag — sec-C1 via Fix-J (PATH_SECRET_PATHS registry + setHttp redaction); product-lead-C1 via the W22 release-redo editorial pass.

High (20 / 20 applied): sec-H1 (GLP-1 endpoint missing Zod + audit

  • rate-limit) closed in Fix-K. Six design-Highs (onboarding tap targets, range-bar palette, PR-badge contrast) closed in Fix-L. Two code-Highs (inventory state machine bypass on PATCH, per-row expire loop) closed in Fix-M. Seven simplifier-Highs (readError dup, templateFill, statusLabel nested ternary, ResearchModeStatus shared type, findDrugIdByBrand, assertMedicationOwnership across 11 routes, MedicationInventoryState import) closed in Fix-N. Code-H2 (cadence + compliance ignore per-user timezone) closed in Fix-O. Dead-H4 (research-mode-staleness module never wired) resolved by deletion in Fix-O. One product-lead-H1 (test count footer stale) and product-lead-H2 (Deferred-to-v1.4.26 section lists already-shipped items) closed in W22.

Medium (17 of 41 applied, 24 deferred to v1.4.26): 17 ship-now Mediums landed across Fix-J through Fix-O; the deferred 24 split between schema-shape decisions (User.onboardingGoals column; /api/audit-log consumer decision), module-surface narrowing (glp1-pk.ts, glp1-knowledge.ts, scheduling/* unused exports), 148 remaining dead i18n keys after the W15 380-key sweep, and seven orphan endpoint go / no-go decisions that need maintainer call. Full deferrals matrix lives in .planning/phase-W21-reconcile-plan.md lines 220-265.

Low (40 / 40 deferred to v1.4.27): appendix in the reconcile plan covers them — none are user-facing; one (i18n-Low-1, e2e healthlog_locale vs healthlog-locale cookie typo) was opportunistically picked up in Fix-P because the touch was a single character.

Seven touch-disjoint Fix-J through Fix-P surfaces totalling 22 atomic commits ran across develop between the W21 audit and the W22 release-prep. Three sequenced merge windows preserved touch-disjoint diffs without conflict (Fix-O before Fix-N on the cadence route; Fix-L before Fix-N on the onboarding components; Fix-M before Fix-O on the PR worker test). No file had two agents editing the same lines.

Strategic posture

v1.5 iOS readiness

The iOS sprint has the contracts it needs to start Day 1. Locked server contracts after v1.4.25:

  • POST /api/measurements/batch — Apple Health bulk ingest with inserted | duplicate | skipped per-entry envelope, idempotency wrapper, rate-limited (v1.4.23, unchanged here).
  • DELETE /api/measurements/by-external-ids — HealthKit deletion-sync (new in v1.4.25).
  • POST /api/workouts/batch — HKWorkout-aligned typed ingest with 20-sport-type union + GeoJSON LineString routes (new in v1.4.25).
  • POST /api/devices — APNs token registration with paired apnsEnvironment (v1.4.23, unchanged).
  • POST /api/onboarding/step — wizard progression with rate limit + audit + 409-on-concurrent (new in v1.4.25).
  • GET /api/personal-records?metricType=X — paginated PR reads.
  • User.sourcePriorityJson two-axis resolver with pickCanonicalSource() — iOS sets Apple Health as the cumulative + sleep + HRV + RHR favourite; Withings stays the point-measurement default.
  • Measurement.deviceType enum with iOS-17/18 HK long-tail mappings ready to extend.
  • MedicationInventoryItem — pen/vial 30-day clock available for an iOS pen-scanner integration.
  • Workout + WorkoutRoute tables (the table-side; endpoint signature finalised during the iOS sprint).
  • docs/api/openapi.yaml regenerates byte-identically from the Zod registry; the drift gate is now hard-fail.

MDR boundary preservation

The GLP-1 Research-Mode surface ships with three concentric defences: chart gating (User.researchModeAck* columns require an active acknowledgment before render), dialog acknowledgment (cites EU MDR 2017/745, MDCG 2021-24, EMA EPAR and Schneck / Urva 2024 before the user can opt in; version-bump re-prompts), and Coach refusal at the prompt layer (GROUND RULE 15 across all six locales, refusal-probe matrix in CI). The titration ladder display is framed as reference-not-advice and bound by the same GROUND RULE 15. Drug-level chart-side 90-day staleness wiring stayed deferred for v1.4.26 (the helper module shipped tested in W19c-Safety but the chart conditional isn't wired — the unused helper was deleted during Fix-O after the reconcile pass; the 90-day gate becomes a clean v1.4.26 surface when the maintainer decides to wire it).

Branch model

develop is the daily target; main is release-only and follows tags. v1.4.25 is the sixth tag through the develop-to-main release-merge model introduced in v1.4.20 F1. GHCR auto-deploy fires only on main; the explicit vars.COOLIFY_AUTO_DEPLOY=true|false toggle closes the silent-miss pattern that hit v1.4.21 / v1.4.22 / v1.4.23.

0-10 score per area

Area Score Note
Insights 9 Seven-sub-page split lands cleanly; Targets redesign with conditional Coach-handoff is the tightest the layout has been; mother page slims to general status + Coach hero. Half-point off for the duplicate StatusCard regression that needed a Fix-I hotfix mid-release.
Dashboard 9 Top-tile polish (single-line headings, inline trend arrow, baseline alignment across tiles) closes the v1.4.24 reviewer note; comparison-overlay default removed in favour of per-chart preference; VO2 max secondary-metric tile lands as opt-in.
Coach 9 Native per-locale prompts replace the REPLY LANGUAGE footer across six locales; GROUND RULE 9 + GROUND RULE 15 close the MDR boundary at the prompt layer; 1800+ refusal-probe assertions in CI on every push. Half-point off for FR/ES/IT/PL prose still being LLM-drafted (structural matrix covers safety; the prose itself benefits from a native human pass — queued for v1.4.26).
Settings 8 Source-priority screen ships with drag-reorder + per-device override + audit-log; doctor-report per-section toggles + mood-default-off lands; Research-Mode toggle with version re-prompt banner lands. Single point off for the settings-cog vs per-message-controls debate (v1.4.23 carryover) still unresolved.
Admin 8 Login overview gains location + provider columns + CSV polish; coach-feedback header layout shift closed; notification-status-card icon parity restored; mobile admin nav gains Overview link. Two points off for the seven orphan endpoint go / no-go decisions still pending a maintainer call.
Mobile (web) 8 44-px touch-target floor across onboarding wizard, top-bar, section strips and injection-site picker hits WCAG 2.5.5; dashboard tile baseline alignment regression-pinned. Two points off because the e2e workflow needed the Fix-I hot-fix re-anchor on dashboard insight-text + chart-tick locators (now class-independent).
Tests 9 2 244 → 3 828 unit (+1 584); 140 → ~170 integration; new drift-guards across Apple Health mapping, side-effect taxonomy triangle, sleep-stage chart i18n, Health-Score provenance, safety-contract YAML matrix, plus per-user TZ regressions and the 1800-assertion refusal-probe matrix. Half-point off for the two pre-existing coach-prefs.test.ts NextRequest URL mock failures still carried from v1.4.23.
CI 9 OpenAPI drift gate flips to hard-fail; refusal-probe matrix runs on every push; multi-arch GHCR builds clean after the Fix-G/H lowercase fix-up; explicit vars.COOLIFY_AUTO_DEPLOY toggle closes the silent-miss pattern. Half-point off for the Fix-H lowercase regression that needed catching post-PR-open.
Docs 9 CHANGELOG expand in W22 brings the public artifact in lockstep with what shipped; per-section delta is complete; deferred-to-v1.4.26 / v1.5 sections are accurate. Half-point off because the W22 reconcile was the C-1 Critical of the release and only ran after the W21 product-lead caught it.
Repo hygiene 9 380 dead i18n keys dropped; dead prompt constants removed; <InsightsPageHero> + <IntakeTimeline> + <ComplianceCharts> + orphan query keys + /api/insights/general-status orphan all gone; MedicationDetailSection wrapper + shared route-guards / read-error / dose-string / research-mode-types modules collapse 11+ duplications. Half-point off for the 148 remaining dead i18n keys queued for a v1.4.26 second-pass.
Demo readiness 8 Multi-arch image is live so the demo VPS pulls native arm64; W11b demo-deploy report covers the runbook; OpenAPI spec is authoritative for iOS DTO codegen. Two points off because the demo seeding still depends on the manual host-side fallback when Coolify auto-deploy is toggled off, and because the iOS Swift app itself is queued for v1.5 (the demo is web-only until then).

v1.4.26 backlog

24 deferred Mediums + 40 Lows + maintainer-decision items split across the following themes:

  • User.onboardingGoals schema column + server-side persistence (today the goals chip-picker holds the choice client-side only; the dashboard-widgets seed feature reads from it in v1.4.26).
  • advance() hook extraction across the three onboarding step components (simplifier surfaced; deferred to avoid collision with the v1.4.25 touch-target pass).
  • 148 dead i18n keys remaining after the W15 380-key sweep (need a second-pass call-site verification).
  • Drug-level chart-side 90-day staleness clock wiring (acknowledgment dialog already re-prompts on version bump and Coach refuses at GROUND RULE 15; the clock is defence-in-depth).
  • FR / ES / IT / PL Coach + insights prose hand-review by native speakers (structural refusal-probe matrix covers safety; the user- facing prose benefits from a human pass).
  • Sleep sub-page stacked-column visual polish (stage colours + legend density).
  • VO2 max chart-row card on /insights/<metric> (dashboard tile shipped; chart card queued alongside the iOS body-composition page).
  • Mood verbal-labels persistence behind a per-user toggle.
  • Coach lastYear baseline + row-tap-to-prefill polish.
  • Lazy-loaded locale JSON bundles (all six locales import synchronously today, ~675 KB to every client).
  • iOS-18 long-tail HK identifier mappings (sleep apnea, GAD-7 / PHQ-9, running form, paddle / row / ski distances, pregnancy / cycle, FHIR clinical).
  • Seven orphan endpoint go / no-go decisions (/api/admin/ai-settings, /api/admin/backup/test, /api/admin/status-overview, /api/monitoring/{glitchtip,umami}/test).
  • glp1-pk.ts and glp1-knowledge.ts unused-export decisions (internalise vs wire dashboard chip).
  • Pearson incomplete-beta replacement (v1.4.23 carryover already partially closed with the conservative MIN_PAIRED_N raise — the rigorous replacement is the v1.4.26 candidate before correlation auto-discovery widens in v1.5/v1.6).

Carry-overs

  • The two pre-existing coach-prefs.test.ts NextRequest URL mock failures still carry through from v1.4.23. Tracked in .planning/v1426-backlog.md; non-blocking for the release.
  • Manual-workout route findFirst serial pattern stays in place (no manual workout UI today; contract correctness only matters once v1.5 UI lands).
  • The Coolify auto-deploy MCP API path still fires force=true and reports "finished" in ~18 seconds without a real docker pull, but the new vars.COOLIFY_AUTO_DEPLOY toggle plus the "Watch image registry for new digests" UI checkbox capture the durable fix; the host-side retag fallback recipe lives in .planning/coolify-auto-deploy-howto.md for the cases where the toggle is off.

Strategic next

The v1.5 sprint starts with iOS first launch (login + dashboard + widget) against locked server contracts — pure Swift work, zero server-side touches. P2 (Apple Health sync) calls the v1.4.23 POST /api/measurements/batch against the v1.4.25 device-type + two-axis resolver. P3 (Coach extended for HRV / sleep / resting HR / steps) ratchets PROMPT_VERSION 4.25.0 → 5.0.0 and copies the web <CoachDrawer> UX to iOS. P4 (per-metric APNs alerts) leans on the v1.4.23 APNs scaffolding for the send-side. P5 (workouts + GeoJSON routes) calls the v1.4.25 POST /api/workouts/batch against the shipped Workout + WorkoutRoute tables.