Skip to content

Latest commit

 

History

History
156 lines (122 loc) · 8.29 KB

File metadata and controls

156 lines (122 loc) · 8.29 KB

Phase 27 — Multilingual clinical explanation (Spanish)

Generated by scripts/i18n_eval.py. Raw results: eval.json.

APEX now generates its clinical explanation in Spanish as well as English:

analyze_signal(signal, 100, backend="template", lang="es")

The interesting part is not the translation. It is that adding a second language nearly removed the safety guarantee for everyone who reads it, in a way that no amount of reviewing the Spanish text would have revealed.


1. The hole

Phase 7 built a consistency gate: APEX may only assert findings the detector actually surfaced, and any report claiming more is flagged before a clinician sees it. It is the mechanism that makes the generated text trustworthy, and Phase 21 showed it catching real fabrications when retrieval went wrong.

It works by matching English impression phrases.

Point it at a Spanish report and it matches nothing. The report parses as asserting no findings at all, which is a subset of anything, so it passes — unconditionally, silently, every time. Measured on 400 PTB-XL records before this phase:

English report Spanish report
Fabricated finding detected 100% 0%
Any finding recognised at all 100% 0%

A Spanish report inventing bloqueo completo de rama izquierda on a patient whose only detected finding was atrial fibrillation was reported consistent. The identical fabrication in English was caught.

This is what a health-equity failure looks like in a codebase: not a slur, not a missing translation, but a guardrail that quietly does not extend to the second-largest language group in US healthcare. Nobody reading the Spanish output would notice — the text is fluent, the disclaimer is present, the JSON validates. Only the gate is missing, and only for those patients.

2. What was built

Spanish vocabulary (src/i18n/vocab_es.py) — all 71 SCP statements, hand-authored, with the finding sentence and the impression term separated exactly as in English. Not machine-translated: clinical Spanish is not English with Spanish words. Bundle branch block is bloqueo de rama, not bloqueo del haz; a fascicular block is conventionally hemibloqueo; atrial enlargement is crecimiento auricular, not the literal agrandamiento.

One renderer, two languages (src/i18n/render.py) — structure, ordering, and the merge logic for localized findings are shared; only a phrase bank changes. The alternative, a second renderer for Spanish, starts identical and drifts. A test asserts English output is byte-identical to the Phase-6 templater across 200 random cases, so divergence is a build failure rather than a discovery months later.

The phrase bank carries grammar, not just words:

English Spanish
Lead clause "in the inferior leads" "en las derivaciones inferiores" (feminine plural agreement)
Serial list "V1, V2, and V3" "V1, V2 y V3" (no serial comma)
Rate "72 bpm" "72 lpm"
Headers Findings / Impression Hallazgos / Impresión

A language-aware gate (src/i18n/parse.py) — the fix. Two properties the English matcher did not need:

  • Accent tolerance on input. The vocabulary spells fibrilación correctly; the matcher folds accents when reading, so a model or clinician typing fibrilacion is still understood. A gate a missing accent can switch off is not a gate.
  • Longest match wins. extrasístoles is a substring of extrasístoles auriculares, exactly as "premature complexes" sits inside "atrial premature complexes". Without this, a correct report is charged with a hallucination that never happened, and a gate that cries wolf gets switched off.

3. Parity, measured

400 PTB-XL records, rendered in both languages, gate audited on each.

Measure English Spanish
Well-formed sections 100% 100%
Language correctly detected 100% 100%
Findings round-trip exactly 100% 100%
Fabricated finding caught 100% 100%
(before this phase) 100% 0%

Round-trip is measured excluding normal studies. 157 of the 400 records are normal ECGs whose impression deliberately collapses to "Normal ECG" (the Phase-6 NORM_COMPATIBLE rule), which suppresses the rhythm term — in both languages, by design. Counting those as failures would report 64.8% for both languages and blame the translation for a rule it never touched.

Two further parity invariants, both enforced by tests rather than asserted in prose:

  • English rendering is byte-identical to the Phase-6 templater (200/200 random cases).
  • The language-aware parser agrees with the Phase-6 parser on English text (300/300).

A bug the parity check caught in the new code

The first version of the Spanish matcher searched the whole report rather than the Impression section. Several morphological sentences are word-for-word identical to another code's impression term — ISCAN's finding is "T-wave inversion", which is exactly INVT's impression; INJAS's is "ST-segment depression", exactly STD_'s — so every ischemia report was charged with additionally asserting INVT and STD_. Round-trip accuracy sat at 84%, and the Spanish gate would have been noisier than the English one: the same second-class treatment, arriving through the opposite door. Restricting to the Impression section, as the English implementation already did, took both languages to 100%.

4. Terminology, checked against Spanish clinical prose

Each Spanish term was checked against 26 Spanish-language cardiology articles (264,270 characters, es.wikipedia, CC BY-SA 4.0, quoted for validation only — same licensing footing as Phase 21's corpus).

34 of 67 terms appear in the reference prose. Confirmation is evidence a term is conventional Spanish usage. Non-confirmation is not evidence of error, and the report says so rather than quietly counting it as a pass: the corpus is 26 encyclopedia articles, and roughly half the unconfirmed set are ECG report-writing conventions that encyclopedic prose has no reason to contain — "alteración no diagnóstica de la onda T", "criterios de voltaje para hipertrofia ventricular izquierda", "lesión subendocárdica anteroseptal". The rest are absent because the corpus lacks the relevant article.

The unconfirmed list is a clinician review list, and it is the honest deliverable here. A native-speaking cardiologist reviewing 33 terms is a bounded, actionable task; "we validated the Spanish" would have been a stronger-sounding and less useful claim.

Getting even this far required fixing the matcher twice. Report vocabulary is plural ("extrasístoles auriculares") while reference prose defines the singular ("extrasístole auricular"), and Spanish pluralizes with +s after a vowel and +es after a consonant — mixed within a single phrase. Stripping one fixed suffix produced "extrasistol auriculare" and matched nothing, reporting a perfectly standard term as unconfirmed. Both attempts are recorded in glossary.py because the failure mode — a review list inflated by matching bugs, hiding the real problems — is the one that matters.

5. Limitations

  • Two languages. English and Spanish. The architecture is a phrase bank plus a vocabulary, so a third is additive, but no claim is made about languages not implemented.
  • The template backend is the validated path. The LLM backends accept lang and receive a Spanish instruction appended to the (untranslated) constraint block, but their Spanish output has not been measured — Phase 21 showed the generator's faithfulness is fragile, and there is no reason to assume it degrades identically in a second language. The deterministic renderer is consistency-clean by construction; the LLM path is not, in either language.
  • No native-speaker review yet. Terminology is checked mechanically against reference prose. That is a floor, not a substitute for a Spanish-speaking cardiologist reading the output.
  • No dialect variation. Cardiology Spanish is fairly standardized, but usage does differ between Spain and Latin America and this vocabulary does not model that.
  • Patient-facing language is out of scope. This is clinician-register Spanish, matching the English. A patient-readable explanation is a different task with different risks.