Skip to content

Guardrails Flow Map — Medication Intelligence

Date: 2026-06-04 · From: Gene (Pharmacy Ops) · For: Faraz + the room What this is: one map of how a messy med list becomes a safe, structured object — and exactly where each guardrail sits, what it sees (input), and what it does (output). Companion to the styled page Guardrails_Flow_Map_2026-06-04.html (self-contained, presentable) and the running demo.

The brain is probabilistic; the boundary is deterministic + pharmacist-gated. Every red node below is a guardrail that stops or diverts the flow. Nothing reaches a member until it clears the final fail-closed rail. Clinical-line leakage target = 0.


The flow (Mermaid)

flowchart TD
    IN([" INPUT<br/>scan printed Rx · type · import"]):::io
    RES["RESOLVE IDENTITY<br/>RxNorm + RxClass<br/>name/NDC to RXCUI + drug class"]:::proc
    IN --> RES
    RES --> Q{"How well did it resolve?"}:::gate

    Q -->|"exact / brand to generic"| SM["SMART-MATCH<br/>modal priors fill<br/>strength · form · frequency"]:::proc
    Q -->|"real drug, not in local table"| LASA["GUARD · LASA<br/>never substitute a look-alike<br/>felodipine NOT amlodipine"]:::guard
    Q -->|"close typo only ( >= 0.86 )"| TYPO["GUARD · typo<br/>did you mean…? suggest only,<br/>never auto-accept"]:::guard
    Q -->|"no confident match"| INV["GUARD · never invent<br/>no guessed strength/dose"]:::guard

    SM --> GATE{"CONFIDENCE x RISK GATE"}:::gate
    GATE -->|"high conf + not high-risk"| AUTO["AUTO-DEFAULT<br/>1-tap accept"]:::ok
    GATE -->|"high-risk: insulin · anticoag ·<br/>opioid · NTI · LASA"| CONF["FORCE-CONFIRM<br/>explicit human OK"]:::warn
    GATE -->|"low confidence"| MAN["MANUAL ENTRY"]:::warn

    LASA --> MAN
    INV --> MAN
    TYPO --> CONF

    AUTO --> OBJ[("STRUCTURED MEDICATION OBJECT<br/>FHIR + provenance + confidence + flags")]:::obj
    CONF --> OBJ
    MAN --> OBJ

    OBJ --> FLAGS["LIST-LEVEL FLAGS · Knowledge Graph<br/>duplicate-therapy · interaction · fall-risk<br/>PHARMACIST VIEW ONLY — never a member alert"]:::pharm
    FLAGS --> ENG["DOWNSTREAM ENGINES<br/>reminders · Balance Meter fall-risk · refill"]:::proc

    ENG --> RAIL{{"DETERMINISTIC CLINICAL-LINE RAIL · blast door<br/>fail-closed · default = do not emit<br/>dosing? diagnosis? disease claim?<br/>schema violation? timeout?"}}:::rail
    RAIL -->|"clean: reminder / confirmation / insight"| EMIT([" EMIT to member"]):::ok
    RAIL -->|"any clinical-line content"| BLOCK([" BLOCK to pharmacist queue"]):::block

    classDef io fill:#741E4F,stroke:#741E4F,color:#ffffff
    classDef proc fill:#ffffff,stroke:#8F3968,color:#241C1A
    classDef gate fill:#F3E8EF,stroke:#741E4F,color:#741E4F
    classDef guard fill:#FBE9E9,stroke:#B23A48,color:#7A1F2B
    classDef ok fill:#E6F2EA,stroke:#3F7A52,color:#1E4D30
    classDef warn fill:#FBF0DC,stroke:#B67A2A,color:#7A4E12
    classDef obj fill:#F7F0E7,stroke:#741E4F,color:#241C1A
    classDef pharm fill:#EDE7F3,stroke:#5B3A8F,color:#3A2363
    classDef rail fill:#741E4F,stroke:#241C1A,color:#ffffff
    classDef block fill:#F6D9DC,stroke:#B23A48,color:#7A1F2B

Color key: burgundy = input / member output · white = process · pink diamond = decision gate · red = guardrail (block or divert) · green = auto / emit (clears) · amber = force-confirm / manual · purple = pharmacist view only · burgundy hex = the deterministic rail (blast door).


Every guardrail — where it sits, what it sees, what it does

Guardrail Gate it lives at What it sees (input) What it does (output)
Never invent Resolve / match a name it can't confidently resolve to a real drug MANUAL; never guesses a strength or dose
Never substitute a look-alike (LASA) Resolve a real drug (RxNorm-known) that is not in the local table MANUAL; never swaps in a similar-spelling drug — felodipine ≠ amlodipine
Typo = suggestion, not auto-accept Resolve a close fuzzy match only (≥ 0.86, e.g. metformn) FORCE-CONFIRM "did you mean…?"; never silently accepted
Confidence × risk gate Gate match confidence + the drug's risk class AUTO (high+safe) · FORCE-CONFIRM (high-risk) · MANUAL (low conf)
High-risk → force confirm Gate insulin · anticoagulant · opioid · controlled · NTI · LASA pair FORCE-CONFIRM; always needs an explicit human OK, regardless of confidence
Confirm, never prescribe Confirm the pre-filled medication object EDITABLE data-entry; editable SIG — never "take X"
Flags → pharmacist view only Object → list flags the whole list, cross-checked via the knowledge graph PHARMACIST: duplicate-therapy / interaction / fall-risk — never a member alert
Deterministic clinical-line rail (blast door) Output (final) the final rendered member string, after all model rails BLOCK → pharmacist on any dosing / diagnosis / disease claim / schema violation / timeout; else EMIT. Fail-closed; default = do not emit

Why two kinds of guardrail

  • Probabilistic "speed bumps" (the brain). Confidence scoring, fuzzy matching, modal priors, the model's own rails (Llama Guard / validators). They shape and slow the flow — route to auto vs. confirm vs. manual. They can be wrong, so they never get the last word.
  • The deterministic "blast door" (the boundary). A non-ML, fail-closed rail with an allow-listed output schema (reminder · confirmation · insight). Default state = do not emit. Anything clinical-line → block → pharmacist queue. This is the FDA wellness-vs-SaMD boundary, enforced in code outside the model's reach.

Companions: Guardrails_Flow_Map_2026-06-04.html (styled, self-contained) · Medication_Matching_Guardrails_for_Faraz_2026-06-02 (the written guardrail list) · AI_Foundation_Sprint_A-B_Specs (the rail contract) · the running demo (rx360_med_intel_demo, the live tester).