docs(planning): record phase B6 completion in STATE.md + report

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-09 21:38:02 +02:00
1 parent 28467b2590
commit f5c6505e37
2 files changed
+110 -2

No files matched your search

+36 -2
View File
@@ -502,10 +502,44 @@ once C2's auto-deploy is verified.
### B6 — Doctor-report v2
- [ ] Configurable date range
- [ ] Practice-name on cover page
- [x] Configurable date range — `d692119`
- [x] Practice-name on cover page — `28467b2`
- Detailed report: `.planning/phase-B6-report.md`
#### B6 status block — 2026-05-09T21:38+02:00 — done
Two atomic commits on `origin/main`:
- `d692119` `feat(doctor-report): configurable date range with default
last-90-days` — `<DoctorReportDialog>` (Radix Dialog + native
`<input type="date">`) prompts the user before the request fires;
defaults end=today, start=today-90d; presets 90d / 6mo / 12mo;
inline validation (end >= start, span <= 2 years).
`normaliseDateRange()` parses `{ startDate?, endDate?, days? }` with
silent fallback. `collectDoctorReportData()` filters with both `gte`
AND `lte` so a custom window honours both bounds. PDF cover prints
the explicit period.
- `28467b2` `feat(doctor-report): practice name on cover page (persisted
as user preference)` — optional "Praxis / clinic name" input on the
dialog, pre-filled from `User.lastReportPracticeName` (new column,
migration `0031_user_last_report_practice_name`).
`sanitisePracticeName()` strips ASCII C0 + DEL controls, collapses
whitespace, hard-caps at 120 chars. PDF cover renders 11pt bold
above the separator when set; omitted when null. `/api/auth/me`
echoes the value. Audit + Wide-Event log
`practiceNameProvided: boolean` (not the value itself).
Tests: 965 / 965 unit pass (was 957), 31 / 31 integration pass,
typecheck clean for B6 files, lint 0 errors. The 3 pre-existing
dashboard-layout typecheck errors continue to belong to A4; the 2
`tour-launcher.tsx` lint errors continue to belong to B5.
Cross-agent: race-conditions on `prisma/schema.prisma` +
`src/components/settings/advanced-section.tsx` mid-session; recovered
each time by re-reading + re-applying. Same rec as A2 / A4 / B-mobile /
B1 / B2 / B3: v1.4.16 should adopt
`superpowers:using-git-worktrees` per parallel agent.
## Phase C — Hardening
### C1 — AI/Codex hardening (infrastructure for hallucination-resistance)
+74
View File
@@ -0,0 +1,74 @@
# Phase B6 — Doctor-report v2
Status: done · 2026-05-09T21:38+02:00 · two commits on origin/main
## Shipped
1. `d692119` `feat(doctor-report): configurable date range with default
last-90-days` — new `<DoctorReportDialog>` (Radix Dialog + native
`<input type="date">`) prompts before the request fires; defaults end=today,
start=today-90d; presets 90d / 6mo / 12mo. New
`normaliseDateRange()` parses `{ startDate?, endDate?, days? }` with
silent fallback to last-90-days. `collectDoctorReportData()` accepts a
range and filters Prisma `findMany` with both `gte` AND `lte` on
measurements, intake events, and mood entries. PDF cover renders the
explicit period from `period.start`/`period.end` (legacy `period.since`
preserved for backwards compat). Audit-log + Wide-Event annotations
record `startDate` / `endDate` for forensic replay.
2. `28467b2` `feat(doctor-report): practice name on cover page (persisted
as user preference)` — new optional "Praxis / clinic name" field on
the dialog, pre-filled from the user's last value. Persisted in
`User.lastReportPracticeName` (migration `0031_user_last_report_practice_name`).
`sanitisePracticeName()` strips ASCII C0 + DEL controls, collapses
whitespace, hard-caps at 120 chars before any layout-sensitive
rendering. PDF cover prints the line in 11pt bold above the separator
when set; omitted when `null`. Both client + server PDF renderers
carry the change. `/api/auth/me` echoes the value so the dialog
pre-fills without an extra round-trip. Audit + Wide-Event annotations
record `practiceNameProvided: boolean` (NOT the value).
## Validation
- `pnpm test` — 965 / 965 unit pass (was 957 at phase start; +8 net
after the commit-1 / commit-2 split + reorg).
- `pnpm test:integration` — 31 / 31 pass.
- `pnpm typecheck` — 0 new errors; the 3 pre-existing dashboard-layout
test errors flagged in STATE.md continue to belong to A4.
- `pnpm lint` — 0 errors, 11 warnings (none in B6 files; the 2
errors in `tour-launcher.tsx` are B5 territory and untouched).
## Race-condition notes
Sibling agents kept rewriting `prisma/schema.prisma`,
`src/components/settings/advanced-section.tsx`, and the test fixtures
mid-session. Recovered each time by reading the current file before the
next Edit and re-applying the diff. The `useEffect` reset pattern in
the dialog flagged the strict `react-hooks/set-state-in-effect` rule;
switched to the codebase-canonical "track-the-trigger" pattern from
`account-section.tsx` (store last-observed `open`, react during render).
## Files
- New: `src/components/doctor-report/doctor-report-dialog.tsx` +
test, `src/lib/__tests__/doctor-report-data.test.ts`,
`prisma/migrations/0031_user_last_report_practice_name/migration.sql`.
- Touched: `src/lib/doctor-report-data.ts`,
`src/lib/doctor-report-pdf-core.ts`, `src/lib/doctor-report-pdf.ts`,
`src/app/api/doctor-report/route.ts`,
`src/app/api/doctor-report/pdf/route.ts`,
`src/app/api/auth/me/route.ts`,
`src/components/settings/advanced-section.tsx`,
`prisma/schema.prisma`, `messages/{en,de}.json`,
`src/lib/__tests__/doctor-report-pdf-core.test.ts`,
`src/app/api/doctor-report/__tests__/pdf-route.test.ts`.
## Out of scope / deferred
- E2E test for the dialog open → submit flow — the existing
`e2e/doctor-report.spec.ts` mocks the data endpoint and clicks the
trigger; updating it to drive the new dialog is out of B6 scope and
better landed alongside C3's e2e reliability work.
- DB-level encryption of `lastReportPracticeName` — the field is
user-provided, low-sensitivity, and already protected by HealthLog's
cookie-session auth. C-3 / phase-D security review can re-evaluate.