Skip to content

Extracting Critical-Value Flags From a Lab Report

9 min read · updated August 11, 2026

A high potassium and a critically high potassium are printed one character apart and mean different things to the organisation holding the report. One is outside a reference interval. The other triggered a telephone call under a written policy, and that is a fact about what happened, not a fact about the number.

Abnormal and critical are different claims

An abnormal flag says the result fell outside the reference interval for that assay in that laboratory. Most abnormal results are of no particular urgency; a slightly low haemoglobin is abnormal every day of the week.

A critical value is a different category. Under the US laboratory regulations at 42 CFR 493.1291, a laboratory must have written procedures for immediate alerting when a test result of a life-threatening nature falls outside its established critical limits, and must document that the alert was made. So a critical flag on a report is evidence that a laboratory’s own critical-limit policy was met and that a notification procedure was invoked. The number alone does not carry that; the flag does.

The extraction consequence is that a single abnormal: true boolean is the wrong shape. It collapses two assertions of very different weight, and any downstream consumer trying to find the urgent results will either get every mildly abnormal result in the dataset or have to reconstruct the distinction from the raw values, which is the thing you must not do. Two fields, or one enumeration with distinct members. Never one boolean.

42 CFR 493.1291 is a US regulation under CLIA and applies to laboratories subject to it; other jurisdictions have their own equivalents and the accrediting body’s checklist usually adds requirements on top, such as read-back of the value by the recipient. The current text is on the eCFR. Treat this page as describing what the flag means in a document, not as advice on what your organisation must do about one.

The marks laboratories use

There is no single printed convention, which is precisely why this needs extracting rather than assuming. What you will meet:

  • A letter in a flag column. H and L for high and low; HH and LL, or sometimes H* and L*, for critically high and low.
  • The letters A and AA. Abnormal and critically abnormal, used where the result is not numeric and so has no direction — a positive culture, a detected pathogen.
  • An asterisk, or two. Appended to the result rather than in a column. One asterisk is conventionally abnormal, two critical, and a footnote at the bottom of the page normally states the convention for that laboratory. Extract the footnote.
  • The word itself. CRITICAL, PANIC, ALERT, sometimes in a comment line beneath the result rather than on it.
  • Typography alone. Bold, a different colour, or a shaded cell. This one is invisible to a text extraction and visible to a vision model, and it is the strongest argument for keeping a visual pass on lab reports rather than working purely from an extracted text layer.

For interchange, HL7 v2 standardises this in its abnormal-flags table, which is where L, H, LL, HH, N, A and AA come from, along with values for susceptibility results and for direction of change. If your output is going anywhere near an interface engine, normalising your extracted marks onto that table is worth doing, and the mapping from a printed asterisk to AA is a decision you should record rather than bury — that decision is exactly the kind of thing an extraction field audit trail is for.

Why you must not recompute it

It is tempting, having extracted the value and the reference range, to derive the flag: if the value exceeds the upper bound, mark it high. This produces a field that looks like the printed one and is not.

The reason is that the two are computed against different limits. Reference intervals describe the central range of a healthy reference population. Critical limits are a separate, much wider set of thresholds set by the laboratory’s medical director, and there is no arithmetic relationship between them — a critical limit is not “twice the reference range” or any other multiple. There is no published universal table you can substitute either; the limits differ between laboratories by design. If the report does not print the critical limit, and most do not, you cannot derive the flag, full stop.

A weaker version of the same argument applies even to abnormal flags. The laboratory computed its flag against the interval it applied, which may be a demographic partition it selected using patient information the report does not print. So your recomputation can disagree with the report on a result where the report is right and you are missing an input.

The correct design is to transcribe the flag and separately record whether your own comparison agrees with it. The agreement check is genuinely useful — as the reference-range page argues, a disagreement between a printed flag and an extracted range is one of the best available detectors of a column misalignment — but it is a validation signal, not a source of the field. Keep them in different columns:

"flag_as_printed":      "HH",
"abnormal":             true,      <- transcribed, not derived
"critical":             true,      <- transcribed, not derived
"flag_convention_note": "** = critical, per page footnote",
"derived_comparison":   "above_reference_high",
"derived_agrees":       true

Modelling it as its own field

A boolean critical field is worth having as a first-class column rather than as a substring of a flag string, for a reason that is about queries rather than about tidiness. The population of critical results in a corpus is small, and it is the population every audit, every quality review and every retrospective study starts from. If it is only recoverable by string-matching a flag column whose conventions vary by source laboratory, then every one of those queries has to reimplement the convention mapping, and they will diverge.

Three more fields earn their place next to it. The direction (high or low), because a critical potassium high and a critical potassium low are different events. The verbatim flag, so the mapping is auditable. And the source laboratory, because the mapping is per-laboratory and you will need to revisit it when a new source arrives.

Resist the urge to add an interpretation field. Whether a critical result was appropriately acted upon is a clinical and operational question about a specific patient, and it is not something an extraction pipeline should be emitting an opinion about. Extract the fact that the laboratory flagged it. Everything after that belongs to people with a licence.

The callback note, and where it hides

Because the regulation requires the alert to be documented, a report with a critical result frequently carries a note recording it — a line giving a time, an initial or a code for who was called, and sometimes a read-back confirmation. It is almost never in the results table. It is a free-text comment appended below the analyte, or in a comments block at the end of the report, or on the last page under a heading.

Two practical consequences. First, an extraction scoped to the results grid will miss it entirely, so the schema needs a comments array that can attach to a specific result or to the report as a whole — the trade-off in that shape is worked through in nested and flat extraction schemas. Second, the note names people — the caller, the recipient — which makes it one of the few free-text fields in a lab report that reliably contains identifiers about somebody other than the patient. If the comment block is going to a third-party model, it is exactly the kind of field where the minimum necessary standard bites: extract the timestamp and the fact of notification if that is what you need, and do not persist the whole comment string into a table that a hundred people can read. The mechanics of stripping it are in PII redaction, and the reason the redaction has to happen before the request rather than after the response is in PII in LLM logs.