RS
RISHI SINGH
Back to All Notes
Mar 12, 2026·6 min read·Engineered for VitalTrace ↗

Deterministic Validation in Clinical AI: Why LLMs Need Biological Plausibility Gates & LOINC Standardization

Why relying solely on LLM JSON output for health records invites catastrophic silent errors, and how we engineered a deterministic clinical validator using physiological plausibility limits, canonical LOINC mapping, and PostgreSQL security-invoker views.

Data QualityHealthcare AITypeScriptZodVitalTrace

The Fallacy of Pure LLM Extraction

When ingesting laboratory reports—whether multi-page CBC panels, metabolic profiles, or lipid panels—modern multimodal LLMs excel at optical character parsing and associating unstructured key-value pairs. However, deploying an LLM directly to persist patient observations introduces critical failure modes:

1. **Hallucinated Clinical Codes**: Models frequently hallucinate plausible-looking 5-digit LOINC codes (e.g., assigning `1558-6` for fasting glucose when the report specified random plasma glucose, or generating nonexistent syntax). 2. **Unit Incongruity**: Reporting a blood glucose value of `105` without capturing whether the laboratory evaluated `mg/dL` or `mmol/L` turns an ordinary reading into either normal fasting blood sugar or severe, life-threatening hyperosmolar coma. 3. **Silent Omissions & Boundary Violations**: LLMs will happily parse a typing artifact such as `Hemoglobin: 140 g/dL` instead of `14.0 g/dL`, generating physiologically impossible observations that corrupt longitudinal analytics.

In **VitalTrace**, we adopted a non-negotiable architectural rule:

**The LLM is an untrusted extractor; deterministic code is the authoritative judge.**
[ Raw Report PDF ] ──► [ Gemini 1.5 Edge Func ] ──► [ Strict Zod Parser ]
                                                          │
       ┌──────────────────────────────────────────────────┘
       ▼
[ Deterministic Clinical Validator ]
  ├── 1. Biological Plausibility Limits Check (e.g., 0.5 < Hb < 25.0 g/dL)
  ├── 2. Canonical LOINC & Synonym Normalization (aliasDictionary.ts)
  ├── 3. Duplicate Specimen Collision Detection
  └── 4. Unit Harmonization & Missing Unit Audit
       │
       ▼
[ PostgreSQL: pending Review State ] ──► [ Clinician / Patient Workbench ]

Step 1: Strict Runtime Typing with Zod

The edge function output must first satisfy a strict Zod schema before entering the validation engine. If the LLM generates extra fields or unexpected data types, the run halts immediately rather than poisoning downstream stores:

typescript
export const ExtractedObservationSchema = z.object({
  raw_test_name: z.string().min(1),
  value_numeric: z.number().nullable(),
  value_text: z.string().nullable(),
  unit: z.string().nullable(),
  reference_range_low: z.number().nullable(),
  reference_range_high: z.number().nullable(),
  flag: z.enum(["normal", "low", "high", "critical_low", "critical_high", "abnormal"]).nullable(),
  loinc_code: z.string().nullable(),
});

Step 2: Biological Plausibility Bounds

Even if a lab report OCR reads `Potassium: 42.0 mmol/L` due to a smudge on the printed paper, human serum potassium cannot exceed approximately `10.0 mmol/L` in a living patient. We defined strict physiological bounds (`PLAUSIBILITY_BOUNDS`):

typescript
export const PLAUSIBILITY_BOUNDS: Record<string, { min: number; max: number; expectedUnit: string }> = {
  // Potassium: 1.0 to 10.0 mmol/L
  "2823-3": { min: 1.0, max: 10.0, expectedUnit: "mmol/L" },
  // Hemoglobin: 2.0 to 26.0 g/dL
  "718-7": { min: 2.0, max: 26.0, expectedUnit: "g/dL" },
  // Fasting Blood Glucose: 20 to 1200 mg/dL
  "1558-6": { min: 20.0, max: 1200.0, expectedUnit: "mg/dL" },
  // Platelets: 5 to 2000 x10^3/uL
  "777-3": { min: 5.0, max: 2000.0, expectedUnit: "x10^3/uL" },
};

If an observation breaches these bounds, it is automatically flagged with severity `CRITICAL_PLAUSIBILITY_BREACH` and requires explicit human verification in the review workbench.


Step 3: Zero-Tolerance LOINC Mapping

Standardizing synonyms (e.g., `"FBS"`, `"Fasting Blood Sugar"`, `"Glucose, Fasting Plasma"`) to canonical LOINC code `1558-6` is vital for longitudinal charting. However, when an unfamiliar or bespoke proprietary test is encountered, our dictionary mandates **null fallback**:

typescript
export function resolveLoincCode(rawName: string): { code: string | null; canonicalName: string } {
  const normalized = normalizeAliasKey(rawName);
  const match = CLINICAL_ALIAS_DICTIONARY[normalized];
  if (match) {
    return { code: match.loinc, canonicalName: match.canonicalName };
  }
  // Zero-hallucination guarantee: Preserve raw name, never guess a code
  return { code: null, canonicalName: rawName.trim() };
}

Step 4: Multi-Tenant PostgreSQL Security Invoker Views

Analytical queries calculating patient trajectories must never leak between accounts. In PostgreSQL 15+, analytical views can specify `WITH (security_invoker = true)`. This ensures that views execute under the privileges of the querying user rather than the view creator:

sql
CREATE OR REPLACE VIEW view_patient_biomarker_trajectories
WITH (security_invoker = true) AS
SELECT 
  obs.profile_id,
  obs.loinc_code,
  obs.canonical_name,
  obs.observation_date,
  obs.value_numeric,
  obs.unit
FROM observations obs
WHERE obs.status = 'confirmed';

Because `security_invoker` is active, PostgreSQL enforces the base table's Row-Level Security policy (`auth.uid() = profile_id`), guaranteeing zero cross-tenant data leakage.

Key Takeaway

In production engineering, especially across health and data infrastructure, machine learning models should serve as intelligent transducers, never as autonomous final arbiters. Deterministic layers provide the defensible audit trail required for institutional trust.