clarke / clarke_PRD_tasks.md
yashvshetty's picture
Clarke: NHS clinical documentation system
9636a02
|
Raw
History Blame
76.6 kB
# Clarke — PRD Tasks (Build Execution Plan)
**Version:** 1.0 | **Date:** 13 February 2026 | **Author:** Project Lead
**Status:** Final — step-by-step execution plan for AI coding agent (Codex)
**Parent document:** clarke_PRD_masterplan.md
**Scope:** Ordered, atomic task list with verification criteria for every step of the Clarke build
**Not in scope:** Strategic rationale (masterplan.md), visual styling (design_guidelines.md), user journey detail (userflow.md), architecture blueprints (technical_spec.md). Tasks reference these documents where needed.
---
## Summary Table
| Task | Title | Priority | Prerequisites | Est. Time |
|------|-------|----------|---------------|-----------|
| 0 | Read & Confirm Understanding | Core | None | 15 min |
| 1 | Create Project Directory Structure | Core | T0 | 15 min |
| 2 | Configuration & Environment Setup | Core | T1 | 20 min |
| 3 | Pydantic Data Models & Schemas | Core | T1 | 30 min |
| 4 | Synthetic FHIR Patient Data | Core | T3 | 45 min |
| 5 | Mock FHIR API Server | Core | T4 | 30 min |
| 6 | Demo Audio Files & Transcripts | Core | T1 | 30 min |
| 7 | **Phase 0 Checkpoint** | Core | T2,T5,T6 | 10 min |
| 8 | MedASR Model Loading & Audio Preprocessing | Core | T7 | 30 min |
| 9 | MedASR Transcription Pipeline | Core | T8 | 30 min |
| 10 | FHIR Client & Tool Functions | Core | T5 | 30 min |
| 11 | MedGemma 4B EHR Agent — Loading & Context Retrieval | Core | T10 | 45 min |
| 12 | Orchestrator — Pipeline Coordinator | Core | T9,T11 | 45 min |
| 13 | Prompt Templates (EHR Agent + Document Generation) | Core | T12 | 30 min |
| 14 | **Phase 1 Checkpoint — Integration Test Point 1** | Core | T13 | 20 min |
| 15 | MedGemma 27B Loading & Baseline Generation | Core | T14 | 45 min |
| 16 | Document Generation Prompt Engineering | Core | T15 | 30 min |
| 17 | End-to-End Backend Pipeline Wiring | Core | T16 | 30 min |
| 18 | Pipeline Hardening — Error Handling & Timeouts | Core | T17 | 30 min |
| 19 | **Phase 2 Checkpoint** | Core | T18 | 15 min |
| 20 | Gradio Theme & CSS Setup | Core | T19 | 30 min |
| 21 | Gradio UI — Core Layout & Dashboard (S1) | Core | T20 | 45 min |
| 22 | Gradio UI — Patient Context & Recording (S2, S3) | Core | T21 | 45 min |
| 23 | Gradio UI — Processing, Review & Sign-off (S4, S5, S6) | Core | T22 | 45 min |
| 24 | UI ↔ Backend Data Binding | Core | T23 | 45 min |
| 25 | End-to-End Demo Scenario Testing (3 patients) | Core | T24 | 30 min |
| 26 | **Phase 3 Checkpoint — Integration Test Point 2** | Core | T25 | 20 min |
| 27 | Synthetic Training Data Generation | Polish | T26 | 45 min |
| 28 | LoRA Fine-tuning MedGemma 27B | Polish | T27 | 90 min |
| 29 | MedASR Evaluation (WER) | Polish | T26 | 30 min |
| 30 | EHR Agent Evaluation (Fact Recall) | Polish | T26 | 30 min |
| 31 | Document Generation Evaluation (BLEU/ROUGE-L) | Polish | T28 or T26 | 30 min |
| 32 | UI Visual Polish | Polish | T26 | 45 min |
| 33 | **Phase 4 Checkpoint** | Core | T26 + any completed T27–T32 | 15 min |
| 34 | HF Space Deployment | Core | T33 | 45 min |
| 35 | HF Hub LoRA Adapter Publication | Polish | T28,T34 | 20 min |
| 36 | GitHub Repo & README | Core | T34 | 45 min |
| 37 | Final Smoke Test & Submission Checklist | Core | T36 | 30 min |
| 38 | **Phase 5 Checkpoint — Final** | Core | T37 | 15 min |
**Total: 39 tasks. Estimated: ~20 hours of active work + 4 hours buffer.**
---
## PHASE 0 — Environment & Data Foundation (Hours 1–3)
**Phase goal:** Running project with configuration, synthetic FHIR data, mock FHIR API, and demo audio assets — everything downstream tasks depend on.
**Estimated time:** 3 hours
**Day-end checkpoint contribution:** Provides foundation for Day 1 (Hours 1–8).
**Context required:** `clarke_PRD_technical_spec.md` (§1–§3, §7–§8).
---
### Task 0: Read & Confirm Understanding
**Prerequisites:** None
**Priority:** Core
**Description:**
Before writing any code, read ALL of the following PRD files completely:
1. `clarke_PRD_masterplan.md` — vision, goals, constraints, success criteria
2. `clarke_PRD_implementation.md` — build phases, time allocation, dependency graph, fallback paths
3. `clarke_PRD_design_guidelines.md` — colour tokens, typography, spacing, animations
4. `clarke_PRD_userflow.md` — screens, states, navigation, demo golden path
5. `clarke_PRD_technical_spec.md` — directory tree, tech stack, data models, API contracts, model serving
After reading, output a structured summary demonstrating comprehension:
- **Product vision** (1–2 sentences from masterplan)
- **Number of screens** to build (from userflow)
- **Number of API endpoints** (from technical_spec §5)
- **The three HAI-DEF models**, their HuggingFace IDs, and their roles in the pipeline
- **Top 3 technical risks** and their fallback paths (from masterplan §8)
- **Must-have list** (from masterplan §12) — list all 10 items
**Files created or modified:** None
**"Done" criteria:** Summary is output and contains all 6 items listed above with correct details.
**Verification method:** Manual review of output. Spot-check: MedGemma 4B model ID should be `google/medgemma-1.5-4b-it` (not 1.0). Number of screens should be 6 (S1–S6). Number of API endpoints should be 12.
**If this fails:** Re-read the specific PRD where the information was missed.
---
### Task 1: Create Project Directory Structure
**Prerequisites:** Task 0
**Priority:** Core
**Description:**
Create the complete Clarke project directory tree exactly as defined in `clarke_PRD_technical_spec.md` §1. Create all directories and empty `__init__.py` files. Create placeholder files (empty or with a single docstring comment) for every file listed in the tree.
The top-level directory is `clarke/`. Key subdirectories:
- `backend/` — orchestrator, api, config, models/, fhir/, prompts/, schemas, audio, errors, utils
- `frontend/` — ui, theme, components, state, assets/
- `data/` — synthea/, fhir_bundles/, demo/, training/
- `finetuning/` — train_lora, generate_training_data, merge_adapter
- `evaluation/` — eval_medasr, eval_ehr_agent, eval_doc_gen, gold_standards/
- `tests/` — test files for each component
- `scripts/` — start.sh, health_check.sh, setup_fhir.sh
- Root files: app.py, Dockerfile, requirements.txt, .env.template, README.md, LICENSE
**Files created or modified:** All files and directories in the tree (~60 files).
**"Done" criteria:** The directory tree matches `clarke_PRD_technical_spec.md` §1 exactly. All `__init__.py` files exist. All placeholder files exist.
**Verification method:** `find clarke/ -type f | sort` output matches the spec tree. `python -c "import backend; import frontend"` succeeds (empty packages import fine).
**If this fails:** Compare find output to spec tree line-by-line and create missing files.
---
### Task 2: Configuration & Environment Setup
**Prerequisites:** Task 1
**Priority:** Core
**Description:**
2a. **`.env.template`** — Populate with all environment variables from `clarke_PRD_technical_spec.md` §3a. Include every variable with its default value and comment.
2b. **`backend/config.py`** — Create a centralised configuration module using `pydantic-settings` (or `python-dotenv` + dataclass). Load all env vars from `.env`. Include defaults matching the `.env.template`. Key config values:
- Model IDs: `MEDASR_MODEL_ID=google/medasr`, `MEDGEMMA_4B_MODEL_ID=google/medgemma-1.5-4b-it`, `MEDGEMMA_27B_MODEL_ID=google/medgemma-27b-text-it`
- FHIR: `FHIR_SERVER_URL=http://localhost:8080/fhir`, `USE_MOCK_FHIR=true`, `FHIR_TIMEOUT_S=10`
- App: `APP_PORT=7860`, `PIPELINE_TIMEOUT_S=120`, `DOC_GEN_MAX_TOKENS=2048`, `DOC_GEN_TEMPERATURE=0.3`
- Fine-tuning: `LORA_RANK=16`, `LORA_ALPHA=32`, `LEARNING_RATE=2e-4`, `TRAINING_EPOCHS=3`
2c. **`requirements.txt`** — List all dependencies with pinned versions from `clarke_PRD_technical_spec.md` §2. Include: torch, transformers, bitsandbytes, accelerate, peft, trl, datasets, gradio, fastapi, uvicorn, httpx, pydub, librosa, jinja2, jiwer, rouge_score, sacrebleu, reportlab, wandb, huggingface_hub, python-dotenv, loguru, pydantic.
2d. **`Dockerfile`** — Create the Dockerfile exactly as specified in `clarke_PRD_technical_spec.md` §3b.
2e. **`LICENSE`** — Apache 2.0 licence file.
2f. **`backend/errors.py`** — Create custom exception classes and logging configuration using loguru (see `clarke_PRD_technical_spec.md` §10c).
2g. **`backend/utils.py`** — Create shared utilities: timing decorator, JSON sanitisation function.
**Files created or modified:** `.env.template`, `backend/config.py`, `requirements.txt`, `Dockerfile`, `LICENSE`, `backend/errors.py`, `backend/utils.py`
**"Done" criteria:** `python -c "from backend.config import Settings; s = Settings(); print(s.MEDASR_MODEL_ID)"` prints `google/medasr`. All files exist and contain the specified content.
**Verification method:** Run the Python import command above. `cat requirements.txt | grep transformers` returns a version. `cat Dockerfile | grep nvidia` returns the CUDA base image line.
**If this fails:** Debug import errors. Ensure `.env` file exists (copy from `.env.template`).
---
### Task 3: Pydantic Data Models & Schemas
**Prerequisites:** Task 1
**Priority:** Core
**Description:**
Implement ALL Pydantic v2 data models in `backend/schemas.py` exactly as defined in `clarke_PRD_technical_spec.md` §4. This includes:
- **Enums:** `ConsultationStatus` (idle, recording, paused, processing, review, signed_off), `PipelineStage` (transcribing, retrieving_context, generating_document, complete, failed)
- **Models:** `Patient`, `LabResult`, `PatientContext`, `Transcript`, `DocumentSection`, `ClinicalDocument`, `Consultation`, `PipelineProgress`, `ErrorResponse`
Copy the exact field definitions, types, descriptions, and defaults from §4. Include all docstrings.
Also create `tests/test_schemas.py`:
- Test that each model validates with valid fixture data.
- Test that each model rejects invalid data (wrong types, missing required fields).
- Test enum values are correct.
**Files created or modified:** `backend/schemas.py`, `tests/test_schemas.py`
**"Done" criteria:** `pytest tests/test_schemas.py` passes with 0 failures.
**Verification method:** `pytest tests/test_schemas.py -v`
**If this fails:** Check field types and defaults against the spec. Common issue: `list[str]` syntax requires `from __future__ import annotations`.
---
### Task 4: Synthetic FHIR Patient Data
**Prerequisites:** Task 3
**Priority:** Core
**Description:**
Create FHIR Bundle JSON files for 5 demo patients in `data/fhir_bundles/`. These are pre-built JSON files that the mock FHIR API will serve. Each patient needs:
- **Patient resource** (demographics, NHS number, GP) — format per `clarke_PRD_technical_spec.md` §8c
- **Condition resources** (active diagnoses with SNOMED codes) — format per §8f
- **MedicationRequest resources** (current medications with BNF names, doses)
- **Observation resources** (recent lab results with LOINC codes, mmol/L units, reference ranges) — format per §8d
- **AllergyIntolerance resources** (allergies with reactions, severity) — format per §8e
- **DiagnosticReport resources** (imaging/reports)
Create one JSON Bundle file per patient: `pt-001.json` through `pt-005.json`.
**The 5 demo patients** (from `clarke_PRD_technical_spec.md` §8b):
| ID | Name | Age/Sex | Scenario | Key Data |
|---|---|---|---|---|
| pt-001 | Mrs. Margaret Thompson | 67F | T2DM, rising HbA1c | HbA1c 55 mmol/mol (was 48), eGFR 52, Penicillin allergy, Metformin 1g BD, Gliclazide 40mg OD |
| pt-002 | Mr. Emeka Okafor | 54M | Chest pain post-angiography | Normal coronaries, Troponin negative, BP 148/92, Aspirin 75mg, Atorvastatin 40mg |
| pt-003 | Ms. Priya Patel | 28F | Asthma review | Peak flow 320 (pred 450), Salbutamol 4x/week, no preventer currently |
| pt-004 | Mr. David Williams | 72M | Heart failure review | EF 35%, BNP 450 pg/mL, Bisoprolol 5mg, Ramipril 5mg, Furosemide 40mg |
| pt-005 | Mrs. Fatima Khan | 45F | Depression follow-up | PHQ-9 score 12, Sertraline 100mg |
Also create `data/clinic_list.json` exactly as specified in `clarke_PRD_technical_spec.md` §8h.
**Files created or modified:** `data/fhir_bundles/pt-001.json` through `pt-005.json`, `data/clinic_list.json`
**"Done" criteria:** All 5 JSON files are valid JSON. Each contains at minimum: 1 Patient, 2+ Conditions, 2+ MedicationRequests, 3+ Observations, 1+ AllergyIntolerance. `data/clinic_list.json` lists all 5 patients. `python -c "import json; [json.load(open(f'data/fhir_bundles/pt-00{i}.json')) for i in range(1,6)]"` succeeds.
**Verification method:** Run the Python JSON validation command above. Manually inspect `pt-001.json` to confirm Mrs Thompson has HbA1c=55, eGFR=52, Penicillin allergy.
**If this fails:** Fix JSON syntax errors. Ensure FHIR resource structure matches the examples in technical_spec §8c–§8f.
---
### Task 5: Mock FHIR API Server
**Prerequisites:** Task 4
**Priority:** Core
**Description:**
Implement `backend/fhir/mock_api.py` — a FastAPI application that serves FHIR-like REST endpoints using the pre-built JSON files from `data/fhir_bundles/`. This is the default for development and HF Spaces deployment (`USE_MOCK_FHIR=true`).
Endpoints to implement (mirroring HAPI FHIR patterns from `clarke_PRD_technical_spec.md` §7c):
```
GET /fhir/Patient/{patient_id} → returns Patient resource
GET /fhir/Patient?name={name}&_count=10 → search patients by name
GET /fhir/Condition?patient={id}&clinical-status=active → patient conditions
GET /fhir/MedicationRequest?patient={id}&status=active → patient medications
GET /fhir/Observation?patient={id}&category=laboratory&_sort=-date&_count=20 → lab results
GET /fhir/AllergyIntolerance?patient={id} → patient allergies
GET /fhir/DiagnosticReport?patient={id}&_sort=-date&_count=5 → reports
GET /fhir/Encounter?patient={id}&_sort=-date&_count=3 → recent encounters
```
The mock API loads all JSON bundles from `data/fhir_bundles/` at startup and indexes them by patient ID and resource type. Each endpoint filters and returns the appropriate resources in FHIR Bundle format.
Also create `tests/test_fhir_client.py` to test:
- Each endpoint returns 200 with valid FHIR JSON for known patients.
- Unknown patient returns 404 or empty Bundle.
- Endpoints handle query parameters correctly (patient filter, _count, _sort).
**Files created or modified:** `backend/fhir/mock_api.py`, `tests/test_fhir_client.py`
**"Done" criteria:** Mock FHIR API starts and responds correctly to all 8 endpoint patterns. `pytest tests/test_fhir_client.py` passes.
**Verification method:** Start the mock API (`python -m backend.fhir.mock_api &`), then: `curl http://localhost:8080/fhir/Patient/pt-001` returns Mrs Thompson's Patient resource with NHS number. `curl "http://localhost:8080/fhir/Observation?patient=pt-001&category=laboratory"` returns observations including HbA1c.
**If this fails:** Check JSON loading paths. Ensure Bundle files have correct resource indexing. Verify FastAPI route parameter parsing.
---
### Task 6: Demo Audio Files & Ground-Truth Transcripts
**Prerequisites:** Task 1
**Priority:** Core
**Description:**
Create 3 demo audio files and their corresponding ground-truth transcripts:
6a. **Ground-truth transcripts** — Create text files in `data/demo/`:
- `mrs_thompson_transcript.txt` — ~200 words. Simulated diabetes clinic consultation. Must mention: HbA1c, fatigue, thirst, gliclazide discussion, metformin continuation, blood test follow-up in 3 months.
- `mr_okafor_transcript.txt` — ~200 words. Chest pain follow-up. Must mention: angiogram results, normal coronaries, reassurance, blood pressure management, lifestyle advice.
- `ms_patel_transcript.txt` — ~200 words. Asthma review. Must mention: peak flow, salbutamol overuse, inhaler technique, preventer inhaler recommendation.
6b. **Audio files** — Generate WAV audio files (16kHz, mono, 60–90 seconds) for each transcript. Options:
- **Preferred:** Use a TTS engine (e.g., `edge-tts` or `gtts`) to generate speech from the transcripts, then convert with: `ffmpeg -i input.mp3 -ar 16000 -ac 1 -acodec pcm_s16le output.wav`
- **Fallback:** Create minimal valid WAV files with silence + a note that real audio will be recorded separately for the video.
Place files at: `data/demo/mrs_thompson.wav`, `data/demo/mr_okafor.wav`, `data/demo/ms_patel.wav`
**Files created or modified:** `data/demo/mrs_thompson_transcript.txt`, `data/demo/mr_okafor_transcript.txt`, `data/demo/ms_patel_transcript.txt`, `data/demo/mrs_thompson.wav`, `data/demo/mr_okafor.wav`, `data/demo/ms_patel.wav`
**"Done" criteria:** All 3 transcript files exist with ≥150 words each. All 3 WAV files exist, are valid audio, and are 16kHz mono. `ffprobe data/demo/mrs_thompson.wav` shows `16000 Hz, mono`.
**Verification method:** `wc -w data/demo/*_transcript.txt` shows ≥150 per file. `python -c "import librosa; y, sr = librosa.load('data/demo/mrs_thompson.wav', sr=None); assert sr == 16000; print(f'Duration: {len(y)/sr:.1f}s')"` succeeds.
**If this fails:** Re-run ffmpeg conversion with correct flags. If TTS fails, generate silence WAV: `ffmpeg -f lavfi -i anullsrc=r=16000:cl=mono -t 60 -acodec pcm_s16le output.wav`.
---
### Task 7: Phase 0 Checkpoint
**Prerequisites:** Tasks 2, 5, 6
**Priority:** Core
**Description:**
Run the complete Phase 0 verification suite. Confirm all foundation components are in place before proceeding to model pipeline work.
Verification checklist:
1. Project directory structure matches spec (`find clarke/ -type f | wc -l` ≥ 50 files).
2. `python -c "from backend.config import Settings; s = Settings(); print(s.MEDASR_MODEL_ID)"` prints `google/medasr`.
3. `pytest tests/test_schemas.py` passes.
4. Mock FHIR API starts and `curl http://localhost:8080/fhir/Patient/pt-001` returns valid JSON.
5. `data/clinic_list.json` has 5 patients.
6. 3 WAV files exist in `data/demo/` and are 16kHz mono.
7. 3 transcript files exist in `data/demo/`.
**Files created or modified:** None
**"Done" criteria:** All 7 checks pass.
**Verification method:** Run each check command above sequentially. Report pass/fail for each.
**If this fails:** Fix the specific failing check, then re-run the entire checkpoint.
---
## PHASE 1 — Core Model Pipelines (Hours 4–8)
**Phase goal:** MedASR transcription pipeline + MedGemma 4B EHR agent + orchestrator connecting them. Backend-only — no UI yet.
**Estimated time:** 5 hours
**Day-end checkpoint contribution:** Completes Day 1 checkpoint (all 6 items from implementation.md §5).
**Context required:** `clarke_PRD_technical_spec.md` (§6a–§6b, §7, §9), `clarke_PRD_implementation.md` (§2–§3 Phase 1).
---
### Task 8: MedASR Model Loading & Audio Preprocessing
**Prerequisites:** Task 7
**Priority:** Core
**Description:**
8a. **`backend/audio.py`** — Implement audio format conversion utilities:
- `convert_to_wav_16k(input_path: str, output_path: str) -> str` — Converts any audio format (WebM, MP3, etc.) to 16kHz mono WAV using pydub + ffmpeg. Exactly as specified in `clarke_PRD_technical_spec.md` §9e.
- `validate_audio(file_path: str) -> dict` — Checks: sample rate = 16000, channels = 1, duration > 5s and < 1800s. Returns dict with duration_s, sample_rate, channels. Raises `AudioError` on failure.
8b. **`backend/models/model_manager.py`** — Implement shared model lifecycle:
- `ModelManager` class that tracks loaded models, monitors GPU VRAM (`torch.cuda.memory_allocated()`), and provides `clear_cache()` (calls `torch.cuda.empty_cache()`).
- Method `check_gpu()` — returns GPU name, VRAM used, VRAM total. Returns mock data if no GPU.
8c. **`backend/models/medasr.py`** — Implement MedASR loading:
- Load model using `transformers.pipeline("automatic-speech-recognition", model="google/medasr", device="cuda:0")` — or return mock if `MEDASR_MODEL_ID == "mock"`.
- `load_model()` — loads the pipeline. Called once at startup.
- `transcribe(audio_path: str) -> Transcript` — loads audio via librosa at 16kHz, runs pipeline with `chunk_length_s=20, stride_length_s=(4, 2), return_timestamps=True`. Returns `Transcript` schema.
- **Mock mode:** If model ID is "mock", return the ground-truth transcript from `data/demo/{patient}_transcript.txt` for known demo files, or a generic placeholder for unknown audio.
**Files created or modified:** `backend/audio.py`, `backend/models/model_manager.py`, `backend/models/medasr.py`, `tests/test_medasr.py`
**"Done" criteria:** In mock mode: `python -c "from backend.models.medasr import MedASRModel; m = MedASRModel(); t = m.transcribe('data/demo/mrs_thompson.wav'); print(t.text[:50])"` prints the first 50 chars of the Thompson transcript. Audio conversion: converting a test file produces valid 16kHz mono WAV.
**Verification method:** Run the Python command above. `pytest tests/test_medasr.py` passes (test mock mode + audio validation).
**If this fails:** Check librosa/pydub installation. If GPU not available, ensure mock mode activates correctly based on config.
---
### Task 9: MedASR Transcription Pipeline
**Prerequisites:** Task 8
**Priority:** Core
**Description:**
Create the FastAPI transcription endpoint and wire it to MedASR.
9a. **`backend/api.py`** — Add these endpoints (from `clarke_PRD_technical_spec.md` §5):
- `GET /api/v1/health` — Returns system health status including model loaded states and FHIR status. Schema per §5b.
- `POST /api/v1/consultations/{id}/audio` — Accepts multipart form-data with `audio_file` (WAV or WebM) and `is_final` boolean. Saves audio, converts to 16kHz WAV if needed, returns duration.
9b. Wire the `/audio` endpoint to call `backend/audio.py` for conversion and store the audio file path in an in-memory consultation store (dict keyed by consultation ID).
9c. Create `tests/test_api.py` — Test `/health` returns 200 with correct schema. Test `/consultations/{id}/audio` accepts a WAV file and returns duration.
**Files created or modified:** `backend/api.py`, `tests/test_api.py`
**"Done" criteria:** FastAPI app starts. `curl localhost:8000/api/v1/health` returns 200 with JSON containing `models` key. Uploading a WAV file to `/consultations/test-001/audio` returns 200 with `duration_s`.
**Verification method:** Start FastAPI (`uvicorn backend.api:app --port 8000 &`), run curl commands, `pytest tests/test_api.py`.
**If this fails:** Check FastAPI route definitions. Ensure multipart form handling is correct.
---
### Task 10: FHIR Client & Tool Functions
**Prerequisites:** Task 5
**Priority:** Core
**Description:**
10a. **`backend/fhir/client.py`** — Implement async FHIR REST client using httpx:
- `FHIRClient` class initialised with `fhir_server_url` and `timeout_s` from config.
- Async methods for each FHIR query pattern from `clarke_PRD_technical_spec.md` §7c.
- Handle 404 (return empty), timeout (raise with context), 5xx (retry once, then raise).
- Return raw JSON dicts.
10b. **`backend/fhir/tools.py`** — Implement the 7 FHIR tool functions specified in `clarke_PRD_technical_spec.md` §6b:
```python
async def search_patients(name: str) -> list[dict]
async def get_conditions(patient_id: str) -> list[dict]
async def get_medications(patient_id: str) -> list[dict]
async def get_observations(patient_id: str, category: str = "laboratory") -> list[dict]
async def get_allergies(patient_id: str) -> list[dict]
async def get_diagnostic_reports(patient_id: str) -> list[dict]
async def get_recent_encounters(patient_id: str) -> list[dict]
```
Each wraps a `FHIRClient` call and extracts the relevant entries from the Bundle response.
10c. **`backend/fhir/queries.py`** — Implement deterministic FHIR query fallback:
- `get_full_patient_context(patient_id: str) -> dict` — Calls ALL 7 tool functions for a patient and aggregates results into a raw context dict. This is the fallback if MedGemma 4B agentic tool-calling fails.
**Files created or modified:** `backend/fhir/client.py`, `backend/fhir/tools.py`, `backend/fhir/queries.py`
**"Done" criteria:** With mock FHIR running: `python -c "import asyncio; from backend.fhir.queries import get_full_patient_context; r = asyncio.run(get_full_patient_context('pt-001')); print(list(r.keys()))"` prints keys including conditions, medications, observations, allergies.
**Verification method:** Run the Python command above. Each key should contain non-empty lists for pt-001.
**If this fails:** Check mock FHIR is running. Verify URL construction in client.py matches mock API routes.
---
### Task 11: MedGemma 4B EHR Agent — Loading & Context Retrieval
**Prerequisites:** Task 10
**Priority:** Core
**Description:**
Implement the EHR context retrieval agent in `backend/models/ehr_agent.py`.
**Primary implementation (deterministic FHIR + MedGemma 4B summarisation):**
Given the known instruction-following bugs with MedGemma 4B (see `clarke_PRD_technical_spec.md` §12, Pitfall 1), start with the **deterministic fallback** approach — it's more reliable and the narrative still works:
1. Call `get_full_patient_context(patient_id)` from `backend/fhir/queries.py` to retrieve all raw FHIR data.
2. Load MedGemma 4B in 4-bit quantised mode (config from `clarke_PRD_technical_spec.md` §6b):
```python
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16, bnb_4bit_use_double_quant=True
)
```
3. Pass raw FHIR JSON to MedGemma 4B with the context synthesis prompt (from `backend/prompts/context_synthesis.j2`) asking it to produce a structured `PatientContext` JSON.
4. Parse output using `parse_agent_output()` from `clarke_PRD_technical_spec.md` §6b — strip system prompt leaks, extract JSON, validate against `PatientContext` schema.
5. If parsing fails after 2 retries, construct `PatientContext` directly from raw FHIR data without MedGemma summarisation (hardcoded extraction logic).
**Mock mode:** If model ID is "mock", return a pre-built PatientContext JSON for known patient IDs.
Also implement `parse_agent_output(raw_output: str) -> dict` exactly as specified in §6b — with regex to strip system prompt leaks, markdown fences, and extract first JSON object.
**Files created or modified:** `backend/models/ehr_agent.py`, `tests/test_ehr_agent.py`
**"Done" criteria:** In mock mode: calling `get_patient_context("pt-001")` returns a valid `PatientContext` with Mrs Thompson's data (problem_list includes diabetes, medications include metformin, allergies include penicillin). `pytest tests/test_ehr_agent.py` passes.
**Verification method:** `python -c "from backend.models.ehr_agent import EHRAgent; a = EHRAgent(); ctx = a.get_patient_context('pt-001'); print(ctx.allergies)"` outputs penicillin allergy data.
**If this fails:** Check FHIR data loading. Verify parse_agent_output handles edge cases. If MedGemma 4B outputs are garbled, the hardcoded extraction fallback should still produce valid context.
**⚠️ FALLBACK DECISION POINT:** If MedGemma 4B produces entirely unusable output after loading (not just in mock mode, but on real inference), stay with deterministic FHIR extraction. The pipeline narrative is preserved — MedGemma 4B is still "understanding" the EHR data through the summarisation step. See `clarke_PRD_implementation.md` §7, Fallback Path #2.
---
### Task 12: Orchestrator — Pipeline Coordinator
**Prerequisites:** Tasks 9, 11
**Priority:** Core
**Description:**
Implement `backend/orchestrator.py` — the core pipeline coordinator that connects all three model stages.
The orchestrator manages the consultation lifecycle:
1. **start_consultation(patient_id)** — Creates a Consultation object, triggers EHR agent in background to pre-fetch patient context, returns consultation ID. Sets status to `recording`.
2. **end_consultation(consultation_id)** — Stops recording, runs the full pipeline:
- Stage 1: Finalise transcript via MedASR (from uploaded audio)
- Stage 2: Synthesise patient context via EHR Agent (may already be cached from start)
- Stage 3: Combine transcript + context into document-generation prompt (Phase 2 will add MedGemma 27B generation)
- Updates `PipelineProgress` at each stage
3. **get_consultation(consultation_id)** — Returns current Consultation state.
4. **get_progress(consultation_id)** — Returns current PipelineProgress.
Wire the remaining API endpoints from `clarke_PRD_technical_spec.md` §5:
- `GET /api/v1/patients` — returns clinic list from `data/clinic_list.json`
- `GET /api/v1/patients/{patient_id}` — returns single patient
- `POST /api/v1/patients/{patient_id}/context` — triggers EHR agent
- `POST /api/v1/consultations/start` — calls orchestrator.start_consultation
- `POST /api/v1/consultations/{id}/end` — calls orchestrator.end_consultation
- `GET /api/v1/consultations/{id}/transcript` — returns transcript
- `GET /api/v1/consultations/{id}/document` — returns document (empty for now)
- `GET /api/v1/consultations/{id}/progress` — returns pipeline progress
In-memory consultation store: `dict[str, Consultation]` keyed by consultation_id.
**Files created or modified:** `backend/orchestrator.py`, `backend/api.py` (update with all endpoints)
**"Done" criteria:** Start mock FHIR + FastAPI. Calling `POST /consultations/start` with `{"patient_id": "pt-001"}` returns 201 with consultation_id. Calling `POST /consultations/{id}/audio` with a WAV file, then `POST /consultations/{id}/end` triggers the pipeline and returns 202. `GET /consultations/{id}/progress` shows stage transitions.
**Verification method:** `pytest tests/test_api.py` passes (update tests for new endpoints). Manual curl sequence through the flow.
**If this fails:** Debug orchestrator state management. Ensure consultation store is correctly updated at each stage.
---
### Task 13: Prompt Templates (EHR Agent + Document Generation)
**Prerequisites:** Task 12
**Priority:** Core
**Description:**
Create the Jinja2 prompt templates that combine transcript and context for document generation.
13a. **`backend/prompts/ehr_agent_system.txt`** — The EHR agent system prompt, exactly as specified in `clarke_PRD_technical_spec.md` §6b. This instructs MedGemma 4B on how to synthesise FHIR data into PatientContext JSON.
13b. **`backend/prompts/context_synthesis.j2`** — Jinja2 template that wraps raw FHIR data and asks MedGemma 4B to produce structured context JSON. Variables: `{{ raw_fhir_data }}`, `{{ patient_id }}`.
13c. **`backend/prompts/document_generation.j2`** — The document generation prompt template exactly as specified in `clarke_PRD_technical_spec.md` §6c. This is the prompt sent to MedGemma 27B. Variables: `{{ letter_date }}`, `{{ clinician_name }}`, `{{ clinician_title }}`, `{{ transcript }}`, `{{ context_json }}`.
Verify that the orchestrator can render the document generation prompt by combining a mock transcript and mock context into the template.
**Files created or modified:** `backend/prompts/ehr_agent_system.txt`, `backend/prompts/context_synthesis.j2`, `backend/prompts/document_generation.j2`
**"Done" criteria:** `python -c "from jinja2 import Environment, FileSystemLoader; env = Environment(loader=FileSystemLoader('backend/prompts')); t = env.get_template('document_generation.j2'); print(t.render(letter_date='13 Feb 2026', clinician_name='Dr. Chen', clinician_title='Consultant', transcript='test', context_json='{}')[:100])"` prints the rendered prompt start.
**Verification method:** Run the command above. The output should contain "NHS clinical documentation assistant" and the rendered transcript.
**If this fails:** Check template syntax. Ensure Jinja2 variables match the expected names.
---
### Task 14: Phase 1 Checkpoint — Integration Test Point 1
**Prerequisites:** Task 13
**Priority:** Core
**Description:**
This is **Integration Test Point 1** from `clarke_PRD_implementation.md` §8. Run the Mrs Thompson demo scenario end-to-end through the backend (no UI yet):
1. Feed `data/demo/mrs_thompson.wav` to MedASR → capture transcript.
2. Feed patient ID `pt-001` to EHR Agent → capture context JSON.
3. Combine into document-generation prompt → print to console.
4. **Verify the combined prompt contains:**
- (a) Transcript text mentioning HbA1c, fatigue, gliclazide
- (b) FHIR-sourced values: HbA1c 55 mmol/mol, eGFR 52, Penicillin allergy
This can run in mock mode — the point is verifying the *fusion* of transcript + context into a well-formed prompt.
Create `tests/test_e2e.py` with a test for this scenario.
Also run the full test suite: `pytest tests/` to confirm no regressions.
**Files created or modified:** `tests/test_e2e.py` (add `test_mrs_thompson_fusion`)
**"Done" criteria:** The rendered document-generation prompt contains both: (1) transcript text with clinical content, and (2) FHIR-sourced patient context with lab values, medications, and allergies. `pytest tests/ -v` passes with 0 failures.
**Verification method:** `pytest tests/test_e2e.py::test_mrs_thompson_fusion -v` passes. Manually inspect printed prompt output.
**If this fails:** Debug which stage produced empty output. If transcript is empty, check MedASR mock. If context is empty, check FHIR mock data loading. If prompt is malformed, check Jinja2 template rendering.
**📌 DAY 1 DECISION POINT:** If this checkpoint fails, do NOT proceed to Phase 2. Fix the fusion point first — everything downstream depends on it.
---
## PHASE 2 — Document Generation & End-to-End Pipeline (Hours 9–12)
**Phase goal:** MedGemma 27B loaded and generating clinic letters. Complete backend pipeline: audio → transcript → context → letter.
**Estimated time:** 4 hours
**Day-end checkpoint contribution:** Achieves Minimum Viable Demo backend (implementation.md §6).
**Context required:** `clarke_PRD_technical_spec.md` (§6c, §10), `clarke_PRD_implementation.md` (§3 Phase 2).
---
### Task 15: MedGemma 27B Loading & Baseline Generation
**Prerequisites:** Task 14
**Priority:** Core
**Description:**
Implement `backend/models/doc_generator.py` — the document generation module using MedGemma 27B.
**Loading (from `clarke_PRD_technical_spec.md` §6c):**
```python
bnb_config = BitsAndBytesConfig(
load_in_4bit=True, bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16, bnb_4bit_use_double_quant=True
)
model = AutoModelForCausalLM.from_pretrained(
"google/medgemma-27b-text-it", quantization_config=bnb_config,
device_map="auto", torch_dtype=torch.bfloat16
)
```
**Generation parameters:** `max_new_tokens=2048, temperature=0.3, top_p=0.9, top_k=40, do_sample=True, repetition_penalty=1.1`
**Interface:**
- `load_model()` — loads model + tokenizer. If model ID is "mock", set flag.
- `generate(prompt: str) -> str` — runs inference, returns raw text.
- `generate_document(transcript: str, context: PatientContext) -> ClinicalDocument` — renders the Jinja2 prompt, calls generate, parses output into ClinicalDocument sections.
- **Output parsing:** Split generated text into `DocumentSection` objects by detecting section headings.
- **Mock mode:** Return a pre-written reference letter.
**Timeout:** 90s. **Retry:** 1 retry with reduced `max_new_tokens=1024`.
Generate 3 baseline letters using the combined prompts from Task 13 (one per demo patient). Save to `data/demo/baseline_letters/`.
**Files created or modified:** `backend/models/doc_generator.py`, `tests/test_doc_generator.py`, `data/demo/baseline_letters/` (3 files)
**"Done" criteria:** In mock mode: `generate_document()` returns a valid `ClinicalDocument` with ≥4 sections. On GPU: MedGemma 27B loads without OOM and generates coherent medical text. `pytest tests/test_doc_generator.py` passes.
**Verification method:** Run tests. On GPU, generate one letter and manually verify it's coherent medical text.
**If this fails:** **⚠️ FALLBACK TRIGGER:** If MedGemma 27B fails to load after 2 attempts (OOM on A100 40GB at 4-bit):
1. Try GGUF Q8_0 via Ollama — switch inference to Ollama REST API. See `clarke_PRD_implementation.md` §7, Fallback Path A.
2. If Ollama also fails — use MedGemma 4B for document generation with extensive prompt engineering. This changes Tasks 16–17 to use 4B instead of 27B. Quality drops but pipeline remains functional.
---
### Task 16: Document Generation Prompt Engineering
**Prerequisites:** Task 15
**Priority:** Core
**Description:**
Iterate on the document-generation prompt to maximise NHS letter quality:
1. Start with the base prompt from `backend/prompts/document_generation.j2`.
2. Generate 3 letters (one per demo patient) using the base prompt.
3. Review each letter for:
- NHS letter structure (date, addressee, Re: line, salutation, sections, sign-off)
- Correct use of FHIR-sourced lab values (exact numbers, not fabricated)
- British medical English (third person, past tense, formal)
- Reasonable length (300–500 words)
4. Iterate on the prompt: add exemplar fragments, strengthen format instructions, add negative examples (what NOT to do).
5. Regenerate 3 letters with the improved prompt.
6. Save the best prompt version as the final `document_generation.j2`.
Key improvements to try:
- Add a brief exemplar letter snippet showing correct NHS format
- Add explicit instructions: "Use EXACT values from patient context — do not round or fabricate"
- Add: "Include both positive AND negative findings from the consultation"
- Add: "If a discussed value differs from the record, mark with [DISCREPANCY]"
**Files created or modified:** `backend/prompts/document_generation.j2` (updated)
**"Done" criteria:** 3 regenerated letters visually conform to NHS clinic letter format. Each letter contains FHIR-sourced values (spot-check: Mrs Thompson letter includes HbA1c 55 and eGFR 52). Letters are 300–500 words.
**Verification method:** Manual review of 3 generated letters. Check for the presence of specific FHIR values.
**If this fails:** Continue iterating on the prompt. If quality plateaus, document the best prompt and move on — prompt engineering has diminishing returns after 3–4 iterations.
---
### Task 17: End-to-End Backend Pipeline Wiring
**Prerequisites:** Task 16
**Priority:** Core
**Description:**
Connect the `/consultations/{id}/end` endpoint to the full pipeline including MedGemma 27B document generation:
1. Update `backend/orchestrator.py``end_consultation()` now:
- Stage 1: Transcribe audio via MedASR → Transcript
- Stage 2: Retrieve patient context via EHR Agent → PatientContext (may already be cached)
- Stage 3: Generate document via MedGemma 27B → ClinicalDocument
- Update PipelineProgress at each stage
- Store final ClinicalDocument in Consultation object
- Set status to `review`
2. Update `backend/api.py`:
- `GET /consultations/{id}/document` returns the generated ClinicalDocument
- `POST /consultations/{id}/document/sign-off` updates status to signed_off
- `POST /consultations/{id}/document/regenerate-section` regenerates one section
3. Add latency logging: total pipeline time, time per stage.
Wire `torch.cuda.empty_cache()` between each model's inference step (see `clarke_PRD_technical_spec.md` §12, Pitfall 3).
**Files created or modified:** `backend/orchestrator.py` (major update), `backend/api.py` (add document endpoints)
**"Done" criteria:** Complete pipeline works: `POST /consultations/start` → `POST /consultations/{id}/audio` (upload WAV) → `POST /consultations/{id}/end` → `GET /consultations/{id}/document` returns a ClinicalDocument with ≥4 sections. Total latency <60s on GPU (or <5s in mock mode).
**Verification method:** Run the full API flow with curl commands. Check that the returned document JSON has sections with headings and content. Check latency logged in stdout.
**If this fails:** Debug stage by stage. Check orchestrator state transitions. Ensure `torch.cuda.empty_cache()` is called between models.
---
### Task 18: Pipeline Hardening — Error Handling & Timeouts
**Prerequisites:** Task 17
**Priority:** Core
**Description:**
Add error handling for all failure modes defined in `clarke_PRD_technical_spec.md` §10:
1. **Pipeline timeout:** `asyncio.wait_for()` wrapper with `PIPELINE_TIMEOUT_S=120`. If exceeded, return `ErrorResponse` with `error="timeout"`.
2. **OOM recovery:** Catch `torch.cuda.OutOfMemoryError`, call `empty_cache()`, reduce `max_new_tokens` by 50%, retry once.
3. **Empty transcript handling:** If MedASR returns empty text, return `ErrorResponse` with `error="audio_error"` and message "Audio could not be transcribed."
4. **FHIR failure degradation:** If EHR Agent fails or FHIR is unreachable, continue with transcript-only document generation. Add warning to `PatientContext.retrieval_warnings`.
5. **Empty/corrupted audio:** Validate audio before MedASR. Return `ErrorResponse` for invalid files.
Test 3 error scenarios:
- Empty audio file → error response
- FHIR server unavailable → document generated from transcript only
- Oversized context (>4096 tokens) → context truncated, generation proceeds
**Files created or modified:** `backend/orchestrator.py` (add error handling), `tests/test_e2e.py` (add error scenario tests)
**"Done" criteria:** All 3 error scenarios handled gracefully — no crashes, informative error messages returned. `pytest tests/test_e2e.py` passes including error scenario tests.
**Verification method:** `pytest tests/test_e2e.py -v` passes. Specifically: `test_pipeline_timeout`, `test_fhir_failure_degradation`, `test_empty_audio` all pass.
**If this fails:** Check exception handling order. Ensure `try/except` blocks don't swallow errors silently.
---
### Task 19: Phase 2 Checkpoint
**Prerequisites:** Task 18
**Priority:** Core
**Description:**
Run the full Phase 2 verification:
1. Full pipeline test: Upload Mrs Thompson WAV → transcript → context → letter. Letter contains HbA1c 55 and eGFR 52.
2. All 3 demo patients produce clinically coherent letters via the pipeline.
3. Pipeline latency <60s on GPU (or <5s in mock mode).
4. Error scenarios pass (empty audio, FHIR down, timeout).
5. `pytest tests/ -v` — all tests pass, 0 failures.
**Files created or modified:** None
**"Done" criteria:** All 5 checks pass.
**Verification method:** Run each check. Full test suite: `pytest tests/ -v`.
**If this fails:** Fix failing tests/scenarios before proceeding to UI work.
---
## PHASE 3 — UI Build & Integration (Hours 13–16)
**Phase goal:** Functional Gradio UI connected to the backend. Complete end-to-end demo working in browser.
**Estimated time:** 4 hours
**Day-end checkpoint contribution:** Achieves Integration Test Point 2 (implementation.md §8).
**Context required:** `clarke_PRD_technical_spec.md` (§9), `clarke_PRD_design_guidelines.md` (§1–§5), `clarke_PRD_userflow.md` (all sections).
---
### Task 20: Gradio Theme & CSS Setup
**Prerequisites:** Task 19
**Priority:** Core
**Description:**
Create the visual foundation for Clarke's UI.
20a. **`frontend/theme.py`** — Create a Gradio theme using Clarke's colour tokens from `clarke_PRD_design_guidelines.md` §1:
- Primary colour: `#1E3A5F` (clarke-blue)
- Secondary colour: `#D4A035` (clarke-gold)
- Background: `#FAFBFD` (clarke-bg-primary)
- Text: `#1A1A2E` (clarke-text-primary)
- Use `gr.themes.Base()` as starting point, override colours.
20b. **`frontend/assets/style.css`** — Custom CSS with:
- All CSS custom properties from design_guidelines §1 (--clarke-blue, --clarke-gold, etc.)
- Hero gradient background (§1 gradient spec)
- Typography: Inter font import, type scale (§2)
- Card styling: border-radius 12px, shadow, hover effects (§3, §4)
- Paper container for document display: max-width 720px, centered, inset shadow (§4.6 from userflow)
- Recording pulse animation keyframes (§4.5 from design_guidelines)
- Skeleton loader animation (shimmer effect)
20c. **`frontend/assets/clarke_logo.svg`** — Create a simple SVG logo (shield/C shape in clarke-blue and clarke-gold).
**Files created or modified:** `frontend/theme.py`, `frontend/assets/style.css`, `frontend/assets/clarke_logo.svg`
**"Done" criteria:** Theme and CSS files exist with all specified tokens. A minimal Gradio app using the theme renders with Clarke colours.
**Verification method:** `python -c "import gradio as gr; from frontend.theme import clarke_theme; demo = gr.Blocks(theme=clarke_theme, css='frontend/assets/style.css'); demo.launch(prevent_thread_lock=True)"` launches without error and shows Clarke styling.
**If this fails:** Check CSS syntax. Ensure theme object is a valid `gr.Theme`.
---
### Task 21: Gradio UI — Core Layout & Dashboard (S1)
**Prerequisites:** Task 20
**Priority:** Core
**Description:**
Build the main UI structure and the Dashboard screen (S1) in `frontend/ui.py`.
The `build_ui()` function returns a `gr.Blocks` layout with:
1. **Top bar:** Clarke logo, "Clarke" text, status indicator.
2. **Main content area** — uses `gr.Column` with visibility toggling to switch between screens (S1–S6).
3. **S1 — Dashboard:**
- Clinic header: "Dr. Sarah Chen — Diabetes & Endocrinology — 13 February 2026"
- Hero gradient background (via CSS class)
- Patient card list: 5 cards, each showing name, age/sex, appointment time, one-line summary
- Cards are `gr.Button` styled as cards (or `gr.HTML` with click events)
- Clicking a card triggers patient selection → transition to S2
4. **`frontend/state.py`** — Implement state management:
- `gr.State` holds current screen name, consultation object, selected patient
- Screen visibility functions: `show_screen(screen_name)` returns visibility updates for all screen containers
5. **`frontend/components.py`** — Reusable component builders:
- `build_patient_card(patient: dict) -> gr.HTML` — renders a styled patient card
- `build_status_badge(status: str) -> gr.HTML` — renders status badge with appropriate colour
Also create `app.py` — the entry point that mounts Gradio + FastAPI together (per `clarke_PRD_technical_spec.md` §9a):
```python
demo = build_ui()
demo = gr.mount_gradio_app(fast_api, demo, path="/")
```
**Files created or modified:** `frontend/ui.py`, `frontend/state.py`, `frontend/components.py`, `app.py`
**"Done" criteria:** `python app.py` launches at localhost:7860. Dashboard shows 5 patient cards with correct names and details. Clicking a card triggers a visible event (even if transition is not yet complete).
**Verification method:** Launch app, open browser to localhost:7860. Visual check: 5 patient cards are visible. `data/clinic_list.json` data is rendered correctly.
**If this fails:** Check Gradio Blocks layout. Ensure `clinic_list.json` is loaded correctly. Verify CSS is applied.
---
### Task 22: Gradio UI — Patient Context & Recording (S2, S3)
**Prerequisites:** Task 21
**Priority:** Core
**Description:**
Build screens S2 (Patient Context) and S3 (Live Consultation).
**S2 — Patient Context:**
- Left panel: Patient context display with sections: Demographics, Problem List, Medications, Allergies (highlighted with ⚠), Recent Labs (with trend arrows ↑↓), Recent Imaging, Clinical Flags
- Centre panel: Empty document area with CTA text "Start Consultation" and "Back to Dashboard" button
- On patient selection: call EHR Agent (or mock) to get PatientContext, populate left panel
- Skeleton loaders while context loads (CSS shimmer animation)
**S3 — Live Consultation:**
- Recording indicator (gold pulsing circle, using CSS animation from Task 20)
- Timer showing elapsed time (MM:SS format, updated via `gr.Timer`)
- Audio capture: use `gr.Audio(sources=["microphone"], streaming=False)` as the pragmatic Gradio approach (capture complete audio, not streaming chunks). If Gradio streaming works, use it; otherwise, capture entire audio on "End Consultation".
- "End Consultation" button (primary style)
- Expandable transcript panel (initially minimised, shows transcript after processing)
- Patient context remains visible on the left (collapsed summary)
Wire the screen transitions:
- S1 → S2: Patient card click → load context → show S2
- S2 → S3: "Start Consultation" click → show S3, start audio capture
- S2 → S1: "Back to Dashboard" → show S1
**Files created or modified:** `frontend/ui.py` (add S2, S3)
**"Done" criteria:** Select a patient on S1 → S2 loads with patient context (from mock/API). Click "Start Consultation" → S3 shows with recording indicator and audio capture widget. "Back to Dashboard" returns to S1.
**Verification method:** Visual check through the flow: S1 → click patient → S2 shows context → click Start → S3 shows recording UI.
**If this fails:** Debug Gradio event handlers. Ensure `gr.State` updates correctly. If audio capture fails, use `gr.Audio(sources=["upload"])` as fallback.
---
### Task 23: Gradio UI — Processing, Review & Sign-off (S4, S5, S6)
**Prerequisites:** Task 22
**Priority:** Core
**Description:**
Build screens S4 (Processing), S5 (Document Review), and S6 (Signed Off).
**S4 — Processing:**
- Three-stage progress indicator showing: "Finalising transcript…" → "Synthesising patient context…" → "Generating clinical letter…"
- Use `gr.Timer(every=1)` to poll pipeline progress and update the stage display
- Simple progress bar (3 segments) with the active segment highlighted in clarke-blue
- Elapsed timer
- "Cancel" button (secondary, destructive)
**S5 — Document Review:**
- Centre panel: Generated NHS clinic letter rendered in a paper container (max-width 720px, white, subtle shadow)
- Letter displayed section by section using `gr.Textbox(interactive=True)` for each section (allowing inline editing)
- FHIR-sourced values: wrap in monospace spans via `gr.HTML` or `gr.Markdown`
- Status badge: "Ready for Review" (amber)
- "Sign Off & Export" button (primary)
- "Regenerate Entire Letter" button (secondary)
- Left panel: collapsed patient context summary
**S6 — Signed Off:**
- Read-only letter display
- Status badge: "Signed Off" (green ✓)
- Export buttons: "Copy to Clipboard", "Download as Text"
- "Next Patient" button → returns to S1 with next patient highlighted
Wire transitions:
- S3 → S4: "End Consultation" → upload audio → trigger pipeline → show S4
- S4 → S5: Pipeline complete → show S5 with generated document
- S5 → S6: "Sign Off" → mark signed → show S6
- S6 → S1: "Next Patient" → reset state → show S1
**Files created or modified:** `frontend/ui.py` (add S4, S5, S6)
**"Done" criteria:** All 6 screens exist and are navigable. The complete flow S1→S2→S3→S4→S5→S6→S1 works with mock data.
**Verification method:** Visual walk-through of entire flow using mock mode. Each screen renders correct content.
**If this fails:** Focus on getting the flow working with minimal styling. Polish comes later. If `gr.Timer` polling is problematic, use a simpler approach (single blocking call with loading indicator).
---
### Task 24: UI ↔ Backend Data Binding
**Prerequisites:** Task 23
**Priority:** Core
**Description:**
Connect all UI interactions to the real backend:
1. **Patient selection (S1 → S2):** Card click calls `POST /patients/{id}/context` → context panel populates with real FHIR data.
2. **Start Consultation (S2 → S3):** Calls `POST /consultations/start` with patient_id → stores consultation_id in `gr.State`.
3. **Audio capture (S3):** Gradio audio component captures audio. On "End Consultation", uploads audio to `POST /consultations/{id}/audio` then calls `POST /consultations/{id}/end`.
4. **Processing (S4):** Polls `GET /consultations/{id}/progress` every second. Updates stage labels. When stage = "complete", fetches document from `GET /consultations/{id}/document` and transitions to S5.
5. **Document display (S5):** Renders `ClinicalDocument` sections as editable textboxes. Each section shows heading + content.
6. **Sign Off (S5 → S6):** Calls `POST /consultations/{id}/document/sign-off` with any edited sections.
7. **Next Patient (S6 → S1):** Resets `gr.State`, returns to dashboard.
Ensure the backend calls work correctly with both mock mode and real model mode.
**Files created or modified:** `frontend/ui.py` (major update — event binding), `frontend/state.py` (update)
**"Done" criteria:** In mock mode: the complete flow works end-to-end in the browser. Select patient → context loads → start consultation → provide audio → end → processing animation → letter appears → edit → sign off → export → next patient.
**Verification method:** Full manual walkthrough in browser at localhost:7860. Each step produces the expected result.
**If this fails:** Debug one step at a time. Check browser console for JavaScript errors. Check server logs for API errors. The most likely failure points are: audio upload format, progress polling timing, and state management.
---
### Task 25: End-to-End Demo Scenario Testing (3 patients)
**Prerequisites:** Task 24
**Priority:** Core
**Description:**
Test all 3 demo scenarios completely:
1. **Mrs Thompson (pt-001):** Upload `mrs_thompson.wav` → transcript mentions diabetes topics → context shows HbA1c 55, eGFR 52, Penicillin allergy → letter includes these values → edit one line → sign off.
2. **Mr Okafor (pt-002):** Upload `mr_okafor.wav` → transcript mentions chest pain → context shows normal coronaries → letter discusses angiogram results → sign off.
3. **Ms Patel (pt-003):** Upload `ms_patel.wav` → transcript mentions asthma → context shows peak flow 320 → letter recommends preventer inhaler → sign off.
For each scenario:
- Verify correct transcription (transcript text is clinically relevant)
- Verify correct context (FHIR data matches patient)
- Verify letter quality (contains both transcript content AND FHIR values)
- Verify editing works (change one paragraph)
- Verify sign-off works
Fix any bugs discovered during testing.
**Files created or modified:** Bug fixes in various files
**"Done" criteria:** All 3 scenarios complete without crashes. Generated letters are clinically appropriate for each patient.
**Verification method:** Manual run-through of each scenario in browser. Screenshot or note the key assertion for each (e.g., "Thompson letter contains HbA1c 55").
**If this fails:** Fix bugs for each specific scenario. Most common issues: wrong patient context loaded, transcript doesn't match audio file, document parsing fails for certain prompt outputs.
---
### Task 26: Phase 3 Checkpoint — Integration Test Point 2
**Prerequisites:** Task 25
**Priority:** Core
**Description:**
This is **Integration Test Point 2** from `clarke_PRD_implementation.md` §8.
**Full demo dry-run:** Perform the Mrs Thompson scenario exactly as it would appear in the competition video:
1. Open Clarke in browser
2. Select Mrs Thompson from patient list
3. Verify context panel populates with correct data
4. Click "Start Consultation", upload pre-recorded audio
5. Click "End Consultation"
6. Verify draft letter appears within 60 seconds (or <5s mock mode)
7. Verify letter contains FHIR-sourced lab values
8. Edit one line, click "Sign Off"
9. Verify status transitions to green
Also: Run `pytest tests/ -v` — all tests still pass (no regressions).
**📌 DAY 2 DECISION POINT (from masterplan §12):** At this point, assess the must-have list:
1. ✅ Working MedASR transcription
2. ✅ Working EHR Agent context retrieval
3. ✅ Working document generation
4. ✅ End-to-end orchestration
5. ✅ Functional Gradio UI
6. ✅ 3 demo scenarios tested
**If ≥2 must-haves are incomplete:** Cancel ALL nice-to-haves (Tasks 27–32). Day 3 is entirely: fix remaining must-haves → deploy.
**Files created or modified:** None
**"Done" criteria:** Demo dry-run completes smoothly. `pytest tests/` passes. All must-haves are checked.
**Verification method:** Manual demo run + test suite.
**If this fails:** This is the last chance to fix critical issues. Prioritise by: pipeline > UI > polish.
---
## PHASE 4 — Fine-tuning, Evaluation & Polish (Hours 17–21)
**Phase goal:** LoRA fine-tuning (if feasible), quantitative evaluations, UI polish, demo preparation.
**Estimated time:** 5 hours
**Day-end checkpoint contribution:** Nice-to-haves from masterplan §12.
**Context required:** `clarke_PRD_technical_spec.md` (§6c fine-tuning params, §11), `clarke_PRD_design_guidelines.md` (full), `clarke_PRD_implementation.md` (§3 Phase 4).
**All tasks in this phase are Priority: Polish** — they improve the submission but are not required for a functional demo. If behind schedule, skip directly to Phase 5 (Task 34).
---
### Task 27: Synthetic Training Data Generation
**Prerequisites:** Task 26
**Priority:** Polish
**Description:**
Generate 250 training triplets (transcript, FHIR context JSON, reference NHS letter) for fine-tuning MedGemma 27B.
Implement `finetuning/generate_training_data.py`:
1. Use Claude API (or another LLM API) to generate diverse clinical scenarios.
2. Each triplet contains:
- `transcript`: A simulated clinician-patient consultation transcript (~200 words)
- `context`: A PatientContext JSON with realistic FHIR-sourced data
- `reference_letter`: A gold-standard NHS clinic letter
3. Clinical scenarios distributed across specialties (per `clarke_PRD_technical_spec.md` §8a).
4. Output format: JSONL with one triplet per line.
5. Split: 200 train → `data/training/train.jsonl`, 50 test → `data/training/test.jsonl`.
6. Manually review 20 samples for quality: clinically plausible, correctly formatted, no fabricated data conflicts.
**Files created or modified:** `finetuning/generate_training_data.py`, `data/training/train.jsonl`, `data/training/test.jsonl`
**"Done" criteria:** `train.jsonl` has 200 lines, `test.jsonl` has 50 lines. Each line is valid JSON with keys: transcript, context, reference_letter. 20 reviewed samples pass quality check.
**Verification method:** `wc -l data/training/train.jsonl` = 200. `python -c "import json; [json.loads(l) for l in open('data/training/train.jsonl')]"` succeeds.
**If this fails:** If API generation fails, reduce to 100 training samples. If quality is poor (>20% fail review), revise generation prompt and regenerate.
---
### Task 28: LoRA Fine-tuning MedGemma 27B
**Prerequisites:** Task 27
**Priority:** Polish
**Description:**
Implement and run QLoRA fine-tuning in `finetuning/train_lora.py`.
**Configuration (from `clarke_PRD_technical_spec.md` §3a and `clarke_PRD_implementation.md` §3 Hour 18):**
- Base model: `google/medgemma-27b-text-it` in 4-bit NF4
- LoRA config: `rank=16, alpha=32, dropout=0.05`, target modules: attention + MLP layers
- Training: `epochs=3, batch_size=2, gradient_accumulation_steps=8, learning_rate=2e-4`
- `max_seq_length=4096`
- Trainer: `trl.SFTTrainer`
- Tracking: wandb (optional)
Steps:
1. **Unload MedASR and MedGemma 4B** from GPU before training to free VRAM.
2. Load base model in 4-bit, apply LoRA configuration.
3. Load training data from `data/training/train.jsonl`.
4. Format each sample as a prompt-completion pair using the document_generation.j2 template.
5. Train. Monitor loss.
6. Save LoRA adapter to `finetuning/adapter/`.
7. **Reload MedASR and MedGemma 4B** after training.
**Files created or modified:** `finetuning/train_lora.py`, `finetuning/adapter/` (saved adapter files)
**"Done" criteria:** Training completes without OOM. Final training loss < initial loss. Adapter saved, <500MB.
**Verification method:** Check training logs for loss curve. `ls -lh finetuning/adapter/` shows adapter files.
**If this fails:** **⚠️ FALLBACK (from implementation.md §3):** If training fails after 2 attempts:
1. Reduce LoRA rank from 16 to 8.
2. Reduce max_seq_length from 4096 to 2048.
3. Reduce training set from 200 to 100.
4. If still fails after these reductions: **abandon fine-tuning entirely**. Use base MedGemma 27B with the optimised prompt from Task 16. Document fine-tuning as "production roadmap" in the writeup. Skip Task 35 (LoRA publication). Redirect remaining time to Tasks 29–32 (evaluation and polish).
---
### Task 29: MedASR Evaluation (WER)
**Prerequisites:** Task 26
**Priority:** Polish
**Description:**
Implement `evaluation/eval_medasr.py`:
1. Compute Word Error Rate (WER) for MedASR on the 3 demo audio clips using `jiwer`.
2. Ground-truth transcripts: `data/demo/*_transcript.txt`.
3. Optionally compare to Whisper large-v3 on the same clips.
4. Output: WER per clip + average WER. Save results to `evaluation_report.md`.
**Files created or modified:** `evaluation/eval_medasr.py`, `evaluation_report.md` (create/append)
**"Done" criteria:** WER computed for all 3 clips. Results appended to evaluation_report.md.
**Verification method:** `cat evaluation_report.md | grep "MedASR WER"` shows results.
**If this fails:** If jiwer fails, compute WER manually. If MedASR WER is >15% on demo clips, note this and consider switching to dictation-style audio (see `clarke_PRD_implementation.md` §7, Fallback Path #4).
---
### Task 30: EHR Agent Evaluation (Fact Recall)
**Prerequisites:** Task 26
**Priority:** Polish
**Description:**
Implement `evaluation/eval_ehr_agent.py`:
1. For each of 5 demo patients, compare EHR Agent output (`PatientContext`) against gold-standard context.
2. Create gold standards in `evaluation/gold_standards/` — manually verified correct context for each demo patient.
3. Metrics: Fact recall (what % of gold facts appear in output), Precision (what % of output facts are correct), Hallucination rate (what % of output facts are not in gold standard or FHIR data).
4. Target from masterplan §11: recall >85%, precision >90%, hallucination <10%.
5. Append results to `evaluation_report.md`.
**Files created or modified:** `evaluation/eval_ehr_agent.py`, `evaluation/gold_standards/pt-001.json` through `pt-005.json`, `evaluation_report.md` (append)
**"Done" criteria:** Metrics computed for 5 patients. Results in evaluation_report.md.
**Verification method:** `cat evaluation_report.md | grep "Fact Recall"` shows results.
**If this fails:** If metrics are below target, note the gaps and adjust EHR agent prompts if time permits.
---
### Task 31: Document Generation Evaluation (BLEU/ROUGE-L)
**Prerequisites:** Task 28 (if fine-tuned) or Task 26 (if using base model)
**Priority:** Polish
**Description:**
Implement `evaluation/eval_doc_gen.py`:
1. Generate letters for 50 test triplets from `data/training/test.jsonl`.
2. Compute BLEU (sacrebleu) and ROUGE-L (rouge_score) against reference letters.
3. If fine-tuned model is available, compare fine-tuned vs baseline (3 letters from Task 15).
4. Manual review of 10 test letters for NHS format compliance and clinical accuracy.
5. Append results to `evaluation_report.md`.
**Files created or modified:** `evaluation/eval_doc_gen.py`, `evaluation_report.md` (append)
**"Done" criteria:** BLEU and ROUGE-L computed. If fine-tuned: fine-tuned scores > baseline scores. Results in evaluation_report.md.
**Verification method:** `cat evaluation_report.md | grep "BLEU\|ROUGE"` shows results.
**If this fails:** If evaluation takes too long, reduce test set to 20 triplets. Focus on getting numbers that demonstrate improvement.
---
### Task 32: UI Visual Polish
**Prerequisites:** Task 26
**Priority:** Polish
**Description:**
Apply visual polish from `clarke_PRD_design_guidelines.md`:
1. **Hero gradient** (§1): Apply the warm-to-cool gradient behind the dashboard header.
2. **Card styling** (§3–§4): Rounded corners (12px), subtle shadow, hover elevation on patient cards.
3. **Recording indicator** (§4.5 from design_guidelines): Gold pulsing circle with ring animation.
4. **Loading states** (§4.8): Skeleton loaders with shimmer animation during context retrieval and processing.
5. **Document reveal** (§5): Subtle scale animation (0.97→1.0) when the letter first appears.
6. **Typography tightening**: Ensure Inter font loads, correct type scale is applied.
7. **Status badges**: Correct colours for each state (amber for review, green for signed off).
8. **Progress bar**: Three-segment bar with active segment glow.
Focus on the elements visible in the demo video — they carry the most judging weight.
**Files created or modified:** `frontend/assets/style.css` (major update), `frontend/ui.py` (add CSS classes), `frontend/components.py` (update)
**"Done" criteria:** UI looks professional and polished. Hero gradient visible on dashboard. Patient cards have hover effects. Recording shows gold pulse. Document appears with subtle animation. Status badges use correct colours.
**Verification method:** Visual inspection in browser at 1920×1080. All specified visual elements are present.
**If this fails:** Prioritise: (1) hero gradient, (2) card styling, (3) recording pulse, (4) status badges. Skip animations if they cause issues.
---
### Task 33: Phase 4 Checkpoint
**Prerequisites:** Task 26 + any completed Tasks 27–32
**Priority:** Core
**Description:**
Assess what was completed in Phase 4 and ensure core functionality still works:
1. `pytest tests/ -v` — all tests pass (no regressions from polish work).
2. Full demo dry-run of Mrs Thompson scenario — still works end-to-end.
3. Inventory completed nice-to-haves:
- [ ] LoRA fine-tuning completed?
- [ ] LoRA adapter saved?
- [ ] WER evaluation completed?
- [ ] EHR Agent evaluation completed?
- [ ] BLEU/ROUGE-L evaluation completed?
- [ ] UI visually polished?
- [ ] evaluation_report.md populated?
This inventory informs what to include in the writeup and video.
**Files created or modified:** None
**"Done" criteria:** Tests pass. Demo works. Inventory documented.
**Verification method:** Test suite + demo run + checklist.
**If this fails:** Fix any regressions before deployment.
---
## PHASE 5 — Deployment & Submission Prep (Hours 22–24)
**Phase goal:** Public HF Space live, public GitHub repo, all submission artefacts ready.
**Estimated time:** 3 hours
**Day-end checkpoint contribution:** Achieves Day 3 checkpoint — competition-ready (minus video/writeup, scheduled for buffer week).
**Context required:** `clarke_PRD_technical_spec.md` (§3b), `clarke_PRD_implementation.md` (§3 Phase 5, §9).
---
### Task 34: HF Space Deployment
**Prerequisites:** Task 33
**Priority:** Core
**Description:**
Deploy Clarke to a public Hugging Face Space:
1. Ensure `Dockerfile` is correct and complete (from Task 2).
2. Ensure `requirements.txt` includes all dependencies.
3. Create HF Space with hardware: `a100-large` (A100 40GB GPU).
4. Set `README.md` YAML frontmatter for HF Spaces metadata:
```yaml
---
title: Clarke
emoji: 🩺
colorFrom: blue
colorTo: gold
sdk: docker
app_port: 7860
hardware: a100-large
---
```
5. Set environment variables as HF Space secrets: `HF_TOKEN`, `USE_MOCK_FHIR=true`.
6. Push code to HF Space repo.
7. Wait for build + startup.
8. Test: access the public URL from an incognito browser, run one demo scenario end-to-end.
**Deployment decision:** If A100 quota is unavailable or too expensive during development, deploy with `USE_MOCK_FHIR=true` and model mocks, then upgrade to GPU hardware for the final submission. The mock demo still demonstrates the full UI flow.
**Files created or modified:** `README.md` (update frontmatter), HF Space configuration
**"Done" criteria:** Public HF Space URL is accessible from incognito browser. Demo scenario (select patient → context loads → upload audio → letter generates → sign off) completes without errors.
**Verification method:** Open HF Space URL in incognito browser on a different device. Run Mrs Thompson scenario.
**If this fails:** Check HF Space build logs for errors. Most common issues: Docker build fails (missing system packages), model download fails (HF_TOKEN not set), CUDA not available (wrong hardware tier). If GPU deployment fails entirely: deploy with mock models as a UI demo, note in writeup that full GPU demo is available locally.
---
### Task 35: HF Hub LoRA Adapter Publication
**Prerequisites:** Tasks 28, 34
**Priority:** Polish
**Description:**
If LoRA fine-tuning was completed (Task 28), publish the adapter on HF Hub:
1. Create a new HF Hub model repository: `{username}/clarke-medgemma-27b-nhs-letter-lora`
2. Upload the LoRA adapter files from `finetuning/adapter/`.
3. Create a model card (README.md) in the repo:
- Description: "LoRA adapter for NHS clinic letter generation, fine-tuned on MedGemma 27B"
- Base model: `google/medgemma-27b-text-it`
- Training details: hyperparameters, dataset size, training loss
- Usage example: loading the adapter with `peft`
- Licence: follow HAI-DEF terms
4. Verify: the model repo page shows correct metadata and files.
**Files created or modified:** HF Hub model repository files
**"Done" criteria:** Public HF Hub model repo exists, contains adapter files, has model card tracing to `google/medgemma-27b-text-it`.
**Verification method:** Visit the HF Hub model page in a browser. Verify adapter files are listed and model card is readable.
**If this fails:** If upload fails, try manual upload via the HF Hub web interface. If fine-tuning was not completed, skip this task entirely.
---
### Task 36: GitHub Repo & README
**Prerequisites:** Task 34
**Priority:** Core
**Description:**
Prepare the public GitHub repository:
1. **Code cleanup:** Ensure all `.py` files have module-level docstrings. Remove any debug print statements. Verify all imports are used.
2. **`README.md`** — Write a comprehensive README:
- Project title and one-line description
- Architecture diagram (ASCII art or embedded image): show the three-model pipeline with arrows
- Features list
- Quick start: installation, environment setup, local run
- Evaluation results (from `evaluation_report.md`, if completed)
- Model information: list all 3 HAI-DEF models with HF links
- Links: HF Space demo, HF LoRA adapter (if published)
- Licence: Apache 2.0 for code, HAI-DEF terms for models
- Acknowledgements: MedGemma Impact Challenge, Synthea, HAPI FHIR
3. **Repository setup:**
- `.gitignore` — Python standard + `__pycache__`, `.env`, `logs/`, model weights, `*.wav` (keep demo wavs via LFS or small files)
- Push to public GitHub repository
- Verify: README renders correctly on GitHub
**Files created or modified:** `README.md` (comprehensive update), `.gitignore`, all `.py` files (docstrings), GitHub repo
**"Done" criteria:** Public GitHub repo has clean code, comprehensive README with architecture diagram, all `.py` files have docstrings, licence file present.
**Verification method:** Visit GitHub repo URL. README renders correctly. `grep -rL '"""' backend/ frontend/ --include="*.py"` returns no files (all have docstrings).
**If this fails:** Focus on README quality first — judges will read it. Docstrings can be minimal if time is short.
---
### Task 37: Final Smoke Test & Submission Checklist
**Prerequisites:** Task 36
**Priority:** Core
**Description:**
Run the complete final verification:
1. **HF Space test:** Open live HF Space from incognito browser on a different device. Run all 3 demo scenarios. Verify each produces a clinically appropriate letter.
2. **GitHub repo test:** Clone the public repo into a fresh environment. Verify `README.md` has all required sections. Verify all Python files have docstrings.
3. **Links check:** All links in README are valid (HF Space, GitHub, HF model repo if applicable).
4. **Create `submission_checklist.md`:**
```markdown
# Clarke — Submission Checklist
## Ready Now (End of 24-Hour Build)
- [ ] Public HF Space: [URL] — accessible, runs 3 demo scenarios
- [ ] Public GitHub repo: [URL] — clean code, README, licence
- [ ] Public LoRA adapter: [URL] (if trained) — traces to google/medgemma-27b-text-it
- [ ] evaluation_report.md — metrics computed (if completed)
## Buffer Week (Mon 16 – Sun 22 Feb)
- [ ] 3-page writeup (Mon 16 Feb)
- [ ] 3-minute video (Tue 17 – Sat 21 Feb)
- [ ] Final Kaggle submission (Sun 22 Feb)
- [ ] Writeup submitted via Kaggle Writeups tab
- [ ] Agentic Workflow Prize selected
- [ ] All links included: video, GitHub, HF Space, HF model
```
**Files created or modified:** `submission_checklist.md`
**"Done" criteria:** All "Ready Now" items are checked. HF Space demo works from external device. GitHub repo is public with complete README.
**Verification method:** Walk through each checklist item. Test each link from incognito browser.
**If this fails:** Fix the specific failing item. Prioritise: HF Space working > GitHub repo > LoRA adapter.
---
### Task 38: Phase 5 Checkpoint — Final
**Prerequisites:** Task 37
**Priority:** Core
**Description:**
Final checkpoint. Verify all Day 3 end-of-build criteria from `clarke_PRD_implementation.md` §5:
1. ✅ Public HF Space is live and accessible from any browser.
2. ✅ Public GitHub repo with clean code, README with architecture diagram, and docstrings.
3. ✅ At least 3 demo scenarios work flawlessly on the live HF Space.
4. ✅ Submission checklist confirms all competition requirements are met (except video and writeup).
**Nice-to-haves completed (record for writeup/video planning):**
- LoRA adapter trained and published? Y/N
- WER comparison table? Y/N
- EHR Agent metrics? Y/N
- BLEU/ROUGE-L evaluation? Y/N
- evaluation_report.md populated? Y/N
- UI visually polished? Y/N
**Files created or modified:** None
**"Done" criteria:** All 4 Day 3 criteria are met. Inventory of completed nice-to-haves is documented.
**Verification method:** Go through each criterion. If all pass: the 24-hour build is complete. Proceed to buffer week for writeup and video.
**If this fails:** The buffer week (Mon 16 – Sun 22 Feb) absorbs remaining work. Prioritise by competition impact: working demo > evaluation metrics > fine-tuning > polish.
---
## Appendix A: Fallback Decision Points Summary
| Task | Risk | Trigger | Fallback | Impact |
|------|------|---------|----------|--------|
| T11 | MedGemma 4B instruction-following | Fails after 2h of prompt engineering | Deterministic FHIR + summarisation only | Narrative slightly weaker. No downstream changes. |
| T15 | MedGemma 27B won't load | OOM on A100 at 4-bit | Try Ollama GGUF → then 4B for generation | T16–T17 adapt. Quality drops. Pipeline intact. |
| T28 | LoRA training fails | OOM, loss diverges, >2h | Skip fine-tuning. Use base model + prompt engineering. | Skip T35. Redirect time to T29–T32. |
| T29 | MedASR WER >15% | Demo clips produce poor transcripts | Switch to dictation-style audio | Swap audio files. Rest unchanged. |
| T34 | HF Space deployment fails | Build errors, GPU unavailable | Deploy with mock models. Demo UI flow only. | Note GPU demo in writeup as local-only. |
## Appendix B: PRD Cross-Reference per Phase
| Phase | Required PRD Files in Context |
|-------|------------------------------|
| 0 | `clarke_PRD_technical_spec.md` (§1–§3, §7–§8) |
| 1 | `clarke_PRD_technical_spec.md` (§6a–§6b, §7, §9), `clarke_PRD_implementation.md` (Phase 1) |
| 2 | `clarke_PRD_technical_spec.md` (§6c, §10), `clarke_PRD_implementation.md` (Phase 2) |
| 3 | `clarke_PRD_technical_spec.md` (§9), `clarke_PRD_design_guidelines.md` (§1–§5), `clarke_PRD_userflow.md` |
| 4 | `clarke_PRD_technical_spec.md` (§6c fine-tuning, §11), `clarke_PRD_design_guidelines.md`, `clarke_PRD_implementation.md` (Phase 4) |
| 5 | `clarke_PRD_technical_spec.md` (§3b), `clarke_PRD_implementation.md` (§3 Phase 5, §9) |
---
*This document is the construction schedule that turns the Clarke blueprint into a working product. Every task traces to a specific section of clarke_PRD_technical_spec.md (architecture), clarke_PRD_implementation.md (build sequence), clarke_PRD_userflow.md (screens), or clarke_PRD_design_guidelines.md (visual specification). Codex executes one task at a time, verifies, and moves on. The user confirms progress at each phase checkpoint.*