mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
chore(release): expand v1.4.25 with Wave 4-5 and reconcile features
Rewrites the v1.4.25 CHANGELOG section to cover the ~90 commits since v1.4.24 across onboarding rebuild, GLP-1 medication tracking end-to-end (drug knowledge, Research Mode with MDR acknowledgment dialog, estimated drug-level chart, side-effect taxonomy, cadence + compliance, EMA titration ladder, pen-and-vial inventory with a 30-day clock), Personal Records detection worker + badge + push opt-in, workout batch ingest, Withings Activity + Sleep v2 syncs, EMA drug knowledge layer, log-redaction path-segment rule that closes the Withings webhook secret leak, GLP-1 convenience endpoint hardening, native first-party Coach + insights system prompts across six locales with a refusal-probe matrix, OpenAPI drift-gate hard-fail flip, 380 dead i18n keys removed, shared helpers + section wrapper consolidations, dashboard top-tile polish, design polish to WCAG 2.5.5 + AA contrast. Updates the test count footer to the current 3828 unit / 344 files / ~170 integration / 9 new migrations (0051-0059) + 1 hardening (0060). Adds the refusal-probe matrix metrics (1800+ assertions x 15 GROUND RULES x 6 locales x 20+ paraphrasings). Replaces the stale "Deferred to v1.4.26" section. Items that already shipped in Wave 4-5 (OpenAPI hard-flip, onboarding rebuild, native FR/ES/IT/PL Coach prompts, PR detection worker, workout ingest, Withings Activity + Sleep v2) are out of the deferred list and into Added / Changed / Fixed / Security / Refactor. The remaining v1.4.26 backlog reads accurately.
This commit is contained in:
1 parent
068b49e709
commit
49f71c9215
1 file changed
+467
-95
+467
-95
@@ -4,18 +4,29 @@
|
|||||||
|
|
||||||
Largest feature delta in the v1.4.x line. Insights expands from one
|
Largest feature delta in the v1.4.x line. Insights expands from one
|
||||||
page into seven dedicated metric routes; GLP-1 medication tracking
|
page into seven dedicated metric routes; GLP-1 medication tracking
|
||||||
lands end-to-end from injection picker through dashboard tile, weight-
|
lands end-to-end across injection picker, dashboard tile, weight-chart
|
||||||
chart markers, therapy timeline, plateau detection and doctor-report
|
markers, therapy timeline, plateau detection, drug-level chart with a
|
||||||
section; cross-source priority becomes a two-axis resolver with a
|
Research-Mode acknowledgment gate, EMA-sourced drug knowledge, EMA
|
||||||
per-user Settings surface; per-user timezone threads through ten
|
titration ladder, cadence visualisation, compliance chips, side-effect
|
||||||
analytics and presentation surfaces; Withings coverage doubles with
|
taxonomy, pen-and-vial inventory with a 30-day in-use clock, and a
|
||||||
twelve new measurement types and webhook-driven BP/temperature
|
dedicated doctor-report section; cross-source priority becomes a
|
||||||
ingestion; Health-Score gains a per-component provenance accordion;
|
two-axis resolver with a per-user Settings surface; per-user timezone
|
||||||
four AI-translated locales (FR / ES / IT / PL) ship behind a
|
threads through ten analytics and presentation surfaces; Withings
|
||||||
maintainership banner; the GHCR image is now multi-arch so Apple
|
coverage doubles with twelve new measurement types, webhook-driven
|
||||||
Silicon Macs and arm64 clouds pull native. Migrations 0044–0054 are
|
BP / temperature ingestion, plus Activity (steps + distance +
|
||||||
all additive and forward-only. `PROMPT_VERSION` 4.24.0 → 4.25.0 with
|
active-energy) and Sleep v2 (stage-level segments) syncs; the
|
||||||
GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
onboarding flow is rebuilt as a nested-route wizard with welcome
|
||||||
|
carousel, goals chip-picker, source selection grid, baseline form,
|
||||||
|
and a welcome-back resume banner; Personal Records ship end-to-end
|
||||||
|
with a 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 with a
|
||||||
|
1800-assertion refusal-probe matrix; the OpenAPI drift gate flips to
|
||||||
|
hard-fail; the GHCR image is 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 with GROUND RULE 9
|
||||||
|
(Coach refuses GLP-1 dose recommendations) and GROUND RULE 15 (Coach
|
||||||
|
refuses drug-level estimates with MDR + MDCG 2021-24 cites).
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
@@ -31,13 +42,13 @@ GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
|||||||
`/insights/schlaf` renders awake / REM / core / deep as stacked
|
`/insights/schlaf` renders awake / REM / core / deep as stacked
|
||||||
columns over the last 7 / 14 / 30 nights, sourced from the
|
columns over the last 7 / 14 / 30 nights, sourced from the
|
||||||
`sleepStage` column on `Measurement`.
|
`sleepStage` column on `Measurement`.
|
||||||
- **Targets (`/insights/zielwerte`) redesigned — 10-phase rewrite
|
- **Targets (`/insights/zielwerte`) redesigned with a conditional
|
||||||
with a conditional Coach-handoff card.** New `<TargetCard>`
|
Coach-handoff card.** New `<TargetCard>` primitive replaces the
|
||||||
primitive replaces the v1.4.22 layout. Page-level consistency
|
v1.4.22 layout. Page-level consistency strip pins meta context
|
||||||
strip pins meta context above the cards. The Coach-handoff card
|
above the cards. The Coach-handoff card only renders when a
|
||||||
only renders when an AI provider is configured; rule-based mode
|
language-model provider is configured; rule-based mode hides it
|
||||||
hides it cleanly. Mobile-first three-column grid; per-card cog
|
cleanly. Mobile-first three-column grid; per-card cog for
|
||||||
for visibility toggles.
|
visibility toggles.
|
||||||
- **GLP-1 medication tracking — full integration across ten
|
- **GLP-1 medication tracking — full integration across ten
|
||||||
surfaces.** New `Medication.treatmentClass` enum (`GLP1`,
|
surfaces.** New `Medication.treatmentClass` enum (`GLP1`,
|
||||||
`STANDARD`); `MedicationDoseChange` history table; `InjectionSite`
|
`STANDARD`); `MedicationDoseChange` history table; `InjectionSite`
|
||||||
@@ -87,25 +98,110 @@ GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
|||||||
Health / manual) and `asOf` timestamp behind the score number.
|
Health / manual) and `asOf` timestamp behind the score number.
|
||||||
`aria-labelledby` panel pairing for screen readers.
|
`aria-labelledby` panel pairing for screen readers.
|
||||||
- **Four additional locales — French, Spanish, Italian, Polish.**
|
- **Four additional locales — French, Spanish, Italian, Polish.**
|
||||||
AI-initial translation bundles plus `<MaintainershipBanner>` on
|
First-party translation bundles cover the full string surface
|
||||||
every page that warns the locale is not actively maintained and
|
with a `<MaintainershipBanner>` flagging the locale as
|
||||||
links to a GitHub issue for corrections. EN + DE stay maintained;
|
community-maintained and pointing at the translation-feedback
|
||||||
FR / ES / IT / PL ride the EN Coach + insights system prompts
|
issue template. Coach + insights system prompts ship as native
|
||||||
via a one-line `REPLY LANGUAGE` footer until native rewrites
|
per-locale bodies (no `REPLY LANGUAGE` footer indirection) with
|
||||||
ship. Locale picker covers all six; signup browser-detect maps
|
the full safety-contract matrix in YAML per locale + structural
|
||||||
`fr|es|it|pl` to the corresponding bundle.
|
refusal-probe coverage in CI (see Tests). EN + DE stay
|
||||||
|
Marc-maintained. Locale picker covers all six; signup
|
||||||
|
browser-detect maps `fr|es|it|pl` to the corresponding bundle.
|
||||||
|
- **Coach — native first-party system 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). The refusal-probe matrix in CI catches
|
||||||
|
cross-locale prompt regressions before they reach the dispatch
|
||||||
|
surface.
|
||||||
- **VO2 max dashboard trend tile (opt-in).** Secondary-metric
|
- **VO2 max dashboard trend tile (opt-in).** Secondary-metric
|
||||||
pattern — default-invisible, surfaces only when the user has
|
pattern — default-invisible, surfaces only when the user has
|
||||||
VO2 max data from Apple Health.
|
VO2 max data from Apple Health.
|
||||||
- **Personal-record schema + listing endpoint.** Migration 0054
|
- **Personal Records end-to-end — schema, detection worker, badge,
|
||||||
+ `PersonalRecord` table + `PersonalRecordDirection` helper
|
push opt-in.** Migration 0054 introduces the `PersonalRecord`
|
||||||
+ `GET /api/personal-records` (paginated). Detection worker
|
table + `PersonalRecordDirection` helper; `GET
|
||||||
deferred to v1.4.26; the table is queryable today.
|
/api/personal-records` is paginated (default twenty-five, max two
|
||||||
- **Workout + WorkoutRoute schema (HKWorkout-aligned).**
|
hundred). A pg-boss worker sweeps MAX / MIN per metric and the
|
||||||
Migration 0053 + Zod boundary in `src/lib/validations/workout.ts`
|
workout slots on every batch-ingest + a thirty-minute fallback
|
||||||
with a twenty-member sport-type union and a `GeoJSON LineString`
|
cron (concurrency five, warmup gate so the very first datapoint
|
||||||
route column in JSONB. Ingest endpoint scheduled to land
|
per metric does not promote itself). Metric trend tiles render a
|
||||||
alongside the v1.5 iOS client.
|
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 the `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 and size-capped.
|
||||||
|
- **Onboarding rebuilt as a nested-route wizard.** The legacy
|
||||||
|
v1.4.20 onboarding ships as a six-step wizard at
|
||||||
|
`/onboarding/[step]` powered by a new `<OnboardingShell>`
|
||||||
|
primitive: welcome carousel with value-prop slides, goals
|
||||||
|
chip-picker, source selection 4-card grid (with Apple Health
|
||||||
|
marked coming-soon), baseline form, source-connect step, and a
|
||||||
|
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` advances the wizard with
|
||||||
|
rate-limit + audit, returns 409 on a concurrent advance to close
|
||||||
|
the read-then-write race. The marketing entry-point swaps from
|
||||||
|
the v1.4.20 single-page flow to the new wizard. Five locales
|
||||||
|
carry the shell key surface (six total).
|
||||||
|
- **GLP-1 — EMA drug knowledge layer.** A first-party drug-knowledge
|
||||||
|
module covers five GLP-1 / GIP-GLP-1 drugs with EPAR-sourced
|
||||||
|
half-life, recommended titration step, brand-name table, and a
|
||||||
|
brand-to-id lookup. A drift-guard test pins the values against
|
||||||
|
the EPAR + Psp 4.13099 references on disk so the module cannot
|
||||||
|
silently drift.
|
||||||
|
- **GLP-1 — Research Mode with estimated drug-level chart, MDR
|
||||||
|
acknowledgment dialog, and Settings toggle.** A pure
|
||||||
|
one-compartment pharmacokinetic helper produces qualitative
|
||||||
|
drug-level traces from the user's injection history (steady-state
|
||||||
|
approximation, observational use only). The chart renders on the
|
||||||
|
GLP-1 medication detail page behind a Research-Mode gate:
|
||||||
|
`User.researchModeAck*` columns (Migration 0058) record the
|
||||||
|
acknowledgment version + timestamp; a dialog explains the
|
||||||
|
EU MDR 2017/745 + MDCG 2021-24 context and cites EMA EPAR plus
|
||||||
|
Schneck / Urva 2024 before the user can opt in.
|
||||||
|
`GET / POST / DELETE /api/auth/me/research-mode` carries the
|
||||||
|
acknowledgment lifecycle. A Settings → Advanced toggle exposes
|
||||||
|
the opt-in plus a re-prompt banner whenever the acknowledgment
|
||||||
|
version bumps.
|
||||||
|
- **GLP-1 — side-effect logging with a 21-entry × 5-category
|
||||||
|
taxonomy.** Migration 0059 introduces the `MedicationSideEffect`
|
||||||
|
table; pure helpers produce the taxonomy + a five-point Likert
|
||||||
|
severity scale; a section on the GLP-1 detail page lets the user
|
||||||
|
log entries with category + severity + free-text notes. Category
|
||||||
|
is derived server-side from the entry (no client-supplied
|
||||||
|
category) so the taxonomy cannot drift between client and server.
|
||||||
|
- **GLP-1 — cadence visualisation + compliance chips.** Pure
|
||||||
|
helpers expand a medication's schedule into expected slots,
|
||||||
|
pair each slot with the closest actual intake, and produce a
|
||||||
|
cadence timeline + compliance chip strip on the detail page.
|
||||||
|
`GET /api/medications/[id]/cadence` returns the structured
|
||||||
|
payload; the helpers honour per-user timezone so cross-midnight
|
||||||
|
doses bucket correctly regardless of locale.
|
||||||
|
- **GLP-1 — EMA titration ladder display.** Pure helpers walk the
|
||||||
|
EMA-sourced titration schedule from the knowledge layer; the
|
||||||
|
GLP-1 detail page renders the user's current step + remaining
|
||||||
|
ladder as observational reference, framed as reference-not-advice
|
||||||
|
and bound by GROUND RULE 15. `GET
|
||||||
|
/api/medications/[id]/titration-ladder` returns the structured
|
||||||
|
ladder + current step.
|
||||||
|
- **GLP-1 — pen-and-vial inventory with a 30-day in-use clock.**
|
||||||
|
Migration 0056 introduces the `MedicationInventoryItem` table +
|
||||||
|
a pure state machine (SEALED → IN_USE → EXPIRED) with a 30-day
|
||||||
|
in-use clock from `markAsFirstUseAt`. An inventory card on the
|
||||||
|
medication detail page surfaces the active pen, days remaining,
|
||||||
|
and SEALED stock; intake events decrement the dose count, and a
|
||||||
|
daily 03:00 cron flips expired in-use items in a single
|
||||||
|
`updateMany`. Re-runs the state machine on every PATCH so a
|
||||||
|
back-dated first-use immediately moves a stale pen to EXPIRED.
|
||||||
- **Apple Health identifier mapping (server-side).** Ports the
|
- **Apple Health identifier mapping (server-side).** Ports the
|
||||||
identifier table from `k0rventen/apple-health-grafana` and
|
identifier table from `k0rventen/apple-health-grafana` and
|
||||||
`dogsheep/healthkit-to-sqlite` with MIT and Apache-2.0
|
`dogsheep/healthkit-to-sqlite` with MIT and Apache-2.0
|
||||||
@@ -127,6 +223,21 @@ GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
|||||||
the latency goes from ~1 h polling to seconds. OAuth scope
|
the latency goes from ~1 h polling to seconds. OAuth scope
|
||||||
upgraded to include `user.activity` and an in-app banner
|
upgraded to include `user.activity` and an in-app banner
|
||||||
prompts existing users to reconnect once.
|
prompts existing users to reconnect once.
|
||||||
|
- **Withings — Activity sync (steps + distance + active-energy).**
|
||||||
|
Calls `getactivity`, ingests one row per day, anchors at noon UTC
|
||||||
|
so positive-offset users bucket cleanly into their local day.
|
||||||
|
Backed by a pg-boss `activity-sync` queue plus a webhook enqueue
|
||||||
|
hook on the new subscription channel.
|
||||||
|
- **Withings — Sleep v2 sync (stage-level segments).** 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 a pg-boss `sleep-v2-sync` queue plus webhook enqueue.
|
||||||
|
The sleep sub-page's stacked-bar chart renders the segments
|
||||||
|
directly.
|
||||||
|
- **Withings — webhook subscriptions expanded to activity + sleep
|
||||||
|
v2.** Subscription registration plus webhook delivery routing for
|
||||||
|
the two new event types.
|
||||||
- **Admin Login overview — location, provider and CSV polish.**
|
- **Admin Login overview — location, provider and CSV polish.**
|
||||||
Adds a location column derived from the audit IP; adds a
|
Adds a location column derived from the audit IP; adds a
|
||||||
provider column distinguishing passkey, password, API-token
|
provider column distinguishing passkey, password, API-token
|
||||||
@@ -141,6 +252,16 @@ GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
|||||||
`ubuntu-24.04-arm` and merges the manifest. Apple Silicon
|
`ubuntu-24.04-arm` and merges the manifest. Apple Silicon
|
||||||
Macs and arm64 clouds now pull native; the previously-stale
|
Macs and arm64 clouds now pull native; the previously-stale
|
||||||
README claim is accurate again.
|
README claim is accurate again.
|
||||||
|
- **GLP-1 endpoint hardening.** `POST
|
||||||
|
/api/medications/[id]/glp1` now parses through bounded Zod
|
||||||
|
schemas (`glp1DoseChangePostSchema`, `glp1InventoryPostSchema`)
|
||||||
|
with length-capped notes, finite-number guards on dose value,
|
||||||
|
and bounded `effectiveFrom`. Every write produces an audit-log
|
||||||
|
row and the route inherits the 30-per-minute-per-user rate
|
||||||
|
limit from the rest of the medication surface.
|
||||||
|
- **Translation-feedback issue template.** GitHub issue template
|
||||||
|
for community translation corrections, paired with the
|
||||||
|
maintainership banner copy on FR / ES / IT / PL surfaces.
|
||||||
- **Repository polish.** README hero rewrite (what / who / try
|
- **Repository polish.** README hero rewrite (what / who / try
|
||||||
the demo, thirty-second read). Topics expanded 10 → 18.
|
the demo, thirty-second read). Topics expanded 10 → 18.
|
||||||
Branch protection v2 with conversation-resolution. GitHub
|
Branch protection v2 with conversation-resolution. GitHub
|
||||||
@@ -156,7 +277,7 @@ GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
|||||||
- **Targets page-shell unified with the rest of Insights.**
|
- **Targets page-shell unified with the rest of Insights.**
|
||||||
Single consistency strip + Coach handoff + per-card actions
|
Single consistency strip + Coach handoff + per-card actions
|
||||||
rather than the v1.4.22 sparkline-everywhere layout.
|
rather than the v1.4.22 sparkline-everywhere layout.
|
||||||
- **AI Coach default-window preference plus chip-order rationalised.**
|
- **Coach default-window preference plus chip-order rationalised.**
|
||||||
The window picker now persists per-user (last seven / thirty /
|
The window picker now persists per-user (last seven / thirty /
|
||||||
ninety days); suggested-prompt chips reorder so health-focus
|
ninety days); suggested-prompt chips reorder so health-focus
|
||||||
chips lead and meta-discovery chips trail. Composer auto-grows
|
chips lead and meta-discovery chips trail. Composer auto-grows
|
||||||
@@ -177,9 +298,47 @@ GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
|||||||
three sections.** Every section header pairs an icon with a
|
three sections.** Every section header pairs an icon with a
|
||||||
heading; the v1.4.24-era split (icon-only on some, heading-only
|
heading; the v1.4.24-era split (icon-only on some, heading-only
|
||||||
on others) is gone.
|
on others) is gone.
|
||||||
- **`PROMPT_VERSION` 4.24.0 → 4.25.0** with new GROUND RULE 9
|
- **`PROMPT_VERSION` 4.24.0 → 4.25.0** carries two new safety
|
||||||
in EN + DE forbidding GLP-1 dose recommendations. Coach falls
|
ground rules across all six locales: GROUND RULE 9 forbids GLP-1
|
||||||
back to a clinical-referral framing on any dose question.
|
dose recommendations (Coach falls back to a clinical-referral
|
||||||
|
framing on any dose question); GROUND RULE 15 forbids drug-level
|
||||||
|
estimates and cites EU MDR 2017/745 + MDCG 2021-24 in the
|
||||||
|
refusal copy. Coach + insights system prompts ship as native
|
||||||
|
bodies per locale rather than the legacy `REPLY LANGUAGE`
|
||||||
|
footer.
|
||||||
|
- **Dashboard top-tile polish.** Tile headings collapse to a
|
||||||
|
single line per locale (BP / BF abbreviations land in EN + DE +
|
||||||
|
the four Romance locales); the trend arrow moves inline next to
|
||||||
|
the headline value; the value row baseline-aligns across tiles
|
||||||
|
regardless of font fallback. Regression guard pins the baseline
|
||||||
|
contract.
|
||||||
|
- **OpenAPI drift gate flips to hard-fail.** `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.
|
||||||
|
- **Coolify auto-deploy gate exposed as an explicit
|
||||||
|
maintainer-toggleable repo variable.** `vars.COOLIFY_AUTO_DEPLOY`
|
||||||
|
is now a `true | false` switch in the deploy workflow instead of
|
||||||
|
the implicit secret-presence gate that silently no-op'd in
|
||||||
|
v1.4.21-23.
|
||||||
|
- **Settings → Sources sentinel cleanup.** The `__default__`
|
||||||
|
device-type bucket sentinel is retired in favour of a null
|
||||||
|
bucket at the storage layer; the Settings UI reads cleaner and
|
||||||
|
the reorder helpers (`reorderLadder`) collapse the two
|
||||||
|
`moveSource` + `moveDeviceType` paths into one.
|
||||||
|
- **Section wrapper for medication detail.** A new
|
||||||
|
`<MedicationDetailSection>` wraps the three medication-detail
|
||||||
|
shells (titration, scheduling, side-effects) plus the inventory
|
||||||
|
disclosure top so cross-section chrome stays consistent and
|
||||||
|
future sections drop in without copy-paste.
|
||||||
|
- **Shared route ownership helper.** Nine medication routes
|
||||||
|
(`titration`, `side-effects`, `inventory`, `cadence`, `intake`,
|
||||||
|
`compliance`, `phase-config`, `api-endpoint`, plus the GLP-1
|
||||||
|
convenience route) now call `assertMedicationOwnership` from
|
||||||
|
`src/lib/medications/route-guards.ts` rather than open-coding
|
||||||
|
the lookup; rate-limit headers across the same surface align
|
||||||
|
on the option-bag form `apiError(..., { headers:
|
||||||
|
rateLimitHeaders(rl) })`.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@@ -192,13 +351,14 @@ GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
|||||||
was subtracting the wrong-period baseline on several charts;
|
was subtracting the wrong-period baseline on several charts;
|
||||||
baseline lookups now match the caption window. Three regression
|
baseline lookups now match the caption window. Three regression
|
||||||
guards.
|
guards.
|
||||||
- **AI prose metric-token leaks** — `metric:<TYPE>` raw tokens
|
- **Raw metric-token leaks in generated prose** — `metric:<TYPE>`
|
||||||
surfaced in three places that escaped the v1.4.22 sweep
|
identifiers surfaced in three surfaces that escaped the v1.4.22
|
||||||
(`<RecommendationCard>` fallback path, briefing keyFinding
|
sweep (`<RecommendationCard>` fallback path, briefing
|
||||||
helper, and Coach in-flight bubble). `stripChartTokens()` regex
|
`keyFinding` helper, and Coach in-flight bubble).
|
||||||
widened to cover lowercase prose remnants; prompt-side GROUND
|
`stripChartTokens()` regex widened to cover lowercase prose
|
||||||
RULES 8 and 13 reaffirm the constraint. PROMPT_VERSION 4.23.0
|
remnants; prompt-side GROUND RULES 8 and 13 reaffirm the
|
||||||
→ 4.24.0 carried the prompt change; 4.25.0 inherits.
|
constraint. PROMPT_VERSION 4.23.0 → 4.24.0 carried the prompt
|
||||||
|
change; 4.25.0 inherits.
|
||||||
- **Withings BP and temperature webhook latency.** Webhook
|
- **Withings BP and temperature webhook latency.** Webhook
|
||||||
subscription now covers BP and temperature endpoints, so the
|
subscription now covers BP and temperature endpoints, so the
|
||||||
earliest a measurement reaches the user drops from ~1 h to
|
earliest a measurement reaches the user drops from ~1 h to
|
||||||
@@ -260,19 +420,135 @@ GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
|||||||
- **Personal-records endpoint unpaginated.** `GET
|
- **Personal-records endpoint unpaginated.** `GET
|
||||||
/api/personal-records` now clamps `?limit` (default twenty-five,
|
/api/personal-records` now clamps `?limit` (default twenty-five,
|
||||||
maximum two hundred); the unbounded read is gone.
|
maximum two hundred); the unbounded read is gone.
|
||||||
|
- **Withings activity sync bucketed positive-offset users into the
|
||||||
|
wrong day.** The per-day row was anchored at 23:59:59 UTC, so a
|
||||||
|
user in `Pacific/Auckland` saw activity rows attached to the
|
||||||
|
following local day. Anchored at noon UTC (`T12:00:00.000Z`)
|
||||||
|
with a regression suite covering Berlin / Los Angeles / Tokyo /
|
||||||
|
Auckland.
|
||||||
|
- **Cadence and compliance helpers ignored per-user timezone.**
|
||||||
|
`expandScheduleSlots`, `pairDoses`, `buildCadenceTimeline` and
|
||||||
|
the compliance-chip helper now accept a `timeZone` argument that
|
||||||
|
threads through `Intl.DateTimeFormat`, so cross-midnight doses
|
||||||
|
bucket correctly regardless of user locale. The cadence route
|
||||||
|
resolves through `resolveUserTimeZone(user)`.
|
||||||
|
- **Inventory state-machine ignored back-dated first-use.** Issuing
|
||||||
|
a PATCH that pushed `markAsFirstUseAt` more than thirty days into
|
||||||
|
the past left the item in IN_USE; the state machine now re-runs
|
||||||
|
on every PATCH and the stale item flips to EXPIRED. Regression
|
||||||
|
test pins the contract.
|
||||||
|
- **Inventory expire-stale cron looped per row.** Replaced the
|
||||||
|
row-by-row `prisma.update` loop in `expireStaleInUseItems` with a
|
||||||
|
single `updateMany`; bulk-update contract pinned by test.
|
||||||
|
- **Onboarding step write was read-then-update.** A concurrent
|
||||||
|
advance could double-step the wizard. The update now conditions
|
||||||
|
on `{ id, onboardingStep: current, onboardingCompletedAt: null }`
|
||||||
|
and returns 409 on conflict.
|
||||||
|
- **Workout schema accepted `endedAt <= startedAt`.**
|
||||||
|
`createWorkoutSchema` gained a `.superRefine` rejecting
|
||||||
|
zero-duration and inverted windows; the PR detection worker's
|
||||||
|
MIN-direction slot also guards against `durationSec === 0` so a
|
||||||
|
malformed row cannot promote itself to a personal record.
|
||||||
|
- **Personal Record detection duplicate writes under contention.**
|
||||||
|
Same-millisecond writes into a null workout slot now reconcile
|
||||||
|
to a single row; regression test seeds the race.
|
||||||
|
- **Source-priority parse failures were silent.** Storage parse
|
||||||
|
errors now route through an observer breadcrumb and the resolved
|
||||||
|
blob is frozen at construction so downstream mutation is caught
|
||||||
|
immediately.
|
||||||
|
- **Health-Score `asOf` derived non-deterministically.** The
|
||||||
|
`asOf` timestamp now derives from the input dates instead of
|
||||||
|
the wall clock so repeated computes against the same dataset
|
||||||
|
produce stable timestamps.
|
||||||
|
- **Source-priority audit-log entries missed two write paths.**
|
||||||
|
Doctor-report-prefs and source-priority PUTs were not landing
|
||||||
|
audit-log rows; both write paths emit now.
|
||||||
|
- **Personal-record badge dark-mode contrast.** Lifted to WCAG-AA
|
||||||
|
contrast on the `<PersonalRecordBadge>` surface.
|
||||||
|
- **Range-bar zone backgrounds.** `<RangeBar>` mixed Tailwind raw
|
||||||
|
palette tokens with Dracula tokens; all zone backgrounds now
|
||||||
|
resolve through Dracula tokens with the pinned test rewritten.
|
||||||
|
- **Research-Mode acknowledgment dialog footer scrolled below
|
||||||
|
fold.** The footer pins outside the scrolling region on small
|
||||||
|
viewports.
|
||||||
|
- **44-px touch-target floor across the onboarding wizard.**
|
||||||
|
Shell back/skip/next, carousel pager, source-card grid, baseline
|
||||||
|
and goals-chip CTAs all hit the WCAG 2.5.5 floor without
|
||||||
|
changing visual density at typical rendering sizes.
|
||||||
|
- **Workout endpoint reconciled inserted-vs-duplicate counts
|
||||||
|
incorrectly under contention.** Race-recovery path produced
|
||||||
|
inconsistent envelope counts; corrected with a regression test
|
||||||
|
seeding the contention window.
|
||||||
|
- **Legacy Withings `?secret=` webhook form had no counter.** An
|
||||||
|
in-memory `withings.webhook.legacy_form_total` counter surfaces
|
||||||
|
through `ops-stats`; the warning text gained the re-subscription
|
||||||
|
URL for affected accounts.
|
||||||
|
- **Acknowledgment dialog i18n back-button.** Medication history
|
||||||
|
page back-button hard-coded `Zurück`; routed through `t()`.
|
||||||
|
- **Sleep + audio-exposure + comparison-hint i18n keys.** Backfill
|
||||||
|
pass picked up the keys missed by the v1.4.22 sweep across all
|
||||||
|
six locales.
|
||||||
|
- **Build resolution for safety-contract YAML.** The loader now
|
||||||
|
resolves the YAML matrix path from `cwd` rather than `__dirname`
|
||||||
|
so the build does not break when the bundler reshapes the
|
||||||
|
module-relative root.
|
||||||
|
- **GLP-1 drift guard self-skips when the EMA research file is
|
||||||
|
absent.** Local checkouts without the reference file no longer
|
||||||
|
red-bar the test.
|
||||||
|
- **`x-axis` chart ticks resolved in user timezone.**
|
||||||
|
`xAxisTicks` now renders the tick formatter in
|
||||||
|
`user.displayTimezone` instead of hard-coding Europe/Berlin.
|
||||||
|
- **Chart token references switched to `var(--token)` form.**
|
||||||
|
Recharts strokes were still using `hsl(var(--token))`; switched
|
||||||
|
to bare `var(--token)` so Tailwind v4's color-mix parser
|
||||||
|
resolves them.
|
||||||
|
- **`detectGlp1Plateau` branches lacked direct coverage.** Added
|
||||||
|
Prisma-mocked unit tests covering the previously-uncovered
|
||||||
|
branches.
|
||||||
|
|
||||||
### Security
|
### Security
|
||||||
|
|
||||||
- **Coach refuses GLP-1 dose recommendations.** New GROUND RULE 9
|
- **Withings webhook secret no longer leaks into structured
|
||||||
in EN + DE — the Coach surfaces a clinical-referral message on
|
logs.** `WITHINGS_WEBHOOK_SECRET` was landing as a URL
|
||||||
any dose adjustment ask, never a number. PROMPT_VERSION 4.25.0
|
path-segment in `http.path` on every Wide Event the request
|
||||||
carries the rule.
|
produced. The logging stack now carries a parameterised
|
||||||
|
`PATH_SECRET_PATHS` registry seeded with the
|
||||||
|
`/api/withings/webhook/[token]` shape, and
|
||||||
|
`WideEventBuilder.setHttp` rewrites path + route segments to
|
||||||
|
`[REDACTED]` before they reach stdout / the in-memory ring
|
||||||
|
buffer / Loki. Existing query-string redaction is unaffected.
|
||||||
|
- **Coach refuses GLP-1 dose recommendations.** GROUND RULE 9
|
||||||
|
across all six locales — the Coach surfaces a clinical-referral
|
||||||
|
message on any dose adjustment ask, never a number.
|
||||||
|
PROMPT_VERSION 4.25.0 carries the rule.
|
||||||
|
- **Coach refuses drug-level estimates with regulatory cites.**
|
||||||
|
GROUND RULE 15 across all six locales — the Coach refuses any
|
||||||
|
ask for an estimated drug level or pharmacokinetic prediction,
|
||||||
|
cites EU MDR 2017/745 + MDCG 2021-24 in the refusal copy, and
|
||||||
|
routes the user to the Research Mode disclosure flow.
|
||||||
|
Adversarial refusal-probe matrix exercises 20+ paraphrasings per
|
||||||
|
GROUND RULE across six locales in CI on every push, so
|
||||||
|
prompt-injection regressions surface before reaching the
|
||||||
|
dispatch surface.
|
||||||
|
- **Research Mode is gated by an MDR acknowledgment dialog.** The
|
||||||
|
estimated drug-level chart on the GLP-1 detail page renders only
|
||||||
|
after the user opts in through a dialog that cites
|
||||||
|
EU MDR 2017/745 + MDCG 2021-24, EMA EPAR and the Schneck / Urva
|
||||||
|
2024 pharmacokinetic reference. The acknowledgment version
|
||||||
|
re-prompts the user on bump.
|
||||||
|
- **GLP-1 convenience endpoint hardened.** `POST
|
||||||
|
/api/medications/[id]/glp1` parses through bounded Zod schemas
|
||||||
|
(`glp1DoseChangePostSchema`, `glp1InventoryPostSchema`), enforces
|
||||||
|
length caps on notes, finite-number guards on dose value, and
|
||||||
|
bounded `effectiveFrom`; every write produces an audit-log row
|
||||||
|
and the route inherits the 30-per-minute-per-user rate limit
|
||||||
|
from the rest of the medication surface.
|
||||||
- **GLP-1 medication strings sanitised before LLM prompt
|
- **GLP-1 medication strings sanitised before LLM prompt
|
||||||
interpolation.** Patient-safety: a malicious or malformed
|
interpolation.** A malicious or malformed medication name no
|
||||||
medication name embedded prompt-injection bait. Sanitiser
|
longer reaches the prompt body verbatim. Sanitiser passes
|
||||||
passes Latin-letter + digit + common punctuation only.
|
Latin-letter + digit + common punctuation only.
|
||||||
- **Batch-ingest rate limit (sixty per minute per user default).**
|
- **Batch-ingest rate limit (sixty per minute per user default).**
|
||||||
`POST /api/measurements/batch` and the new
|
`POST /api/measurements/batch`, `POST /api/workouts/batch` and
|
||||||
`DELETE /api/measurements/by-external-ids` carry a token-bucket
|
`DELETE /api/measurements/by-external-ids` carry a token-bucket
|
||||||
rate limit returning the standard 429 envelope.
|
rate limit returning the standard 429 envelope.
|
||||||
- **Audit-log writes on source-priority and doctor-report-prefs
|
- **Audit-log writes on source-priority and doctor-report-prefs
|
||||||
@@ -287,7 +563,7 @@ GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
|||||||
paths; one user's priority blob never enters another user's
|
paths; one user's priority blob never enters another user's
|
||||||
resolver.
|
resolver.
|
||||||
|
|
||||||
### Refactor
|
### Refactor / Hygiene
|
||||||
|
|
||||||
- **`pickCanonicalSource` becomes a two-axis lookup with single-
|
- **`pickCanonicalSource` becomes a two-axis lookup with single-
|
||||||
axis fallback.** Reuses `getDeviceTypeLadder()` so the
|
axis fallback.** Reuses `getDeviceTypeLadder()` so the
|
||||||
@@ -306,63 +582,159 @@ GROUND RULE 9 (Coach refuses GLP-1 dose recommendations).
|
|||||||
- **`HK_QUANTITY_TYPE_TO_MEASUREMENT` removed.** The legacy view
|
- **`HK_QUANTITY_TYPE_TO_MEASUREMENT` removed.** The legacy view
|
||||||
was a redundant projection of `APPLE_HEALTH_TYPE_MAP`; all
|
was a redundant projection of `APPLE_HEALTH_TYPE_MAP`; all
|
||||||
callers go through the canonical map now.
|
callers go through the canonical map now.
|
||||||
- **W7e dead-code cleanup pass.** Drops `<InsightsPageHero>`
|
- **Dead-code cleanup pass.** Drops `<InsightsPageHero>` (zero
|
||||||
(zero callers since v1.4.20), `<IntakeTimeline>`,
|
callers since v1.4.20), `<IntakeTimeline>`, `<ComplianceCharts>`
|
||||||
`<ComplianceCharts>` wrapper and three orphan `insightsGeneralStatus`
|
wrapper and three orphan `insightsGeneralStatus` query keys from
|
||||||
query keys from the v1.4.16-era hero. Removes the orphan
|
the v1.4.16-era hero. Removes the orphan
|
||||||
`/api/insights/general-status` route (superseded by
|
`/api/insights/general-status` route (superseded by
|
||||||
`<InsightAdvisorCard>` since v1.4.16).
|
`<InsightAdvisorCard>` since v1.4.16).
|
||||||
- **Coach `<CoachDrawer key={prefill}>` controlled-prop refactor
|
- **Coach `<CoachDrawer key={prefill}>` controlled-prop refactor
|
||||||
is fully in place** — the v1.4.24 follow-up of `useResettableValue`
|
is fully in place** — the v1.4.24 follow-up of `useResettableValue`
|
||||||
is now the only call path; the legacy remount hack code is gone.
|
is now the only call path; the legacy remount hack code is gone.
|
||||||
|
- **380 dead i18n keys dropped.** Runtime probe across the six
|
||||||
|
locales identified 380 keys with zero call sites and zero runtime
|
||||||
|
resolutions; all six locale bundles are smaller by that count.
|
||||||
|
Top namespaces: `settings`, `admin`, `classifications`,
|
||||||
|
`medications`. The remaining ~148 keys are queued for a second
|
||||||
|
pass in v1.4.26.
|
||||||
|
- **Dead system-prompt constants removed.** `BASE_SYSTEM_PROMPT`
|
||||||
|
and `INSIGHTS_SYSTEM_PROMPT` constants had no remaining
|
||||||
|
importers after the native per-locale prompt move; both deleted.
|
||||||
|
- **`useInsightStatus` hook extracted.** The four insights
|
||||||
|
sub-page status queries collapsed into a single hook so the
|
||||||
|
duplicated `useQuery` + Suspense fallback shape lives in one
|
||||||
|
place.
|
||||||
|
- **`<MedicationDetailSection>` wrapper.** Three medication-detail
|
||||||
|
shells (titration, scheduling, side-effects) and the inventory
|
||||||
|
disclosure top share a single wrapper; future medication detail
|
||||||
|
sections drop in without copy-paste.
|
||||||
|
- **Shared helpers across the medication + onboarding surfaces.**
|
||||||
|
New modules `src/lib/api/read-error.ts`,
|
||||||
|
`src/lib/medications/route-guards.ts`,
|
||||||
|
`src/lib/medications/research-mode-types.ts` and
|
||||||
|
`src/lib/medications/dose-string.ts` consolidate previously
|
||||||
|
duplicated patterns. Three near-identical dose-string parsers
|
||||||
|
collapse to one `parseDoseMg`; four-times-duplicated
|
||||||
|
`readError` collapses to one; nine medication routes call the
|
||||||
|
shared `assertMedicationOwnership`.
|
||||||
|
- **Side-effect taxonomy drift-guard.** `SIDE_EFFECT_CATEGORY_VALUES`
|
||||||
|
and `SIDE_EFFECT_ENTRY_VALUES` now derive from the Prisma enum
|
||||||
|
via `z.nativeEnum`; a drift-guard test pins Prisma enum ↔
|
||||||
|
taxonomy map ↔ validator triangle so the three cannot drift.
|
||||||
|
- **Side-effect category derived server-side.** The
|
||||||
|
`createSideEffectSchema` no longer accepts a client-supplied
|
||||||
|
`category`; the server derives it from the entry. Removes the
|
||||||
|
defensive 422 path and the cross-tier drift surface.
|
||||||
|
- **Dashboard top-tile baseline alignment.** Inline trend arrow +
|
||||||
|
baseline-aligned value row across all dashboard tiles, with the
|
||||||
|
baseline contract pinned by regression test.
|
||||||
|
- **Range-bar Dracula token swap.** `<RangeBar>` zone backgrounds
|
||||||
|
resolve through Dracula tokens with the pinned test rewritten;
|
||||||
|
raw palette references gone.
|
||||||
|
- **44-px touch-target floor across the top-bar + section
|
||||||
|
strips.** WCAG 2.5.5 alignment across the broader navigation
|
||||||
|
surface, complementing the onboarding-specific pass.
|
||||||
|
- **Cat-C typo + naming polish from the W10 review pass.** Minor
|
||||||
|
identifier renames flagged by the dead-code probe; no functional
|
||||||
|
change.
|
||||||
|
- **`safeRequestProp` widened catch.** Narrowed catch broadened to
|
||||||
|
tolerate `undefined` requests after the hygiene-review pass
|
||||||
|
surfaced the regression.
|
||||||
|
- **`pickCanonicalWorkout` helper for cross-source workout
|
||||||
|
dedup.** Source-priority logic centralised for the v1.5 iOS
|
||||||
|
workout-ingest path.
|
||||||
|
- **Insights regenerate button relocated; tab strip lifted.**
|
||||||
|
Tab-strip extraction + relocation of the regenerate button to
|
||||||
|
the top-right, paving the way for the seven sub-page surfaces.
|
||||||
|
|
||||||
### Tests
|
### Tests
|
||||||
|
|
||||||
- 2244 → 2652 passing unit tests (+408). Integration suite
|
- 2244 → 3828 passing unit tests across 344 files (+1584; one
|
||||||
140 → 174 (+34). e2e green on the W2 CI fix (coach-prefs URL
|
pre-existing skip carries through). Integration suite 140 → ~170
|
||||||
mock + Pixel-5 selector hardening).
|
across 11 files. e2e green on the W2 CI fix (coach-prefs URL
|
||||||
- New unit suites: GLP-1 plateau-detection text formatter; two-axis
|
mock + Pixel-5 selector hardening) plus the Fix-I hot-fix that
|
||||||
source-priority resolution (single-axis fallback, per-device
|
re-anchored the dashboard insight-card and the mobile x-axis
|
||||||
override, mixed-bucket selection); source-priority Settings
|
tick locators.
|
||||||
reducer (reorder, reset, validate); medication-card GLP-1
|
- **Coach refusal-probe matrix.** 1800+ assertions exercise 15
|
||||||
variant + injection-site-picker (RTL); doctor-report prefs
|
GROUND RULES across six locales with 20+ adversarial
|
||||||
PUT contract; personal-records pagination clamp;
|
paraphrasings each. CI runs the matrix on every push; any
|
||||||
`berlinIsoWeekday` timezone-aware suite; sleep-stage chart
|
prompt-injection or jailbreak regression surfaces before
|
||||||
i18n-suffix drift-guard; Health-Score provenance i18n
|
reaching the dispatch surface. Drift-guard tests pin the
|
||||||
drift-guard; api-handler private-field crash regression.
|
YAML-per-locale safety-contract matrix in lockstep with the
|
||||||
- New integration suites: two-axis canonical-source resolution
|
validator-derived enums.
|
||||||
|
- **New unit suites (selection):** GLP-1 plateau-detection text
|
||||||
|
formatter; two-axis source-priority resolution (single-axis
|
||||||
|
fallback, per-device override, mixed-bucket selection);
|
||||||
|
source-priority Settings reducer (reorder, reset, validate);
|
||||||
|
medication-card GLP-1 variant + injection-site-picker (RTL);
|
||||||
|
doctor-report prefs PUT contract; personal-records pagination
|
||||||
|
clamp; `berlinIsoWeekday` timezone-aware suite; sleep-stage
|
||||||
|
chart i18n-suffix 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.
|
||||||
|
- **New integration suites:** two-axis canonical-source resolution
|
||||||
end-to-end; `requireAuth()` narrow-scope on unscoped route;
|
end-to-end; `requireAuth()` narrow-scope on unscoped route;
|
||||||
batch-ingest race reconciliation under contention.
|
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).
|
||||||
|
- **Migrations:** 9 new (0051–0059) + 1 hardening (0060
|
||||||
|
`onboarding_step_not_null` backfill + NOT NULL flip). All
|
||||||
|
additive and forward-only; migration 0057 comment rewritten to
|
||||||
|
match PG11+ fast-path ADD COLUMN DEFAULT semantics.
|
||||||
|
|
||||||
### Deferred to v1.4.26
|
### Deferred to v1.4.26
|
||||||
|
|
||||||
See `.planning/v1426-backlog.md` for the full thirty-plus item
|
See `.planning/v1426-backlog.md` for the full backlog with effort
|
||||||
list with effort estimates and source citations. Headline items:
|
estimates and source citations. Headline items:
|
||||||
|
|
||||||
- OpenAPI drift-gate hard-fail flip (still warn-only after this
|
- `User.onboardingGoals` column + server-side persistence for the
|
||||||
release; iOS DTO codegen needs hard-fail confidence before
|
goals chip-picker selection (today the picker holds the choice
|
||||||
the v1.5 iOS sprint starts).
|
client-side only; the dashboard-widgets seed feature reads it in
|
||||||
- Onboarding rebuild promoted from v1.5 (last release where new
|
v1.4.26).
|
||||||
users see the v1.4.20-era onboarding without sub-pages, GLP-1,
|
- `advance()` hook extraction for the three onboarding step
|
||||||
six locales).
|
components — pattern surfaced in the simplifier review, deferred
|
||||||
- Native FR / ES / IT / PL Coach + insights system prompts
|
to avoid collision with v1.4.25 touch-target work.
|
||||||
(current `REPLY LANGUAGE` footer is interim; native bodies
|
- `glp1-pk.ts` unused-export decision (internalise vs wire
|
||||||
let each safety contract speak in its target voice).
|
dashboard chip).
|
||||||
- Personal-record detection worker (schema shipped this release;
|
- Seven orphan endpoint go / no-go decisions
|
||||||
sweep-on-insert + nightly cron pending).
|
(`/api/admin/ai-settings`, `/api/admin/backup/test`,
|
||||||
- Workout ingest endpoint (`POST /api/measurements/batch?kind=workout`
|
`/api/admin/status-overview`,
|
||||||
— schema shipped, endpoint waits on iOS contract finalisation).
|
`/api/monitoring/{glitchtip,umami}/test`).
|
||||||
- Withings Activity sync routine (OAuth scope shipped; sync
|
- ~148 dead i18n keys remaining after the W10 runtime-probe sweep
|
||||||
waits on reconnect-banner adoption window).
|
(the v1.4.25 pass removed 380 of the 528 candidates; the
|
||||||
- Withings Sleep v2 routine.
|
remaining ~148 need second-pass call-site verification).
|
||||||
- 414 dead i18n keys cleanup (top namespaces: `settings:114`,
|
- FR / ES / IT / PL prose hand-review by a native speaker for the
|
||||||
`admin:75`, `classifications:69`, `medications:21`).
|
Coach + insights surface (the structural refusal-probe matrix
|
||||||
|
covers safety; the user-facing prose still benefits from a
|
||||||
|
human pass).
|
||||||
|
- Coach `lastYear` baseline + row-tap-to-prefill polish.
|
||||||
|
- Sleep sub-page stacked-column visual polish (stage colours +
|
||||||
|
legend density).
|
||||||
|
- Mood verbal-labels persistence behind a per-user toggle.
|
||||||
|
- Drug-level chart-side 90-day staleness clock wiring (the
|
||||||
|
acknowledgment dialog already re-prompts on version bump and
|
||||||
|
Coach refuses at GROUND RULE 15; the clock is defence-in-depth).
|
||||||
- iOS-18 long-tail HK identifier mappings (sleep apnea, GAD-7 /
|
- iOS-18 long-tail HK identifier mappings (sleep apnea, GAD-7 /
|
||||||
PHQ-9, running form, paddle / row / ski distances, pregnancy /
|
PHQ-9, running form, paddle / row / ski distances, pregnancy /
|
||||||
cycle, FHIR clinical).
|
cycle, FHIR clinical).
|
||||||
- VO2 max chart-row card on `/insights/<metric>` (dashboard tile
|
- VO2 max chart-row card on `/insights/<metric>` (dashboard tile
|
||||||
shipped; chart card queued alongside iOS body-composition page).
|
shipped; chart card queued alongside the iOS body-composition
|
||||||
- Withings webhook secret moved from query string to header form.
|
page).
|
||||||
- Lazy-loaded locale JSON bundles (all six locales import
|
- Lazy-loaded locale JSON bundles (all six locales import
|
||||||
synchronously at present, ~675 KB to every client).
|
synchronously at present, ~675 KB to every client).
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user