Safety and confidence
The validator compares Component, Property, Time, System, Scale, and Method when the report supplies the corresponding fact. It runs after every ordinary candidate-retrieval path and before ranking can emit a code.
Units are evidence, not identity
The raw OCR unit is preserved. UnitAssessment reports a canonical UCUM-like
form and one of four states:
Do not write UnitAssessment.canonical back into the raw observation. For
example, a fax U/L may yield canonical arbitrary-unit evidence {arb}/L;
retain U/L in LabObservation.unit and display that printed surface to the
reviewer. The mapper accepts {arb}/L for backward compatibility, but that
tolerance is not permission to replace report text.
Gemini may optionally explain an unrecognized or recovered OCR unit, such as a
lowercase l versus capital I in ulU/mL. That suggestion is advisory
review metadata only. It must not overwrite LabObservation.unit, bypass
unit/property validation, or become a registry mapping without an audited
clinician correction.
| State | Meaning | Mapping behavior |
|---|---|---|
valid |
The printed surface parsed directly, including a report note such as (calc) that is stripped into annotations. |
Use it as property evidence. |
recovered |
A bounded unit-grammar repair was verified, for example ulU/mL to u[IU]/mL or mgdL/ to mg/dL; the accepted surface is in recovered_surface. |
Use the canonical form while retaining raw text and repair trace. |
missing |
No unit was extracted. | Review by default; a confirmed ordinary panel component or exact clinician-approved template can proceed if all remaining safety facts agree. |
unrecognized |
The surface could not be parsed. | Keep likely candidates, return review/abstain diagnostics, and request correction. Do not label every candidate invalid. |
The grammar covers every UCUM example unit of the pinned release (annotations,
groups, bracket atoms, a leading solidus), the unit names, scale words and
report notes laboratories print, and the release's own display forms; see
OCR recovery for the list. Two
additive fields (2026-09-17) carry the trace: recovered_surface is the
accepted surface of a recovered repair, and annotations holds the
non-dimensional notes read off the surface, both report notes (calc,
by wt) and UCUM annotations (creat from mg/g{creat}). Annotations never
change a dimension: cells/uL shares its dimension with 10*3/uL and /uL.
A term whose LOINC example lists alternatives ([IU]/L;m[IU]/mL) accepts any
of them.
Units help select the correct LOINC Property and sibling. A valid dimensional conflict remains a hard failure: mass cannot select a molar property, a molar unit cannot select a mass property, and a dimensional unit cannot select a ratio/fraction result. This boundary protects LDL cholesterol from LDL particle number and similar clinically distinct siblings.
Complete, incomplete, unreadable, missing
A printed unit is compared with the candidate's, and only a complete unit can contradict it (2026-09-24):
| Comparison | Example | Validation |
|---|---|---|
| complete | mg/dL, x1000/μL, 10^6 against a term whose own unit is 10*6 |
Dimension and property are checked; a conflict is a hard failure (LDL Size nm never files as a mass code). |
| incomplete | 10^3 or x1000 where the candidate expects 10*3/uL |
Validated exactly like a missing unit (unit_partial when a unit is required). |
| unreadable | a surface the grammar cannot read (two unreadable characters, an unknown atom) | Reviews, unless the candidate is an exact clinician approval or a confirmed panel member, which may proceed as for a missing unit. |
| missing | no unit | Unchanged: a required unit reviews; the same approval and panel exception applies. |
A term whose UCUM example units are all bare annotations ({INR},
{score}, {ratio}) needs no printed unit: by UCUM an annotation alone is
unity, a result style, and an INR is never printed with a unit. An annotated
dimensional unit (mg/g{creat}) is still a unit.
A dimensional unit beside a number is a quantity, so a candidate whose
Property never carries a dimension (PrThr, Prid, Imp, Type, Find,
ID, Titr, Score; LOINC's property axis, closed) is rejected
(dimensional unit conflicts with a presence, identity, titer or score
property, 2026-09-25): C-Pep in ng/mL had tied with an allergen-mix
[Presence] term whose Latin names explained its letters. An answer word
beside a stray unit (Negative mg/dL) is not this rule's business: the
value's shape says what kind of result was printed.
A ratio unit says what it relates (2026-09-25; units.ratio_basis,
units.denominator_annotation). The dimensions of mg/g and mmol/mol
both cancel, but the atoms on each side of the solidus do not: a mass ratio
selects MRto and rejects SRto (mass ratio unit conflicts with a molar
ratio property), a molar ratio the reverse. An annotation on the
denominator (mg/g creat, which the release itself writes as mg/g{creat}
on 1,434 example units) names the denominator analyte: a slashed Component
whose denominator it does not name (creat begins Creatinine, not
Globulin) and whose own examples do not carry it is another ratio (unit
names a denominator the candidate's component does not have).
ALBUMIN/CREATININE RATIO, RANDOM URINE in mg/g creat had sat 0.005 above
the albumin/globulin ratio and the molar ACR term. The annotation also
names the denominator through a release name of the term that is not a
word of its numerator (WBC for Leukocytes under
Erythrocytes.nucleated/Leukocytes), singular and plural alike (WBCs;
safety._denominator_named, 2026-10-05): NUCLEATED RBCS printed /100
WBC had lost every ratio term, the release's own example /100{WBCs}
included. Read from the unit and the candidate's own Component, examples
and release names, never from an analyte list.
Units are supporting evidence, never a reason to abstain (the practice's
decision, 2026-09-24; config/axis_safety_policy.json 2026.09.24.1 sets
missing_unit_outcome and unrecognized_unit_outcome to accept). A
missing, magnitude-only or unreadable unit never blocks a candidate; a mapped
row that went without the unit its code would need carries review_flags
(unit_missing, unit_incomplete, unit_unreadable). Where the unit is what
would pick between siblings (Glucose in mg/dL is MCnc, in mmol/L SCnc), the
practice's approved Property for that analyte and material decides
(meaning_groups[].practice_property); with none, or two, the margin decides
as usual. A complete unit that contradicts a candidate still rejects it: that
selects the right sibling, it does not abstain the row. Publication still
requires a unit a clinician types to parse (it becomes the approval's
requirement); an approval without a unit publishes with a warning.
Ratios need no unit: the units cancel, and laboratories print a ratio bare,
as ratio, as mg/mg or g/g. All of these are accepted against every ratio
style in the release ({ratio}, mg/mg{creat}, g/g{creat}, a blank
example); a dimensional unit (mg/dL) on a ratio row still rejects the ratio
term. Which Properties are dimensionless is read from LOINC's property codes:
ratios end in Rto, fractions in Fr, relative quantities start with Rel,
plus Ratio, Prct and ARat. Rates (MRat, SRat: mass or substance per
time) are dimensional, so mg/d and mg/24 h are units of a 24-hour urine
term, never a conflict. A discriminator word is observed when a row word the term's own release
names use contains it: MICROALBUMIN/CREATININE RATIO names the albumin of
14959-1 (which LOINC names "Microalbumin/Creatinine"); Prealbumin does not.
Every Component word is observed when the row prints the term's own long-name
head, the release's clinical wording of the Component (_name_head_covers,
2026-09-25): Direct Bilirubin names Bilirubin.direct (1968-7), whose
Component Bilirubin.glucuronidated+Bilirubin.albumin bound holds the
albumin discriminator; Bilirubin alone prints no head and is still
rejected there.
Under the configurable review policy, a candidate held back only for its
unit ranks with the survivors and is never filed; when it leads, the row
abstains naming it (unit_missing), stages.unit_review_candidate_count.
"Magnitude only" is what was printed (units.magnitude_only_unit), not a
verdict: the release itself prints 10*6 as the complete unit of counts in
millions. When an approval or confirmed member proceeds on an incomplete or
unreadable unit, or on a unit whose prefix was unreadable, the mapped result
carries review_flags (unit_incomplete, unit_unreadable,
unit_prefix_unreadable) so the main project files it for LOINC review; a
mapped row's reasons are emptied, so this field is the one that survives.
When such an approval cannot proceed (a source-scoped or legacy entry), its
blocked outcome is approved_candidate_unit_review with "needs review",
not "was rejected".
The grammar reads notation compositionally rather than from a list of printed
forms: a leading multiplication sign before a number is only a sign
(x1000/uL is 1000/uL); 10 followed by ^, *, E or a parenthesised
integer is a power of ten (10E3, x10(9)/L); a bare 1.73 denominator is
the body-surface-area convention (mL/min/1.73 reads as mL/min/1.73.m2,
the eGFR dimension); an arbitrary unit may lose its brackets (arb'U/mL).
Control, format and private-use characters become one visible placeholder;
a single placeholder before an atom that takes SI prefixes is an unknown
prefix (10^3/<?>L keeps the volume dimension and is recovered), two
placeholders stay unreadable. The force-exact result-style guard treats a
style no unit establishes (absent, unreadable, magnitude-only) as unknown,
so a certified WBC force entry applies to x1000/μL or 10^3; only a
parsed contradicting style (a percent) keeps it off.
A printed % never matches a term whose units are only UCUM annotations
({titer}, {ratio}, {index}). Both are dimensionless, so the dimension
check alone passed them, but a percent is a fraction and a titer, ratio or
index is not: %NEUT reached neutralizing-antibody titer terms through
their Neut alias. This is a hard failure (percent unit conflicts with the
candidate's titer, ratio or index result style), read from the candidate's
own example units, not from a list of analytes.
Unitless LOINC result styles
A blank report unit is valid when the selected active LOINC term itself has a
non-dimensional official example token, currently {ratio} or {titer}. For
example, total-cholesterol/HDL cholesterol ratio (9830-1) may be reported as
4.5 without a physical unit. The mapper therefore does not reject that row
solely because UNITSREQUIRED=Y.
This is not a broad ratio exemption. A ratio term whose LOINC example is a
dimensional surface such as mg/g still requires an observed compatible unit.
The editable values live in
axis_safety_policy.json -> unit_policy.unitless_example_tokens; changing
them requires clinical review, regression tests, and a new artifact release.
A second, narrower exemption (policy 2026.09.17.1,
unit_policy.unitless_property_codes = Rto, MRto, SRto, CRto, DRto, NRto)
covers a ratio-of-like-quantities property whose term documents no
example unit at all, such as the GGT/AST ratio (2325-9, CRto,
UNITSREQUIRED=Y): the printed number is a bare ratio and a blank unit does
not block it. A ratio term with mg/g keeps its requirement, ArVRat
(eGFR) is never in the list, and a dimensional unit against any ratio
property remains a hard failure. Without the policy file the set is empty
and nothing changes. The review contract applies the same rule to
approvals with unit=null.
A row whose value has no number (Negative, None seen, 2+), no explicit
scale and no unit is treated as non-quantitative (value_shape fact): it
conflicts only with Qn candidates and never asks for a unit. A printed
unit is itself evidence of a quantitative result style, so NONE SEEN with
/HPF keeps its field-count terms (the first production run of this rule
had rejected every candidate of such rows). No result vocabulary is
consulted, so an unseen word behaves like a seen one.
The editable release-controlled files are:
config/unit_surface_rules.json: grammar-level OCR surface repairs.config/unit_release_vocabulary.json: generated from the pinned release bytools/export_example_units.py, never hand-edited: the UCUM annotation tokens the release uses, the display words LOINC pairs with them (creatinine->creat), and the display forms the grammar cannot read aligned to their terms' UCUM example (arb U/mL->[arb'U]/mL). The grammar always comes first; a pairing that shares no word with its UCUM example (SD,Da) is left out so such a printed unit goes to review.config/axis_safety_policy.json: unit policy plus reusable axis safety vocabulary.config/axis_context_aliases.json: context and method-family equivalences such asImmunoBlotand LOINCIB.
These files are not an unbounded per-analyte alias list. Increment their version, run tests, run deployment canaries, and deploy them with the pinned registry artifact.
Scientific count surfaces such as x10E3/uL and x10E6/uL are normalized by
the unit grammar. ratio is a non-dimensional result-style surface and can
only support a compatible ratio/fraction term. These are grammar rules, not
analyte-specific maps. See OCR recovery contract.
The printed value
The value cell is a fact of the row, read by grammar
(result_style.value_shape, 2026-09-25): number (4.5, 1,234, 5.7 H),
comparator (<40), titer (1:64, <1:64), range (2-5), grade
(2+), answer (one to three words without a digit: Negative, None
seen, Pattern A), pointer (See note), status (TNP, Not
reportable), sentence (four or more words or sentence punctuation), or
nothing (O.9 is no number; Positive 1:80 is mixed). Only the pointer
words, the status phrases and the degree words of an ordinal answer are a
vocabulary, versioned in config/axis_safety_policy.json (value_policy,
2026.10.05.1); every other shape is grammar, so an unseen answer word
behaves like a seen one. An answer whose first word is a degree word
(NONE SEEN, FEW, NEGATIVE, NOT DETECTED; result_style.ordinal_answer,
2026-10-05) states a presence or an amount, never a type: Crystals
[type] (Prid, nominal) then joins Crystals [Presence] as its sibling
and the presence term is the answer, while a name outside the vocabulary
(CALCIUM OXALATE) keeps the type term apart for a reviewer. CRYSTALS
NONE SEEN had tied the two by 0.003 on every urinalysis with microscopy.
What each shape decides: a pointer or a status is no result, and the row
abstains before retrieval with value_not_a_result by every path (fast
path and force-exact included; production had filed See note under a
microscopy term and TNP as measurements; the application filters such
cells first and the mapper is the second net; a result_kind the
application sends is honoured the same way, anything but result). A titer
is a Property fact (Titr) unless a dimensional unit contradicts it, and a
candidate that is not a titer result is rejected (value is a titer;
candidate is not a titer result): <1:64 keeps Ehrlichia chaffeensis IgG
Ab [Titer] and rejects its [Presence] and [Units/volume] siblings,
which retrieval had left within 0.003 of each other. A sentence fits only a
narrative or document term. An answer word or a grade establishes the
non-quantitative scale as before (Negative keeps the presence term and
rejects the Qn siblings); with an answer word and no unit a semi-quantitative
titer sibling groups with the presence term and ranks after it. A bare
number, comparator or range with no unit is evidence only
(universal_axis_facts.value) and never a gate: index-reported presence
tests print bare numbers.
An approval of the row's surface rejected on the value's shape (a titer, a
sentence, or a Scale the value contradicts) is inapplicable, not blocked:
it was made for rows printing another kind of value. Urine GLUCOSE
NEGATIVE under the serum approval 2345-7 therefore ranks the test-strip
presence term instead of stopping on the approval
(inapplicable_approved_candidates).
Specimen and panel context
specimen is the analytical material; collection_specimen records how the
sample was drawn. Blood, Venous may be compatible with blood-derived
serum/plasma results and rules out physically disjoint urine/CSF candidates,
but it must not claim that every test was analyzed as whole blood or
serum/plasma. A word that names a collection device rather than a material
(swab, brush, scraping, aspirate, cup, kit;
specimens.material_words, 2026-10-05) states no analytical specimen: a
row printed Swab rejects no System, while Vaginal swab keeps its site and
still rejects a urine term. A report's either/or heading (... MALE
UR/SWAB) had reached the mapper as specimen: Swab and rejected every
NAA term of a Trichomonas row.
An exact recognized report heading may confirm a component's membership in an official LOINC panel. If the row lacks an analytical specimen, the clinician-approved panel default can then supply that context. An explicit row specimen wins, and a contradiction of a printed row fact is a hard failure. The parent panel LOINC is never emitted for an individual result row. See Panel context.
A specimen carries its provenance (LabObservation.specimen_source,
2026-09-24): row (the row's own cell), section_heading (the heading above
it) or report (a document-level phrase). Two conflicts are soft evidence to
confirm, never a hard rejection: a report-level specimen that contradicts a
candidate's System (a document-level Ser/Plas stamped on a CBC section), and
a row specimen that contradicts a confirmed panel member whose reviewed panel
default agrees with the candidate (Serum stamped on a hospital's CBC row;
the eosinophil-count approval stays named for review instead of stepping
aside for serum proteins). The second is soft only while the specimen is the
only contradiction (2026-10-06): for an approval another printed fact already
refused, the mapper asks the specimen gate with printed_decides and the row's
or section's specimen outranks the member default, so the urinalysis
microscopy rows that run onto a page without their heading and reach the CBC
heading with Urine printed beside them (their /HPF refuses the blood
count) set the blood-count approval aside as inapplicable. Both soft
conflicts review with specimen is soft
evidence and conflicts with the candidate system; confirm the specimen, and
an approval blocked that way is named for review rather than set aside as
inapplicable. A report-level specimen is also only a non-explicit retrieval
hint, so it cannot steer candidate retrieval to another System (serum IgE
terms for a blood count).
An approval of the row's surface whose System contradicts a trusted
heading's default specimen, while a confirmed member of that heading survived
validation for the row, was made for another context and is inapplicable
(2026-09-25; Mapper._without_panel_default_approvals): under URINALYSIS
REFLEX the serum approval of GLUCOSE steps aside and the urine test-strip
member leads, whether the value is NEGATIVE or 97 mg/dL. Only a trusted
heading with hard defaults speaks (never a hint or sibling inference), only
when the row prints no specimen of its own (a report-level phrase is not the
row's, so it does not keep the heading out), and only when the heading has a
surviving member for the analyte: a non-member row under the wrong heading
(hemoglobin A1c under a chemistry panel) keeps its approval. Since
2026-10-02 the rule also covers an approval another gate rejected first:
under URINALYSIS, COMPLETE the practice's blood-count approval of RBC
(789-8) is rejected on /HPF before the specimen gate runs; it is
inapplicable, not blocked, and the urine sediment member 13945-1 files.
Evidence about the material ranks row cell, then section heading, then
document. A confirmed member's reviewed panel default therefore replaces a
report-level specimen outright (specimen_source: confirmed_panel_default):
the CBC rows under their own trusted heading are whole blood whatever the
document header says. And a specimen that is not printed on the row (a
report-level phrase, or a memberless panel's soft default) never blocks an
approval of the row's own surface: the approved code maps with
review_flags: ["specimen_unconfirmed"]. A specimen the row itself prints
still decides.
When an official panel component has passed normal safety validation, it gets a
strong ranking preference over non-member siblings. That allows CMP Globulin
to select its documented calculated component rather than an unrelated serum,
plasma, urine, or body-fluid globulin sibling. Panel membership remains ranking
evidence, not a validation bypass.
Method and timing
Method tags are safety context, not decoration. Calculated LDL and LDL
Direct must not silently choose one another's method-specific sibling.
Conversely, a missing method does not reject a generic method-unspecified
LOINC. The mapper uses a method-specific LOINC only when the method is explicit
in the row or supported by reviewed source evidence. Method families come
from the reviewed axis_context_aliases.json; a multi-word LOINC method
that contains a family's own word of five or more letters belongs to that
family, so Creatinine-based formula (CKD-EPI 2021) is a calculated method
and a row that says calc fits it. A parenthesised qualifier after a method
names the formula or the instrument, not the method (2026-10-07): Calc
(NIH) is a calculation and IA (Roche) an immunoassay, unless the
qualifier names a family itself; two words of which one is a family's own
alias of three or more letters and the other names nothing (calc nih once
the parentheses are gone) read the same way, while two-letter aliases
(if, ia, ib) stay out of sentences. LDL Chol Calc (NIH) had failed
every calculated term, the practice's approval included. For an approval of
the row's own surface a printed method whose every word the approved alias
carries is already judged (Mapper._validation_view): the application read
it out of the name, and the clinician judged the name whole. A sentence that contains a family's
multi-word alias as a phrase belongs to that family too (2026-10-05): a
report's methodology footnote Roche Cobas 6800/8800 systems using
real-time Polymerase Chain Reaction (PCR) is the PCR family and fits
Probe.amp.tar, while the instrument words alone name no method; TMA,
transcription mediated amplification and nucleic acid amplification
(test) are reviewed surfaces of the same family (axis_context_aliases.json
2026.10.05.1). A formula name printed in the row
(CKD-EPI, CKD-EPI 2021, MDRD; reviewed method surfaces of
axis_context_aliases.json 2026.10.05.1 with their own canonicals) is the
row's method, so a cystatin C formula fails it while both CKD-EPI equations
fit; beside such a name the calculated family's manner word yields
(Estimated GFR (MDRD) is one clue, context._formula_over_manner), while
LDL Direct calculated keeps both clues and its conflict. A year contradicts only a printed year
(2026-09-25): CKD-EPI 2009 rejects the 2021 term, while a row that names
the formula without its year (CKD-EPI) fits every year of it. Production
had rejected the approved 2021 term for such a row and filed the 2009 one.
Siblings that differ only in a method the row does not print are one
unresolved meaning group (meaning_groups[].unresolved: "method_variant",
2026-09-25): the 2009 and 2021 CKD-EPI equations, calculated and direct LDL,
the three stool O&P methods. With no printed method they are unresolved
unless the practice approved the analyte in exactly one of their methods
(the existing rule) or, under a trusted heading, exactly one of them is a
confirmed member of the heading's record (the urinalysis record names the
test-strip specific gravity, not the automated strip; the record is the
practice's statement of the method the panel reports); with a printed method that fits several of them
(CKD-EPI) they are unresolved when the top two tie on every ordering key
before LOINC's common rank (approval of the row's surface, printed axis
matches, the practice's approved targets, panel membership). The mapper
then abstains with method_variant_ambiguity, naming the leader and its
variants, instead of letting the margin between them file one; a reviewed
registry leader is exempt (the reviewer chose the variant for that name).
So Est GFR (CKD-EPI) files the approved 2021 term and reviews with no
approval, and the expanded Estimated GFR (Non-African American) reviews
under a practice that approves two eGFR methods until the row's method
column says which.
What decides inside a group when the row prints no method is the practice's
policy (practice_policy.method_default, 2026-09-29). With
practice_then_method_less, the order is: an approval of the row's own
question; a confirmed member of the row's trusted panel; the practice's
approved code for the analyte; LOINC's method-less term; the practice's
single approved method where no method-less term exists; otherwise the
row reviews. method_less puts the method-less term before the panel
member and the practice's code. ask lets neither a method-less term nor
the practice's method decide: the group is unresolved unless the panel
record names the method.
Retrieval may return the method-specific siblings alone. The mapper then
looks the method-less sibling up (axis_siblings.AxisSiblingIndex: the
same Component, Property, Time, System family and Scale, no Method; active
result terms only; built once from the terms the catalog holds) and
validates it like any candidate (Mapper._method_less_siblings, source
sibling_completion, evidence completes). Nothing is added when the row
prints a method, when a method-less survivor is already there, or under
ask. method_variant_ambiguity therefore remains where LOINC has no
method-less sibling and the practice approved no single variant
(fibrinogen by coagulation assay or derived, the Lyme immunoassay and
immunoblot interpretations): a real question, asked once. A filing the
policy made is recorded in stages.policy_defaults as {axis: "method",
choice: "method_less", code} (completed: true when the term was looked
up); it carries no review flag, because the method-less term is the
general reading. The other filing the policy makes, the code the practice
approved for the analyte over its method-less sibling
(practice_then_method_less), is recorded the same way as {axis:
"method", choice: "practice_method", code} (2026-10-05): the automated
immature-granulocyte count over LOINC's method-less count. Nothing is
recorded when the row printed the method.
A row that states a total names the whole component. LOINC writes a
sub-fraction as Component.qualifier (Thyroxine.free, Bilirubin.direct,
Cholesterol.in LDL), so a candidate whose dotted sub-part the row does not
mention is hard-rejected (row states a total; candidate is an unstated
sub-fraction of the component): T4 (THYROXINE), TOTAL keeps Thyroxine
and loses Thyroxine.free; Bilirubin, Total keeps Bilirubin.total and
loses Bilirubin.direct; a ratio such as Cholesterol.total/Cholesterol.in
HDL passes for Total Cholesterol/HDL ratio because every sub-part is in
the row. Grammar only: LOINC's dot and the English word, no analyte list. A
row without the word stays ambiguous on purpose. One reading was added for
Release A (0.3.5, 2026-10-08): LOINC writes a lipoprotein fraction as the
dotted sub-part (Lipoprotein.alpha is HDL, Lipoprotein.beta.subparticle
the LDL particles) and says HDL/LDL only in the term's short and related
names, so a row that prints one of the policy's fraction acronyms
(lipoprotein_fraction_acronyms) which the term's release names carry has
named that sub-part: HDL-P (total) states the total of the alpha fraction
and files the practice's 49748-7; T4 (THYROXINE), TOTAL prints no such
acronym and still loses Thyroxine.free.
A printed unit reckoned per volume, per mass or per time contradicts a
Property reckoned per another (0.3.6, 2026-10-09,
safety._property_dimension_conflict): LOINC's Property grammar says a
concentration (…Cnc) is per volume, a content (…Cnt) per mass and a rate
(…Rat) per time, and the unit's dimension says what the print is per. It
decides only where the term's own example units do not: Lead [Mass/mass] in
Specimen (MCnt, no example unit) had held the margin against the venous-blood
lead term for a row in ug/dL, and Albumin [Mass/time] in Urine collected for
unspecified duration (MRat) against the urine albumin in mg/dL, which the
time gate rightly allows for a random collection. A dimensionless print
(mg/g, %, a per-100 count) says nothing here; a per-100 print's apostrophe
(/100 WBC'S) is unit noise removed by the surface rules
(unit_surface_rules.json 2026.10.09.1), so the print reads as the
per-100-leukocytes count and contradicts a count per volume.
A method clue read out of the row name is void for a candidate whose own
component contains every word of it. LOINC's method axis holds questionnaire
and assay names that are ordinary words elsewhere (CAST is a survey
instrument), so the catalog-aware context extractor reads CAST inside
HYALINE CAST as a method; against the sediment term Hyaline casts that
word names the analyte, singular or plural, and is not a method conflict
(observed method word names the candidate component). A real method word
(Immunoassay) still conflicts. The rule is derived from the candidate's
component text, never from a list of analyte names, and applies in both the
validator and universal signature grouping.
A method or time clue may not consume the row's last analyte word. The
catalog-aware extractor reads LOINC Part names in the row, and some are
also the analyte's own abbreviation: Neut is the neutralization method,
PT a time aspect. When the clues of every axis together cover every
word of the row, the leading word is the analyte (lab names put it first),
and the method and time clues on it are released
(context._release_analyte_clues): Neut % (Auto) keeps Auto as its
method and Neut as its analyte, and a bare PT or INR states neither a
method nor a time. LDL Chol Calc keeps Calculated, because its analyte
words are not clues.
A method or time clue that LOINC itself uses to name a retrieved candidate's
analyte is void for the row (context.release_candidate_clues, 2026-09-25).
Direct Bilirubin reads direct as the method Direct assay; production
therefore hard-rejected every methodless term of the analyte LOINC names
Bilirubin.direct (1968-7) and filed an amniotic-fluid total bilirubin
measured by direct spectrophotometry (12476-8). The release runs after
retrieval, against the retrieved terms: a clue whose words are all
analyte-head words of a term (grounding.analyte_head_words: the Component
and the long name's head, never related names, which carry Calc and Dir)
that also names another word of the row is dropped, the facts and the
universal candidates are rebuilt without it, and
stages.released_clues[{axis, value, span, named_by}] records it. LDL
Direct keeps its method (the bilirubin term names no other word of that
row); LDL Chol Calc keeps Calculated. The registry fast path applies the
same release against the approved term alone, so an approval of Bilirubin,
Direct files there.
Fasting is generally pre-analytic context, not a replacement for a 24-hour
LOINC Time axis. Timing words are normalized to LOINC time aspects first
(time_surface_code: random, spot, point in time -> Pt; 24 hour,
24 hr, timed urine, any <n> hour -> <n>H; fasting, trough,
post challenge pass through). An explicit duration conflicts with a
point-in-time candidate and with a different duration; an explicit
point-in-time collection (random) conflicts with every timed sibling, so
Albumin, Urine collected at random no longer ties with its 24-hour term.
A component acronym of the form X/Y in the row name (A/G Ratio) counts
as observing both halves of a candidate's Albumin/Globulin component, so
the albumin discriminator is not an unobserved qualifier there.
Qualitative, ordinal, titer, and numeric result styles are compared
against the candidate Scale and Property rather than treated as ordinary units.
A report scale word is normalized to its LOINC scale code before that
comparison (ordinal -> Ord, nominal -> Nom, qualitative -> Ord,
quantitative -> Qn, semi-quantitative -> SemiQn, narrative ->
Nar; the reviewed scale entries of config/axis_context_aliases.json),
so a consumer that labels a test-strip result ordinal no longer conflicts
with an Ord presence term. A word LOINC does not use is no scale at all
(2026-09-25; scale="%" had hard-rejected every candidate of Lymph %
(Auto) as a text mismatch): an unparseable scale is absent, never a
contradiction. A consumer's scale label is its classification of the printed
value, never a printed fact (no report prints "ordinal"), so it contradicts a
candidate only across the boundary the value itself proves, a number against
a word: within Ord, Nom, SemiQn, Nar and Doc the label decides
nothing (2026-09-25; an Ord label had made the practice's approved [Type]
term for LDL PATTERN, Scale Nom, inapplicable and the row a case), and the
value's own shape keeps the finer distinctions (a sentence fits only
Nar/Doc, a titer only Titr, see the value grammar below). The remaining
property-specific relaxation (Qn/SemiQn for titers) applies to the codes.
The validator, the universal index and the ranking axis matches share this
one rule (scale_surface_code, _scale_surfaces_compatible).
Name heuristics and clinician approvals
Some checks infer from the printed name whether a candidate is the named
analyte: antibody isotype, organism family and species, a component or
system qualifier the row does not print, a row that states a total, an
unobserved component discriminator, high versus low density, and a
lipoprotein fraction acronym (LDL, HDL, VLDL). They exist to keep an
IgG row off an IgM code and an HDL row off an LDL code. They are
heuristics about naming, and LOINC names are not uniform: the LDL particle
terms are filed as Lipoprotein.beta.subparticle and say LDL only in
their short and related names. The acronym check therefore reads every
release name (component, long common name, short, consumer and related
names), as the density check does.
A clinician approval of the row's own surface is the name judgement. When
the candidate is such an approval (exact_for_row with clinician
authority, on the full pipeline and on the registry fast path alike), the
name heuristics are recorded (deferred_name_conflict, and a reason
name heuristic deferred to the clinician approval) and skipped. Every
physical gate still applies: time, unit dimension and property, specimen,
method and scale. Publication is where the heuristics check the
clinician's choice, so validate_review_decision keeps them as errors (an
IgG code for a row printed IgM is refused); once published, the approval is
not second-guessed by a naming rule.
The same judgement covers the facts read out of the name. For an approval
of the row's own surface, the validator sees the row's own columns
(specimen, method, time), not the specimen, method or time words parsed
from the approved name: Blood in White Blood Cells (WBC), Stool,
Direct in Direct HDL, Concentration in Mean Corpuscular Hemoglobin
Concentration were already judged by the clinician
(Mapper._validation_view, full pipeline and fast path alike). Context
conflicts read from the name (Plasma or Serum gives two specimen clues)
do not override such an approval either. A specimen, method or time the
row prints in its own column still decides. A duration printed in the
name (Calcium, 24Hr Urine) states the time of a candidate whose own time
aspect is that duration; it never contradicts one, because a number in a
name can also be a challenge time (Glucose 2 hr post), which LOINC files
inside a point-in-time Component.
Siblings that name one analyte
LOINC often has several terms for one reported analyte that differ only in
an axis the report does not print: Hepatitis C virus Ab in Ser,
Ser/Plas and Ser/Plas/Bld; a method-specific and a methodless term; the
general Lipoprotein.beta.subparticle size and its .medium subparticle.
Between such siblings the confidence margin measured only retrieval noise,
so the row reviewed although every survivor named the same analyte (four
hepatitis C terms scored 0.938 each in production). After ranking, the
mapper therefore groups the survivors by meaning (meaning.MeaningGrouper)
and takes the margin between groups:
- Key. Component root, Property, Scale, Time and System family (serum
and plasma variants,
PPPandPRPare one family). Under a panel trusted for ranking, a confirmed member and its non-member twin in another System family are one group. - Component root. A term that adds a dotted qualifier to another
surviving term's Component (a ratio keeps its denominator:
Lymphocytes.variant/LeukocytesextendsLymphocytes/Leukocytes) joins that term's group when the row prints neither the qualifier's words nor a word only the qualified term's LOINC names carry. An abbreviation of a qualifier word counts as printed (Immforimmature,Bandsforband form); a synonym from the qualified term's names must be the row's own word (Atypicalforvariant), because a row word such aslymphbegins many release words that do not name the qualifier. A base that asserts a method of its own is not the general reading. An isotype the row prints is a fact (2026-10-05): a term that adds an isotype or a numbered partner the row does not print (Ab.IgG+IgMfor a row printingIgM,virus 1+2for a row printing1;meaning._pair_qualifier) is an unprinted extension of the row's term and joins its group after it, and a term that drops the printed isotype (HSV 2 AbforHSV 2 Ab, IgG) is the general term of a narrower printed analyte and joins the isotype term's group after it, because LOINC's isotype-less antibody term means any class, which the print contradicts (_printed_isotype_extension).HEPATITIS A IgM,Herpes Simplex 1 Ab, IgGandHerpes Simplex 2 Ab, IgGhad reviewed on margins of 0.055-0.07 between such pairs. - Material the practice uses. When the row states no specimen, terms
that differ only in System join when the practice's clinicians approved
that analyte (Component and Property) in exactly one material family, and
a term of that family wins:
Lymphs %meetsLymphocytes/Leukocytesin blood, body fluid and synovial fluid, and the practice approved blood only. Two approved materials (serum and urine osmolality) keep the Systems apart for review; the group recordspractice_system. - A count per microscopy field.
/HPFand/LPFare a urine sediment examination by that method (2026-10-07): urine and urine sediment are one material, the field microscopy sibling is the printed method the group prefers (in a general group too), and Component roots fold singular and plural (ErythrocyteandErythrocytesare one analyte). Urinalysis rows that reached the mapper under the CBC heading had reviewed between the sediment count by microscopy andErythrocyte [#/area] in Urine by Computer assisted; they file 13945-1 / 5821-4 wherever the heading landed. A printed other material (stool, sputum, a wet preparation) keeps its own terms: the rule never files a urine sediment code over it. The unit gate reads the same fact: a count per field is not a concentration, so a...Cncterm with no example units (Leukocyte esterase [Units/volume] in Urine, which had outranked the sediment count) is rejected (safety._field_count_conflict). - Scale on a printed number. A number printed with a dimensional unit is
a quantitative result (2026-10-06): a semi-quantitative sibling, the test
strip with a detection limit the row never prints (
Albumin [Mass/volume] in Urine by Detection limit <= 20 mg/L test strip), joins the quantitative method-less term's group and ranks after it.Albumin, Urineprinted12 mg/Lhad reviewed at 0.005 between the two. - Method. With no printed method, a method-specific term joins only a
group that has a methodless term, or a set of method-only siblings the
practice approved in exactly one of their methods (stool O&P by light
microscopy;
practice_method). Calculated and direct LDL, each asserting a method the row did not print, stay two groups and the row reviews. - Winner. Chosen by evidence, never by a list: a code a clinician approved for this row's own surface, then the general term over an unprinted qualifier, then the practice's material, then an axis the row printed and the candidate matches, then a code the practice approved for any surface, then panel membership, then no unprinted method, then LOINC's common-test rank.
The winner keeps the score of its group's best member and records the
others (meaning_group_alternatives); stages.meaning_groups lists every
group of more than one term, and the alternatives stay in candidates. A
different Component, Property, Scale or Time is always a different group,
so a genuine ambiguity still reviews, and 0.82/0.08 are unchanged.
A row that states a relation between analytes (X/Y between words, or the
words ratio, index, per, vs: BUN/CREAT, Albumin Creatinine Ratio) is not
one analyte's quantity. A candidate that is not itself a relation (no slashed
Component, no ratio, fraction or relative Property, no relation word) is
rejected (row states a relation; candidate is a single analyte), and a plain
registry alias contained in such a row (BUN in BUN/CREAT) is not retrieved.
Grammar only: HIV 1/2 Ab (a numbered pair), Lyme IgG/IgM Ab (names that
differ only in their last character enumerate), a slash inside parentheses
(RISK RATIO (CHOL/HDL) still says ratio) and a slash inside a reviewed
method surface (INSULIN, INTACT, LC/MS/MS, GC-MS; safety.relation_stated
passes the multi-word method aliases of axis_context_aliases.json, version
2026.09.25.1, to states_relation) state no relation (2026-09-25; the
LC/MS/MS rows had rejected every candidate as "a single analyte"). Like the
other name heuristics, it is deferred for an approval of the row's own
surface. Whether the two sides of a surviving pair name one analyte is the
catalog's reading, not the grammar's (2026-10-08, grounding.slash_enumerates,
read once per row against its candidates and passed to the validator as
relation): a side is the whole text on its side of the slash with the
relation words removed (normalization.slash_sides; ARACHIDONIC ACID and
EPA of ARACHIDONIC ACID/EPA RATIO), and a side names a candidate term
when the term explains every word of it. SGPT/ALT and SGOT/AST are two
names of one enzyme — terms named by both sides exist (SGPT is among the
related names of every alanine aminotransferase term) and the sides do not
each have an analyte of their own; a stray a short side also reaches (ALT
is among the names of a nucleotide term) is not an analyte of the row's —
and ABO/Rh is the pair LOINC writes as the Component ABO & Rh group;
such a slash enumerates, the single-analyte terms are not refused, and the
row records stages.slash_enumeration. ARACHIDONIC ACID/EPA names the
arachidonate terms on one side and the eicosapentaenoate terms on the
other, so it relates them; CHOL/HDL names Cholesterol.in HDL on both
sides but HDL is its sub-part, a denominator, so the relation stands; a
ratio term counts for nothing, nor does a side of fewer than three letters
(Na/K). A hospital's CMP had rejected every alanine and aspartate
aminotransferase term, the practice's approvals ALT (SGPT) and AST
(SGOT) among them.
The mirror (2026-10-05): a ratio of two analytes needs both named. A
candidate whose Component is slashed and whose Property is a typed ratio
(MRto, SRto, NRto: a ratio of two measured quantities) is rejected
for a row that states no relation in its name, prints no ratio unit (no
mass or substance ratio, no denominator annotation; % is a fraction of
a whole, not a ratio of two analytes) and does not name every side of
the Component by that side's own words (grounding.unnamed_relation_sides:
6 against 3, albumin against creatinine; digits count, because
LOINC tells omega 6 from omega 3 by them): row names one analyte;
candidate is a ratio of two. OMEGA-3 TOTAL and OMEGA-6 TOTAL (% by
wt) had filed the omega 6/omega 3 molar ratio 48382-6 outright, the only
OmegaCheck member that survived, whose Component contains the row's words;
a GLOBULIN row no longer carries the albumin/globulin ratio. LOINC's
fractions (...Fr: Hemoglobin A1c/Hemoglobin.total, Lymphocytes/
Leukocytes) and its plain Ratio (Erythrocytes.nucleated/Leukocytes,
printed per 100 cells) relate an analyte to a reference population and
are not read here; OMEGA-6/OMEGA-3 RATIO, CHOL/HDLC RATIO,
ALBUMIN/GLOBULIN RATIO state the relation, ALBUMIN, URINE in mg/g
states it through its unit, and an approval of the row's own surface is
deferred to as above.
A registry alias contained in a longer row keeps its authority only when
every word the row adds is one of the target's own release words (the same
word, or one abbreviating the other: Plt Count, VLDL Cholesterol Cal,
Glucose, Fasting). Otherwise the extra words may change the analyte
(LDL PATTERN, Nucleated RBC %, Small LDL-P): the hit is ordinary
retrieval (registry_match: contained_unexplained, score 0.75, below
acceptance, no registry tier or bonus), so containment alone never files.
With no material known (no specimen printed, no trusted heading with a hard
default) and no approval of the analyte in any material, System siblings of
one analyte join one group and the default material wins
(2026-09-25; MeaningGrouper._default_material_keys), so a practice that
files in serum reads Alpha-1-Globulins as its serum electrophoresis
fraction rather than the urine, body-fluid or synovial term that tied it
at 0.900. Since 2026-09-29 the default is per test family
(Mapper._practice_class_defaults): for each LOINC class, the material
most of the practice's published approvals of that class are in, when the
class has at least practice_policy.material_default.min_codes approved
codes (5) and that material holds at least min_share of them (0.70);
urine sediment counts as urine. On the 2026-09-25 registry: chemistry,
serology and microbiology read in serum or plasma, hematology in blood,
urinalysis in urine; toxicology has no material with the share and
coagulation and blood bank too few approvals, so their rows ask. The
default of a group is the one material among its siblings that is the
default of its own class; two such materials (a chemistry term in serum
beside a urinalysis term in urine) leave the Systems apart. The material
the panel records that name the row agree on comes first, as before.
The default must be among the siblings; otherwise the Systems stay apart
for review. The filing is recorded in stages.policy_defaults as {axis:
"system", choice, code, class}. An
analyte the practice approved somewhere keeps the practice rule above (one
material decides, two stay apart). The mapped row carries
review_flags: ["specimen_unprinted"]: the code is the practice's reading,
the material was never printed. PEP, SPEP, UPEP and protein
electrophoresis are reviewed surfaces of the electrophoresis method
(axis_context_aliases.json 2026.10.05.1), so Albumin (PEP) keeps the
electrophoresis term over the plain albumin; a clue that would leave the
name only single-character words is released (C-Pep is C-peptide, not an
electrophoresis of C).
The same reading for a row that prints no unit at all (2026-10-08, Dr
Tro's confirmed answers, practice_policy version 2026.10.08.1). The
Property siblings of an analyte the practice never approved in any Property
for that material join under the practice's property default
(property_default: MCnc; MeaningGrouper._default_property_keys): a
unit-less urine creatinine reads as the mass concentration, not the molar
one. A unit that is printed but incomplete is not "no unit at all" and the
siblings stay apart as before. In the urine microscopy family (System urine
or urine sediment, a microscopy Method — read from LOINC's axes,
meaning.microscopy_method) a bare number reads as the count per field and
a degree word (FEW, MODERATE; value_policy.ordinal_answers) as the
presence term (scale_default.urine_microscopy): the presence twin folds
into the count on a number, the count into the presence term on a word; a
type name (CALCIUM OXALATE) is no degree word and keeps the type term
apart, and an approval of the row's own surface files before any of this.
For the Property, an approval of the analyte in any Property for that
material keeps the practice's own rule (_practice_property_keys), which
since the same day counts only the approved Properties among the survivors:
the timed urine creatinine the practice approved beside the random one is no
sibling of a point-in-time row, so the random row reads as the approved mass
concentration. A microscopy result with no specimen and no trusted heading
reads in the practice's microscopy material (method:microscopy beside the
per-class defaults in Mapper._practice_class_defaults: the material most of
the practice's approved microscopy terms are in, urine) even where the panel
records that name the row disagree (the CBC's blood count is not what a
degree word reports); urine and urine sediment are one material and the
microscopic examination is the method the group prefers, as on a field unit;
the row is flagged specimen_unprinted like any default material, and a
printed other material (stool, sputum) keeps its own terms. Each filing is
recorded in stages.policy_defaults ({axis: "property", choice} — the
default's Property, or practice_property with the approved one —
{axis: "scale", choice: count_per_field | presence}) and a row read by a
Property rule or the count reading files with review_flags:
["unit_missing"] instead of waiting for a unit: the decision is the
practice's, the unit was never printed. Two readings of the value's shape
go with it, grammar from LOINC's Property and Scale axes: on a degree word a
morphology term (Erythrocyte [Morphology], Morph) reads as presence the
way a type does and ranks after the presence term; on a bare number the word
siblings of an analyte — an interpretation, a type, a morphology (a nominal
Scale) — join its one quantitative group as alternatives
(MeaningGrouper._fold_word_terms), so Creatinine [Interpretation] in
Urine no longer holds the margin against the mass concentration a unit-less
Creatinine, Urine prints a number for, and the test strip's
semi-quantitative twin folds into the quantitative term on a bare number as
it does beside a unit (Dr Tro's U4: the plain term, never the strip or
detection-limit variant) — unless the row's trusted panel names the strip
term as its member, as the urinalysis record names the test-strip specific
gravity (2026-09-29): the practice's record decides. A presence term keeps
its own group on a number, as decided on 2026-09-25: index-reported presence
tests print bare numbers; on a degree word the urine strip's
semi-quantitative count reads as presence with the microscopy count and
ranks after the microscopy presence term. One guard closes the material
question (Mapper._open_material_outcome): a microscopy result with no
material printed whose leader is a microscopic examination in another
material reviews naming it — WBC MODERATE with nothing else printed had
filed the stool leukocytes once the blood morphology terms stopped holding
the margin, because the urine term was not among the candidates and nothing
may stand in for the default. A serology row printing Negative is a
degree word too; its serum term is no microscopic examination and is its
own answer, with its class default as before.
A challenge state the row does not print (C peptide^post CFst, the
fasting C-peptide) extends its analyte the way a dotted qualifier does and
joins the general term's group; a timed challenge (Glucose^2H post dose
glucose) carries a number the row would have printed and stays its own
analyte (2026-09-25). C-Pep had abstained 0.072 from its fasting sibling.
A trailing word after the analyte, which LOINC then names in the singular
(Erythrocyte clumps, Erythrocyte casts, Leukocyte clumps over
Erythrocytes / Leukocytes), is an unprinted qualifier in the same way
(2026-10-02, meaning._trailing_qualifier): when the row prints neither
the word nor a name only the narrower term carries, that term joins the
count's meaning group and ranks after it. A urinalysis RBC printed
/HPF under a heading that also prints Urine had tied the count
13945-1 with the clumps term 58449-0 by 0.026; a row printing RBC
Clumps, or LE for leukocyte esterase, keeps the narrower term apart.
A A+B+C compound of named analytes that adds analytes the row does not
print (Basophils+Eosinophils+Monocytes/Leukocytes against Mono % (Auto))
is an unprinted extension of the single analyte's term, and a dotted
Property (NFr.DF, a pure number fraction) is a unit convention on its
family (NFr), so both join the general term's meaning group and rank after
it: the general term, then the practice's approved code, then the undotted
Property, then common rank (2026-09-25; meaning._compound_qualifier,
_property_root). A numbered pair (HIV 1+2 Ab) is never split, and a row
that prints the compound's analytes (Baso+Eos+Mono %) keeps the compound
apart. Mono % (Auto) had tied three ways at 0.900.
The row must name what is filed
Embedding similarity can rank a term whose names share nothing with the row:
Baso (Absolute) scored the basil IgE term above the basophil count the row
abbreviates. A leader the row's own words do not name is therefore never
filed while a candidate the row does name survives; the row abstains with
unnamed_top_candidate, naming that candidate (grounding.row_names_term).
A row names a term when one of its words (not an axis word of the term) is
one of the term's analyte words, from its Component, long-name head,
consumer, short and related names, or abbreviates one (Baso ->
basophil), or is a near spelling of a long one. Only the row abbreviates:
the basil term's Abs (antibodies) never names a row printing Absolute.
An abbreviation is the start of a word at least two letters longer
(2026-10-05): the start of a token one letter longer is another token
(rpr inside the peach allergen's rPru p, TSH inside TSHR), and a
compacted related phrase matches whole, never by its start. A test printed
by its method (RPR, VDRL, FTA-ABS) names the terms that carry that
Method (grounding._names_and_axis): when every row word left after the
term's other axis words is a word of the Method, the Method's words are
names, not axis words. RPR NONREACTIVE had reviewed on three
peach-allergen terms it "named" by that substring while the reagin terms
it meant were named by nothing. A one-letter token followed by a word the
term explains is the initial of a name word (M. genitalium for
Mycoplasma genitalium; a trailing D against a B12 term stays
unexplained). OCR confusions (I/l/1, O/0, rn/m) are folded and related
names also count compacted (Hgb A1c = HgbA1c). A row of two letters or
fewer carries no lexical signal. Approvals and reviewed registry hits are exempt, and a
leader with no named competitor is unaffected, because some abbreviations
appear in no LOINC name (RDW, MPV, ANC): measured on the practice's
743 approved surfaces, 14 would not ground, all such abbreviations.
A group winner whose names explain strictly more of the row's words than the
leader's do takes the lead (Mapper._coverage_order,
grounding.row_word_coverage, 2026-09-25). Between different component
roots the margin is retrieval noise: Direct Bilirubin ranked total
bilirubin (its names explain bilirubin) over Bilirubin.direct
(bilirubin and direct); INSULIN RESISTANCE SCORE ranked the contained
Insulin approval over the score term; Babesia duncani WA1 IgG ranked
isotype-less antibody terms over the IgG term. Coverage is the row's content
words explained by the term's analyte names, matched as row_names_term
matches them; a term's axis words never count, nor do the spans of the row's
kept axis clues (a method or specimen word is not an analyte word). The new
leader keeps its own score, so an unexplained margin still reviews; the
winners it strictly covers become alternatives and leave the margin; a
reviewed registry leader is never displaced (the clinician named the code);
equal coverage is untouched. stages.coverage_dominance records leader,
displaced and each winner's coverage.
Outcomes and diagnostics
The confidence policy can return:
mapped: a safe candidate passed confidence and margin gates.abstain: evidence is ambiguous, incomplete, or needs correction.invalid_candidate: candidates existed but every one had a hard safety conflict.no_candidate: no usable candidate was generated.force_mapped: a separately governed, exact-lossless operational exception.
Every result includes bounded diagnostics,
provenance.stages.candidate_decision_trace, and a single
provenance.stages.primary_outcome. The main project should show the primary
outcome first, then candidate diagnostics, so an unrelated rejected sibling is
not presented as the reason a routine row abstained.
A blocked approved code stays the outcome
When a clinician-approved entry matched the row's own surface (registry
authority with exact_for_row) but its candidate did not survive validation,
the approved code is the outcome, not the noise that survived. The row
abstains even when an unrelated survivor clears both thresholds, reasons
names the rejection (the clinician-approved code 27353-2 was rejected:
registry required_specimen needs an explicit analytical specimen), and
primary_outcome is built from the blocked candidate:
missing_required_clinical_factwhen a registry constraint failed (specimen, method, class, property, panel): the report lacks a fact the approval requires.Estimated Average Glucoseapproved forBldon a row that states no specimen abstains on27353-2instead of ranking an ethyl glucuronide term. The constraint decides whether the entry applies, never whether the code exists (2026-09-25): an entry the row's context does not satisfy is inapplicable, its authority, match and constraints leave the candidate, and the code goes on with the score its retrieval layers gave it (registry_entry_out_of_scopein its evidence) or leaves when nothing else proposed it (trace outcomeinapplicable). Before, the gate hard-rejected the code: a bareIron Saturationrow, which only contains the% SATURATIONalias approved under the iron heading, lost 2502-3 and filed the molar twin 14801-5 at 0.998; it now ties the two fractions and reviews.approved_candidate_rejectedwhen the validator rejected the approved code for any other reason (an OCR-damaged unit such asm/min/1.73m2onEGFR). The candidate-level diagnostic (unit_dimension_mismatch) is kept beside it so the main project's unit repair can still act, andcandidate_displaycarriescode - long common namefor the review page.
primary_outcome.candidate_code may therefore name a code that is absent
from candidates. When nothing survived, the status stays
invalid_candidate/abstain as the policy decided, with the same primary
outcome.
An approval is only blocked when it applies to the row. When the approved
code's System contradicts a printed fact, the approval was made for another
context and blocks nothing: a printed analytical specimen or collection
source (GLUCOSE approved for serum on a urine row of a urinalysis panel),
a trusted panel's default specimen, or the entry's own required_specimen
against a printed specimen. Such an approval is recorded in
stages.inapplicable_approved_candidates and its registry_evidence item
carries applicable: false with not_applicable_reason, so a consumer does
not route it to a unit repair; the row's survivors are ranked as usual.
The rule does not depend on which gate rejected the code first: the
validator stops at the first gate that rejects, and the specimen gate comes
after the unit gate, so the mapper asks the specimen gate on its own
(safety.material_conflict, the validator's own specimen logic) for every
rejected approval of the row's surface (2026-10-02). A urinalysis RBC
printed /HPF with Urine on the row, in its section heading or as the
collection source does not stay blocked on the blood count's unit. A
report-level phrase stays soft evidence and keeps the block. A missing fact
(no specimen where Bld is required, no heading where a panel is required)
or a unit rejection with no contradicting material still blocks, with one
exception (2026-10-07, Mapper._made_for_another_row): a count per
microscopy field (/HPF, /LPF) refused against a code whose units are per
volume is another kind of result, not a convertible unit, so the approval is
inapplicable whatever the heading or the specimen printed; a unit of the
code's own dimension (mmol/L for mg/dL) still blocks and names it. A contained or compact-form registry hit is not an approval of the
row's surface and never triggers the rule, and a code approved under two
entries that are both exact for the row (mg/dL universally, mmol/L for
one laboratory) is validated against the union of their units before it can
be called blocked; a contained entry neither adds nor relaxes a unit, so the
full pipeline and the registry fast path stay equivalent. If any
clinician-authority candidate survives, nothing changes.
Force-exact exception
force_mapped is intentionally separate from a clinician-approved mapping.
It is allowed only for a verified active Observation/Both LOINC target and
an exact lossless label match. It bypasses unit and six-axis checks by explicit
policy, is auditable in provenance, is excluded from ordinary accuracy metrics,
and is blocked from Elation by default. It must be created only through the
restricted server-side publication action, never a general staff/clinician UI.
An override may additionally be source-scoped only when a documented assay requires it. A source-scoped exact override must match the incoming source laboratory or source test identifier; it never prevents the source-neutral mapping path from running for another laboratory. The OCR-recovery bootstrap contains three Labcorp-specific examples and otherwise uses source-neutral canonical identities. See OCR recovery contract.