Extract abbreviations from incident notes, review collisions and expose expansions without changing what the original note said.
Project: ship an incident glossary with scoped expansions
Set the reader-facing contract
The incident viewer may display a proposed long form beside a short form, with its source and confidence state. It must preserve the original characters and document revision. A reader can inspect the local definition, registry entry or unresolved candidates. The viewer never silently rewrites an incident note. Start with RA in shipping and risk documents, then add an unqualified RA occurrence that must remain unresolved. The scope rules decide what evidence is admissible.
Build the review set
Collect notes with local parenthetical definitions, definitions several paragraphs away, conflicting sections, copied quotations and unknown forms. Group every revision of one incident in the same evaluation split. Annotate the short form, long form if present, section and correct reader action. Include notes where the acronym letters do not align with any nearby phrase. A clean, independent holdout prevents a repeated template from making extraction look more reliable than it is.
Stage extraction and migration
Extract candidates, apply section scope, and fall back to the approved registry only when domain evidence is present. Keep unresolved cases visible for review. When a new registry version arrives, mark dependent expansions and index rows stale. Reprocess only affected documents, compare their previous and new display decisions, and have an owner approve changed meanings. Registry versioning keeps the old interpretation recoverable.
Measure the release
Report correct display rate, wrong expansion rate, unresolved rate, reviewer minutes and search-result changes by domain. Inspect every high-impact collision rather than averaging it into easy single-meaning forms. Shadow the new glossary on recent incidents, then release with the prior registry and index ready for rollback. Access control on the incident note must also protect its expansion and any cached search snippet.
Implementation
def display_expansion(local_candidates, registry_candidates):
local = {item["expansion"] for item in local_candidates}
if len(local) == 1:
return {"state": "local", "expansion": next(iter(local))}
if len(local) > 1:
return {"state": "review", "reason": "local-collision"}
approved = {item["expansion"] for item in registry_candidates}
if len(approved) == 1:
return {"state": "registry", "expansion": next(iter(approved))}
return {"state": "unresolved"}
assert display_expansion([{"expansion": "Return Authorization"}], []) == {
"state": "local", "expansion": "Return Authorization"}
assert display_expansion([], [{"expansion": "Return Authorization"},
{"expansion": "Risk Assessment"}])["state"] == "unresolved"
Performance and operating cost
Building the distinct expansion sets takes O(l + r) time and space for l local and r registry candidates. The function does not decide whether candidates were extracted correctly; reviewer quality and source scope remain upstream gates. A wrong expansion in a published incident can cost more than an unresolved label, so measure that error explicitly.
Common Mistakes
- Displaying a registry default despite conflicting local definitions.
- Removing an unknown short form from the reader view.
- Mixing revisions of one incident across train and test.
- Exposing an expansion from a restricted note in a public search snippet.
