Clinical Note Consistency: Summary Claims vs. the Chart
Objective
Discharge summaries and referral letters are written from — but not mechanically checked against — the chart. A summary that states a procedure that wasn't performed, or omits a documented allergy, is a documentation error with clinical consequences. This recipe matches each summary claim to the chart section it concerns and flags the ones the chart contradicts, as a review assist for a clinician — and is deliberately loud about where NLI must not be the decision-maker.
!!! danger "Read this before anything else" This is a documentation-consistency assist, not a clinical safety device. It compares wording. It does not understand medicine, does not compare dosages or dates with typed precision, and must never gate a clinical decision on its own. Every flag is for a qualified human to adjudicate. Numeric and temporal facts (doses, timings, counts) are exactly where the model class is weakest — handle those with exact comparisons, not NLI.
Step 1: The chart, as atomic facts
CREATE TABLE IF NOT EXISTS recipe_clinical_chart (
id INT PRIMARY KEY,
section TEXT,
fact TEXT
);
INSERT INTO recipe_clinical_chart (id, section, fact) VALUES
(1, 'allergy-list', 'The patient chart documents an allergy to penicillin, which caused a rash.'),
(2, 'operative-note', 'The operative note records that the appendix was surgically removed.'),
(3, 'discharge-plan', 'The patient was discharged home with outpatient follow-up in two weeks.');
Step 2: Summary claims, each matched to its chart section
Match the claim to the relevant chart section first — with your record
system's structure, not NLI. The chart_id below is that match.
CREATE TABLE IF NOT EXISTS recipe_clinical_summary (
id INT PRIMARY KEY,
claim TEXT,
chart_id INT
);
INSERT INTO recipe_clinical_summary (id, claim, chart_id) VALUES
(1, 'An appendectomy was performed.', 2),
(2, 'A cholecystectomy was performed.', 2),
(3, 'The patient has no known drug allergies.', 1);
!!! note "Why match, then verify — don't dump the whole chart"
NLI_VERIFY reports a LIE if any anchor contradicts the statement
(contradiction takes precedence). Hand it the entire chart as anchors and
an unrelated line can spuriously contradict a true claim, turning
everything into LIE. Verify each claim against the section it is about.
When you don't have an explicit mapping, retrieve the relevant section by
vector similarity first — the discipline in the RAG Answer Gate
recipe.
Step 3: A procedure claim the matched note supports
SELECT JSON_UNQUOTE(JSON_EXTRACT(NLI_VERIFY('nli-default', s.claim,
JSON_ARRAY(c.fact)), '$.verdict')) AS verdict
FROM recipe_clinical_summary s
JOIN recipe_clinical_chart c ON s.chart_id = c.id
WHERE s.id = 1;
Expected: TRUTH — "appendectomy" is entailed by "the appendix was surgically
removed."
Step 4: A procedure claim the matched note contradicts
SELECT NLI_VERIFY('nli-default', s.claim, JSON_ARRAY(c.fact)) AS review
FROM recipe_clinical_summary s
JOIN recipe_clinical_chart c ON s.chart_id = c.id
WHERE s.id = 2;
Expected: verdict = LIE, violated_anchor = the operative note — the
summary names a gallbladder removal the note does not record.
Step 5: A safety-critical claim the matched section contradicts
SELECT JSON_UNQUOTE(JSON_EXTRACT(NLI_VERIFY('nli-default', s.claim,
JSON_ARRAY(c.fact)), '$.verdict')) AS verdict
FROM recipe_clinical_summary s
JOIN recipe_clinical_chart c ON s.chart_id = c.id
WHERE s.id = 3;
Expected: LIE — "no known drug allergies" is contradicted by the documented
penicillin allergy. A summary that drops a recorded allergy is exactly the
error worth catching.
Step 6: The honesty step — terse notation under-entails
Charts are terse. A shorthand allergy line may not lexically entail a fully-spelled claim, even when both mean the same thing:
SELECT JSON_UNQUOTE(JSON_EXTRACT(NLI_VERIFY('nli-default',
'The patient has a documented penicillin allergy.',
JSON_ARRAY('allergy: penicillin (rash)')), '$.verdict')) AS terse,
JSON_UNQUOTE(JSON_EXTRACT(NLI_VERIFY('nli-default',
'The patient has a documented penicillin allergy.',
JSON_ARRAY('The patient chart documents an allergy to penicillin, which caused a rash.')), '$.verdict')) AS full;
Expected: terse = UNVERIFIED_PLAUSIBLE, full = TRUTH. The same true fact
verifies or not depending on how the anchor is written. Normalize chart text
into full sentences before verifying, and treat UNVERIFIED_PLAUSIBLE on a
safety-critical claim as "route to a human", never "probably fine."
Step 7: The review queue — every claim, verdict first
SELECT s.id, s.claim, c.section,
JSON_UNQUOTE(JSON_EXTRACT(NLI_VERIFY('nli-default', s.claim,
JSON_ARRAY(c.fact)), '$.verdict')) AS verdict
FROM recipe_clinical_summary s
JOIN recipe_clinical_chart c ON s.chart_id = c.id
ORDER BY s.id;
Expected: claim 1 TRUTH, claims 2 and 3 LIE. The clinician reviews the two
flags; they are not auto-corrected.
Cleanup (Optional)
DROP TABLE IF EXISTS recipe_clinical_chart;
DROP TABLE IF EXISTS recipe_clinical_summary;
Use it from your app
- Run the Step 7 query at summary-finalization time; surface
LIEverdicts (and safety-criticalUNVERIFIED_PLAUSIBLE) on the clinician's sign-off screen, with the violated chart line attached. - Match claims to chart sections with your record structure (or vector retrieval); normalize chart shorthand into sentences first (Step 6).
- Why in-DB: chart and summary already live in the record system; the check is a query, and no PHI leaves the database for a third-party NLI service.
Key Concepts Learned
- Verify each claim against the section it is about — handing the whole chart as anchors lets an unrelated line spuriously contradict a true claim (contradiction precedence).
- Terse source text under-entails — normalize anchors to full sentences, or a
true claim reads as
UNVERIFIED_PLAUSIBLE. - Dropped-contradiction (a missing allergy) and added-contradiction (a wrong
procedure) both surface as
LIEagainst the matched section. - Dosages, timings, and counts are the model's weak spot; gate those with exact comparisons and leave NLI out of the numeric path entirely.