## Audit outcome - Audited commit `500fc56b5f3cf27413ff2d449279bef3bad191e0`. - Read source, schemas, synthetic fixtures, and tests only; no production data inspected. - Made no file changes. - Existing Sprint 6H-B unit coverage passes with the required import path: - `PYTHONPATH=scripts/health ... tests/test_dashboard_v5_sprint6h_b.py` - **5 passed** - Playwright successfully discovered **11 tests** across the 6H-B and 6I-A specs. ## Existing implementation map ### Capture and media - `dashboard-v5-capture.js` - Six capture types and URL/history-driven dialogs. - One file input with `multiple`, `capture="environment"`, and image-only `accept`. - Maximum three images, 12 MB each. - Local image previews and removal. - Sequential uploads followed by action queue submission and status polling. - `capture_media.py` - JPEG/PNG only; HEIC/HEIF is explicitly rejected. - Magic validation, Pillow decode, private quarantine, SHA-256 dedupe, and JPEG thumbnails. - `capture_contract.py` - Version 1 payload with at most three attachment tokens. - `health_dashboard_server.py` - `POST /api/v1/capture/upload`: authenticated, same-origin, one-time CSRF, raw octet stream. - `GET /api/v1/capture/status/{idempotency_key}`. - `GET /api/v1/capture/media/{attachment}/thumbnail`. - `health_dashboard_action_worker.py` - Append-only correction/withdrawal versions. - Corrections inherit all previous media only when no new files are supplied. - New files replace inherited attachments as a group; selective retain/remove is unavailable. ### Today, day, calendar, and record - **Today:** bundle-rendered snapshot, tasks, and medication. It does not display capture chronology/media. - **Day:** canonical day data is rendered by `dashboard-v5-day-controller.js`; capture chronology is loaded separately by `dashboard-v5-capture.js`. - **Chronicle:** sorted timed/undated entries, thumbnails, correction/withdrawal controls, and basic version/status history. - **Calendar:** counts canonical sources plus active captured supplements and photos. Other capture types generally rely on worker mirroring into legacy canonical tables. - **Record:** tabs for overview, labs, medications, appointments, documents, and report. No capture/chronicle tab. - **Doctor report timeline:** sourced from the legacy events API, not `capture_entries`. ## Material gaps 1. `capture="environment"` on the only picker does not provide explicit **Camera Roll versus direct capture** choices. 2. No video intake, validation, poster generation, playback endpoint, or browser rendering. 3. Client accepts HEIC/HEIF while the backend always rejects it—misleading UI contract. 4. Upload progress is text-only; `fetch` provides no per-file byte progress. 5. Token tracking is positional. Removing a file resets every token and can cause redundant uploads and temporary quarantine orphans. 6. Capture date/time defaults from browser `Date` and browser timezone, rather than authoritative Zurich/user-selected day context. 7. Chronicle loading uses delays and click matching rather than a date-keyed abort/version contract; a stale response can render after rapid day navigation. 8. Version history exposes only version/status/time, not the media attached to each historical version. 9. Selective media retention/removal during correction is impossible. 10. Today and Record omit captured media/chronology. 11. The 6H-B browser spec is not wired into `run_v5_isolated_matrix.sh` or package scripts. The generic matrix fixture does not seed the three capture timeline rows expected by that spec. 12. Existing browser coverage previews an image but does not exercise a complete upload → queue → worker → regenerated display path. ## Smallest Sprint 6I-B path 1. **Explicit source controls** - Replace the single input with: - Camera Roll: no `capture`, `multiple`, image/video allowlist. - Take photo: image input with `capture="environment"`. - Record video: video input with `capture="environment"`. - Preserve the current cap as **three images plus one video**. - Remove HEIC/HEIF from visible acceptance unless local decoding is added. 2. **Authoritative capture context** - Add a small authenticated `/api/v1/capture/context` response containing Zurich `today`, local time, and allowed selected-day context. - A capture launched from Day defaults to that explicit day; all other launches default to server-authoritative Zurich today. - Do not derive the date from browser timezone or browser storage. 3. **Versioned attachment contract** - Introduce contract v2 with typed attachments and an explicit: - `retained_attachment_refs` list for correction; - `live_photo_pairs` list linking one selected image and video token/ref. - Never infer Live Photo pairing from names, timestamps, or file order. - Validate retained refs belong to the corrected active entry. 4. **Private video handling** - Add a new additive 6I-B migration rather than mutating the frozen 6H-B migration. - Extend attachment metadata with media kind, safe MIME, duration, poster, and optional explicit Live Photo relation. - Locally inspect MOV/MP4 with bounded `ffprobe`, enforce size/duration/dimensions/codecs, then normalize to a fixed MP4 and generate a poster with bounded `ffmpeg`. - Strip metadata and make no external conversion requests. 5. **Preview, remove, and progress** - Track state per item: `{file, kind, objectURL, token, progress, error}`. - Use XHR upload progress for each card and an aggregate status. - Removing one item must retain other uploaded tokens. - Show `` for images and muted local `