From 302ebed66b8a48d5ff22e7a80bb621bf2e37450b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 15 May 2026 17:55:01 +0200 Subject: [PATCH] docs(planning): bucket B7 implementation report for v1.4.27 Per-commit subjects, deliverable-vs-actual verification matrix for every fix-plan item, the orphan-endpoint grep table that grounds the five-endpoint v1.4.28 defer, and the seven recorded deviations from the original fix-plan scope. --- .../round-3-b7-symmetry-cleanup-report.md | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 .planning/round-3-b7-symmetry-cleanup-report.md diff --git a/.planning/round-3-b7-symmetry-cleanup-report.md b/.planning/round-3-b7-symmetry-cleanup-report.md new file mode 100644 index 000000000..1c2f7522f --- /dev/null +++ b/.planning/round-3-b7-symmetry-cleanup-report.md @@ -0,0 +1,172 @@ +--- +file: .planning/round-3-b7-symmetry-cleanup-report.md +purpose: B7 implementation report for v1.4.27 — symmetry sweep + dead-code cleanup + low-tier polish +contributor: B7 +baseline: cef9bc14 +landed: d10e0f28 +--- + +# Bucket B7 — implementation report + +## Commits + +| # | sha | subject | +|---|-----------|---------| +| 1 | `39fef7d3` | `chore(ui): unify heading weight, card cadence, and label-input gap across settings and admin` | +| 2 | `32a023df` | `chore(ui): apply M7 + L1 + L3 + L4 polish across medication form, motion-reduce, details aria, therapy timeline` | +| 3 | `9b0b1c6b` | `chore(ui): repair stray motion-reduce tokens that bled into JSDoc comments and pair the mood chart spinner` | +| 4 | `205ee1dd` | `chore(api): surface every safeRequestProp fallback through a console warning` | +| 5 | `988bbf1a` | `feat(workouts): wire pickCanonicalWorkout into the list read path and collapse the attach route N+1` | +| 6 | `6a76f746` | `feat(coach): extend the snapshot window enum with lastYear` | +| 7 | `3a7599c8` | `chore(api): delete the orphan /api/audit-log surface and seed the five README-tied admin orphans into v1.4.28` | +| 8 | `3ec1f44d` | `chore(lib): extract shared allMessages and resolveKey between context and server-translator` | +| 9 | `39571c6e` | `chore(lib): derive metricPriorityObjectSchema from SOURCE_PRIORITY_METRIC_KEYS` | +| 10 | `f72d2de2` | `chore(cleanup): retire dead exports across glp1 modules and scheduling helpers` | +| 11 | `d10e0f28` | `chore(charts): align chart-tick timezone handling across the chart surface` | + +## Deliverables vs fix-plan + +### Commit 1 — heading weight + card cadence + label-input gap (F13 symmetry) + +Standardised to `font-semibold` across every divergent `

` / `

