A local test name is one string. A LOINC code is a six-axis claim about component, property, time, system, scale, and method. Axis maps a pasted lab catalog to that structure and refuses to guess where it matters: a CSF glucose is never the serum glucose code, and a mass fraction is never a substance fraction.
Twelve synthetic local rows against six LOINC axes. Every result below is computed in this request by token overlap and three hard vetoes — no model, no fuzzy score winning over a rule.
Every hard mapping error in a lab catalog is one axis quietly assumed. Axis makes the assumption explicit and lets a veto stop the candidate.
A confident mapping, a candidate that must be looked at by a human, and an honest miss. There is no fourth state where the tool silently picks the closest string.
Component, property, time, system, scale, method. A code is only accepted when its axes survive the row's specimen, unit dimension, and result type.
A candidate with the best lexical score can still be rejected by specimen, dimension, or qualitative/quantitative mismatch — and the reason is shown.
No LLM and no network call. The same CSV produces the same rows, in the same order, with the same reasons.
CSV header is validated. Names, specimens, and units are lowercased, punctuation-stripped, and German/Italian synonyms are folded to English.
Token overlap against each LOINC long name, component, and curated synonyms. The top three are kept, viable or vetoed.
Specimen class, UCUM dimension, and result type. A vetoed candidate can never win, even with the highest lexical score.
Accept only with a clean winner, enough evidence, and a margin. A vetoed favourite downgrades the row to review. No candidate means no_match.
The demo uses this endpoint. Row limit is 200; the sample catalog is served as text/csv.
# map a CSV file as a JSON string CSV=$(python3 -c 'import json;print(json.dumps(open("catalog.csv").read()))') curl -s -X POST http://localhost:4100/api/map \ -H 'content-type: application/json' \ -d "{\"csv\": $CSV}" # or send the raw CSV body curl -s -X POST http://localhost:4100/api/map \ -H 'content-type: text/csv' \ --data-binary @catalog.csv
{
"rows": [{
"local_code": "GLU-CSF",
"status": "accept",
"code": "2344-0",
"axes": { "component": "Glucose", "property": "MCnc",
"time": "Pt", "system": "CSF", "scale": "Qn",
"method": "—" },
"confidence": 0.92,
"reasons": [{ "rule": "accepted", ... }],
"candidates": [ /* top 3, with vetoes */ ]
}],
"summary": { "accept": 10, "review": 1, "no_match": 1 }
}
Twenty-seven entries cover common chemistry and hematology. Real LOINC has ~100k codes and long-tail method variants; this is a demonstration of the decision layer, not a licensed terminology service.
Synonyms are hand-curated. A local name that shares no token with the catalog returns no_match rather than a plausible guess — which is the honest failure, but still a failure.
Duplicate local codes, composite panels, free-text units, and locale-specific abbreviations will produce more review rows. The tool is built to surface those, not to erase them.
Lab mapping is usually a quality/compliance purchase signed off by a lab director, not an engineering tool budget. A working demo shortens the conversation; it does not create the line item.
Axes and codes are illustrative. Any production use needs review by a qualified laboratory professional and the current LOINC release.
Rows are mapped in memory and discarded. There is no catalog storage, audit trail, or PHI handling in this build.