# Architecture ## Data contract (single source of truth) [`app/pipeline/types.py`](../app/pipeline/types.py) is the authority. Every component consumes and emits instances of these pydantic models. If you need to add a field, add it here first and the components will fail loudly until they handle it. Key shapes: - `Note` — free-text input + optional section list. - `Span` — typed offset ranges (Condition/Medication/Lab/...) with negation + temporality. - `ICD10Link` — (Condition span, ICD-10 code, linker confidence). - `HCCCandidate` — HCC id, RAF weight, hierarchy state, ICD-10 links, confidence (raw + calibrated), MEAT evidence, risk. - `MEATEvidence` — category (M/E/A/T), quoted text + offsets, NLI entailment, `verified` flag. - `RiskAssessment` — level (low/medium/high), score, transparent reason list, named component scores. - `CodingResult` — the whole thing, serializable. ## Component map | # | Component | Inputs | Outputs | Real or stub | |---|---|---|---|---| | A | Section Segmenter ([a_segmenter.py](../app/pipeline/components/a_segmenter.py)) | Note | Note with sections | Rule-based (real, narrow) | | B | Clinical NER ([b_ner.py](../app/pipeline/components/b_ner.py)) | Note | `list[Span]` | Dictionary baseline (stub) | | C | Negation + Temporality ([c_negation.py](../app/pipeline/components/c_negation.py)) | Note + spans | Spans with flags; `is_attributable()` filter | Rule-based (real) | | D | ICD-10 Linker ([d_linker.py](../app/pipeline/components/d_linker.py)) | Spans | `list[ICD10Link]` | Exact + alias match (stub) | | E | HCC Crosswalk ([e_crosswalk.py](../app/pipeline/components/e_crosswalk.py)) | Links | HCC candidates + trumping | **Real** (DuckDB + CSV) | | F | MEAT Extractor ([f_meat.py](../app/pipeline/components/f_meat.py)) | Note + candidate | `list[MEATEvidence]` | Rule-based (stub) | | G | Calibrator ([g_calibrator.py](../app/pipeline/components/g_calibrator.py)) | HCC + raw conf | Calibrated conf | Identity (stub) | | H | Over-coding Risk ([h_risk.py](../app/pipeline/components/h_risk.py)) | Candidate | `RiskAssessment` | **Real** (transparent heuristic) | | I | Verifier ([i_verifier.py](../app/pipeline/components/i_verifier.py)) | Note + candidate | Candidate with verified/dropped evidence | **Real** (substring) + NLI hook | ## Orchestration order ``` A segmenter → B NER → C negation/temporality → filter non-attributable spans → D linker (conditions only) → E crosswalk + trumping ↘ F MEAT extractor (per candidate) → I verifier (per candidate) ↙ G calibrator (per candidate) → H risk (per candidate) → rank: non-trumped first, then calibrated_conf × RAF_weight ``` Notes: - I (verifier) sits **between F and G** — a candidate with zero verified MEAT evidence is still kept (with an empty evidence list), because risk heuristic H needs to see that emptiness and flag the candidate accordingly. Dropping the candidate silently would undercount the suspect list a coder needs to see. - G (calibrator) runs late because it doesn't affect rank tie-breakers inside E, but it does affect the final ranking H reads. ## Why hierarchy trumping is handled inside component E Trumping requires the full candidate set; it's not a per-span decision. Running it inside the crosswalk (`HCCCrosswalk.apply_trumping`) keeps the orchestrator code short and the crosswalk tests self-contained. ## Why MEAT evidence belongs on HCCCandidate (not on Span) One MEAT evidence row justifies one HCC. The same sentence can justify Assess for HCC-18 and Monitor for HCC-85. Binding MEATEvidence to HCC rather than to span avoids a many-to-many association table. ## API shape Endpoints in `app/api/server.py`: - `POST /api/code` — `{text, note_id}` → `CodingResult`. Single source of truth for the frontend. - `GET /api/gallery` — returns precomputed `GalleryItem[]` for the preloaded demo cases. Computed once at app startup so clicking a gallery entry is instant. - `GET /api/healthz` — `{status: "ok", version}`. Used by the Docker healthcheck. - `GET /api/reference/hcc` — HCC label table for UI tooltips linking to CMS. ## Frontend `ui/src/App.tsx` is a controller holding `noteText`, `result`, `selectedHCC`, and the gallery. Three presentational components: - `NotePanel` — textarea + highlight preview (MEAT quotes underlined by category). - `HCCList` — ranked HCC suggestions; trumped ones dimmed. - `DrillIn` — selected HCC's MEAT-by-category, risk reasons, ICD-10 support. State flows strictly one-way. The only network call besides gallery is `codeNote()` from `ui/src/lib/api.ts`. ## Deployment target Single Docker image (`Dockerfile`) for an HF **Docker Space**: - Stage 1 (node:20-alpine): build the React UI. - Stage 2 (python:3.11-slim): install minimal Python deps, copy `app/`, `eval_harness/`, `data/reference/`, and the built UI at `ui/dist/`. - Uvicorn serves FastAPI on :7860 and the UI via `StaticFiles` mount. - HF Spaces auto-builds the Dockerfile; the Python CI runs on GitHub Actions without building the image.