` in `src/components/settings/` and `src/components/admin/`. Five files touched: + +- `account-section.tsx` — `text-sm font-medium` → `text-sm font-semibold` (two passkey sub-headings) +- `integrations-section.tsx` — withings-credentials sub-heading +- `user-management-section.tsx` — edit + reset-password sub-headings +- `thresholds-editor-section.tsx` — card root `space-y-5` → `space-y-4` +- `ai-section.tsx` — card root `space-y-6` → `space-y-4` + +The password-change dialog at `account-section.tsx:610-642` lifted `space-y-1.5` → `space-y-2` across all three label-input pairs. + +### Commit 2 — M7 + L1 + L3 + L4 polish + +- **M7**: `medication-form.tsx` — Dialog inline-control sweep. Day-of-week and interval buttons (`h-8`) lifted to `min-h-11`; the trailing `` (`h-9 w-9`) to `h-11 w-11`; label-input gaps (`space-y-1.5`) to `space-y-2`. +- **L1**: 70 files swept by `python3` script — added `motion-reduce:animate-none` to every `animate-spin` / `animate-pulse` / `animate-bounce` className across `src/components/**` and `src/app/**` (121 token insertions). The drift-on-quote-delimiter bug that hit nine files in this commit was repaired in commit 3. +- **L3**: `inventory-section.tsx` + `coach-panel/message-thread.tsx` get explicit `aria-controls` / `id` pairing between `` and the disclosed panel; `glp1-medication-card.tsx` already shipped the pattern. +- **L4**: `therapy-timeline.tsx` — sr-only `

{entry.medicationName}

` per timeline entry. + +L2 (Health Score disclaimer) — owned by B1 commit 6 per coordination notes. Not re-touched. + +### Commit 3 — hotfix for the JSDoc-comment bleed + +The L1 motion-reduce script treated apostrophes inside `/* … */` JSDoc bodies as quote delimiters and appended the utility into the comment body across nine files. Repaired each via a targeted regex pass: + +- `account-section.tsx` (2 places), `about-section.tsx`, `ai-section.tsx`, `api-token-overview-section.tsx`, `glp1-medication-card.tsx`, `DrugLevelChart.tsx`, `mood-chart.tsx`, `health-chart.tsx`, `glp1-tile.tsx` — total 10 comment fixes. + +Also threaded the missing `motion-reduce:animate-none` through the mood-chart spinner that the script had skipped after the working-tree juggle with B6's parallel commits. + +### Commit 4 — safeRequestProp warning + verification of BL-P1-2 / BL-P1-4 + +The W7d narrowing landed earlier in `61d156e7`; what remained was to add the `console.warn` on every fallback so misfires surface in the dev console + run log. Verification of the related items: + +- **BL-P1-2** (`BASE_SYSTEM_PROMPT` + `INSIGHTS_SYSTEM_PROMPT` bare exports): already retired in `41c7425b` (chore(ai)). Bare symbol grep returned zero hits; only locale-suffixed `_DE` / `_EN` forms remain, which are out of scope per the deliverable. +- **BL-P1-4** (stale comment at `targets/route.ts:807`): the brace `}` was already cleaned up; the current line reads `// src/lib/ai/prompts/general-status.ts already enforce this`. Verified via line-707 grep before commit. +- **`globals.css` `@source` path**: the path `../../.planning` from `src/app/globals.css` resolves correctly to `/.planning` per Tailwind v4 docs (paths are relative to the stylesheet). The earlier `61d156e7` already pinned `source("../..")` on the `@import` so the auto-detection root is repo-root. No further change. + +### Commit 5 — workout dedup wiring + attach-route N+1 collapse + +- New `src/app/api/workouts/route.ts` — paginated GET that runs every fetch through `pickCanonicalWorkout()` with `DEFAULT_WORKOUT_SOURCE_PRIORITY` and the 5-min cluster window. Adds `FETCH_MULTIPLIER = 2` so the canonical-page query stays full after dedup. +- `src/app/api/workouts/batch/route.ts` — the `Promise.all(withoutExternal.map(p => tx.workout.findFirst(...)))` route-attach loop collapses to a single batched `tx.workout.findMany` with one `OR` row per entry. Per-batch round-trip count drops from 1+N to 2 for a 100-row batch; the createdAt-DESC tie-break is preserved via in-memory grouping. +- New `src/app/api/workouts/__tests__/canonical-dedup.test.ts` — four cases: twin collapse, proximity-window separation, sport-type isolation, limit clamp. + +### Commit 6 — Coach `lastYear` snapshot window + +- `types.ts` — added `lastYear` to `coachScopeWindowSchema` between `last90days` and `allTime`; extended `CoachProvenance.windows` union. +- `snapshot.ts` — `windowToDays(lastYear) === 365`. Seeded the provenance window set with the resolved scope window so the source-chip surfaces the year-in-review chip even when the per-metric branches only add `last30days` / `last90days`. +- `__tests__/snapshot.test.ts` — added `respects the scope.window — lastYear flags the year-in-review window` assertion. +- `source-chips.tsx` — added `lastYear` entry to `WINDOW_KEYS` so the i18n resolver looks up `insights.coach.window.lastYear`. + +The `insights.coach.window.lastYear` i18n key is missing across all six locale bundles. Resolves through the fallback chain to the raw key string until B6 lands the translations; the key is deferred to v1.4.28 in the backlog file. + +### Commit 7 — orphan endpoint deletions + v1.4.28 defer + +Orphan-endpoint grep verification (each `grep -rln src/`, plus follow-up grep in `tests/`, `scripts/`, `playwright/`, `e2e/`, root docs): + +| Endpoint | src callers | tests/scripts | README | CHANGELOG | AGENTS | Action | +|---|---|---|---|---|---|---| +| `/api/audit-log` | 0 | 0 | — | — | — | **deleted** | +| `/api/admin/ai-settings` | 0 | 0 | L362–363 | L752, L3261 | — | defer v1.4.28 | +| `/api/admin/backup/test` | 0 | 0 | L368 | L752 | — | defer v1.4.28 | +| `/api/admin/status-overview` | 0 | tests/ exists | L367 | L753 | L194 | defer v1.4.28 | +| `/api/monitoring/glitchtip/test` | 0 | tests/ exists | L381 | — | — | defer v1.4.28 | +| `/api/monitoring/umami/test` | 0 | tests/ exists | L382 | — | — | defer v1.4.28 | + +The `/api/audit-log` deletion is one route file (1 281 B). No DTO or test fixture existed; the planning text mentioned them as "DELETE candidates" but the surface had already been pared back by an earlier sweep. + +Five admin / monitoring endpoints defer to v1.4.28 — per the fix-plan directive, a README mention counts as a consumer reference. The v1.4.28 backlog seed captures each grep finding plus the maintainer-decision framing. + +The `insights.coach.window.lastYear` i18n key is also seeded into the v1.4.28 backlog under B7 (B6 territory). + +### Commit 8 — shared `allMessages` + `resolveKey` extract + +New `src/lib/i18n/shared-resolve.ts` with the per-locale message map and the dotted-key resolver. `context.tsx` and `server-translator.ts` both import from it; the two duplicate copies are gone. Net 61/-66 LOC. + +### Commit 9 — derive `metricPriorityObjectSchema` + +The 14-key listing on `metricPriorityObjectSchema` and the parallel 14-key block on `sourcePrioritySchema`'s flat shape now derive from `SOURCE_PRIORITY_METRIC_KEYS` via `Object.fromEntries`. Adding a metric class is a single-line constant edit instead of three parallel listings. + +### Commit 10 — dead-export retirement + simp-M6 / simp-M7 / BL-P4-5 + +**glp1-knowledge.ts** — 8 of the 10 export symbols flagged by dead-M5 dropped via export-keyword removal (kept as internal types). `routeForBrand` and `GLP1_DRUG_IDS` retained as exports because grep showed the glp1-knowledge + ladder test suites read them; the deliverable's "10 unused" count was test-aware and the actual prod-only count is 8. Per-symbol verification table: + +| Symbol | prod refs | test refs | Action | +|---|---|---|---| +| `Glp1Route` | 0 | 0 | export → internal type | +| `Glp1DrugClass` | 0 | 0 | export → internal type | +| `Glp1Pharmacology` | 0 | 0 | export → internal type | +| `Glp1Storage` | 0 | 0 | export → internal type | +| `Glp1Pen` | 0 | 0 | export → internal type | +| `Glp1AdverseReactions` | 0 | 0 | export → internal type | +| `Glp1Indications` | 0 | 0 | export → internal type | +| `Glp1SourceCitations` | 0 | 0 | export → internal type | +| `routeForBrand` | 0 | 1 (glp1-knowledge.test) | kept (test-only reader) | +| `GLP1_DRUG_IDS` | 0 | 2 (glp1-pk.test, ladder.test) | kept (test-only reader) | + +**scheduling/cadence.ts** — `ExpectedDose` interface drops its `export` keyword (used internally only). The dead-M7 surface called out `ExpectedDose` plus several functions (`expandScheduleSlots`, `pairDoses`, `missedDoses`) — but the latter three are read by `__tests__/cadence.test.ts`, so they stay exported. + +**simp-M6**: `pairDoses` — replaced the centre-sort + windowStart re-sort double-pass with a single `windowStart` sort. Sorting by `windowStart` and by `(start+end)/2` produce the same order for non-overlapping windows (which is the only shape pairDoses sees). + +**simp-M7**: `escalationDue` parameter rename `drugId` → `drugIdForCeiling` + per-parameter JSDoc clarification per the W21-simplifier finding. + +**BL-P4-5**: `__testables.WEEKDAY_KEYS` plus the underlying private constant retire from `glp1-snapshot.ts` (zero callers anywhere). + +### Commit 11 — chart-tick timezone audit (BL-P4-2) + +The five chart files called out in the deliverable (`sleep-stage-stacked-bar`, `mood-chart`, `health-chart`, `medication-compliance-chart`, plus broader insights surface) all anchor their day-key computations at `Date.UTC(...)` and route ticks through the timezone-aware `tzFmt.date` / `tzFmt.dateShort` pair. They audit clean. + +The outlier was `src/components/charts/compliance-heatmap.tsx`: + +- Tooltip date formatter parsed the day-key against local tz (`new Date(dateStr + "T00:00:00")`). Pinned to `T00:00:00Z` + `getUTC*` accessor trio. +- The heatmap walk read `getDay()` / `getMonth()` (server-tz) while the dateKey was UTC-anchored via `toISOString().slice(0, 10)`. The Monday-alignment and month-marker placement could land one cell off on an SSR pass running on a non-Berlin host. Swapped to `getUTCDay()` / `getUTCMonth()`. + +## Verification + +Per-commit gate: `pnpm typecheck` + `pnpm lint` + relevant `pnpm test` — all green on every commit. Final full-suite run at HEAD (d10e0f28): 355 test files, 3 976 tests passing + 1 skipped (no regressions vs the cef9bc14 baseline). + +## Deviations from the fix-plan + +1. **Estimated commit count**: 7 atomic listed in the fix-plan vs 11 landed. The mid-flight directive ("pack everything in we can") added simp-M6 / simp-M7 / BL-P4-5 / BL-P4-11-S1 / BL-P4-11-S10 / dead-M5 / dead-M7 / BL-P2-3 / BL-code-M3 / BL-P4-2 to B7's scope. The 11 commits split those across thematic concerns without packing unrelated items together. + +2. **Commit 3 (hotfix)** was not in the deliverable list — it repairs the broken-comment side-effect of commit 2's L1 sweep. Folded as a small follow-up commit per the directive "If you break a gate, fix the root cause and create a NEW commit — never `--amend` on a hook-rejected commit." The original commit 2's hooks all passed; the broken comment was a runtime-quiet drift caught on the next typecheck pass. + +3. **BL-P1-2 / BL-P1-3 / BL-P1-4** were largely no-ops because earlier commits in the v1.4.27 cycle (`41c7425b`, `61d156e7`) had already retired the bare symbol exports + narrowed `safeRequestProp` + cleaned the targets-route stale comment. The remaining piece for commit 4 was the `console.warn` addition on the `safeRequestProp` fallback, which surfaces a tolerated misfire in dev. + +4. **Five admin / monitoring orphan endpoints** deferred to v1.4.28 rather than deleted in commit 7. The README references count as consumer per the fix-plan directive; defer is the documented call. + +5. **`globals.css` `@source` "fix"** was no-op for the same reason — the path already resolved correctly to `/.planning` per Tailwind v4's relative-to-stylesheet semantics. Confirmed via Tailwind v4 docs query. + +6. **`pickCanonicalWorkout` wiring** created a new `GET /api/workouts` route from scratch because no list/read route existed yet; the fix-plan listed the file path but the file was greenfield. The picker contract stays a pure function as specified; the route owns the query window + the response-meta envelope. + +7. **`B6 territory respected**: messages/*.json, mood/labels.ts, i18n-drift-guard.test.ts left untouched. Where my motion-reduce sweep accidentally touched a file B6 had uncommitted edits in (mood-list.tsx, mood-chart.tsx), the working tree was left intact for B6 to land alongside their refactor; B6 committed the merge atomically in `22b11427`. + +## Untouched untracked files + +These untracked files were present in the working tree at the start of the session (created by earlier contributors) and remain untracked: + +- `.planning/v1422-w1a-insights-probe.mjs` +- `.planning/v1422-w1a-targets-probe.mjs` +- `.planning/v1422-w1a-tokens-probe.mjs` +- `scripts/audit-a6.mjs` +- `scripts/audit-a6-v2.mjs` + +No B7 work depends on them; left for the next contributor or for `.gitignore` cleanup.