The settlement-value skill walks a case end-to-end: injuries, activities, parties, events, ratings, TD payments, denial dates. It emits a structured INJURY: line that the attorney reads, the assistant consumes, and the downstream rating math depends on. The line looked correct in shape — every field populated — but one field was unusable.

INJURY: {"doi":"2024-08-15","body_part_codes":[21,22,26,27,25,54],...}

The attorney can quote DOI. The attorney can quote the carrier claim number. The attorney cannot quote [21,22,26,27,25,54] — and worse, cannot tell at a glance whether those six numbers are the right six body parts. The Application says the injury was to the left arm and inner ear (vestibular complaint). Are those six numbers consistent with that? Without a key, nobody can tell.

This is the same shape of bug as a metric you can't read. The data was being faithfully reported. The reporting was useless.

What the obvious fix was — and why it didn't exist

The obvious fix: call the body-parts catalog endpoint, look up each code, emit the label.

There is no catalog endpoint. /bodyParts/index returns the API's generic "insufficient privileges" error — which, in this API, is the undifferentiated response for endpoint does not exist, not a real authorization problem. /injuryTypes/index returns the same. The codes are write-shaped (they go into q1_injury_description_N_id on the injury record) but there is no read endpoint that returns the catalog they index into.

The structural data is in the system; the dictionary that makes it readable is not. Most APIs have this gap somewhere. This one happened to be on the field that drove a settlement-valuation line the attorney actually quotes.

Inferring the catalog from the data

The codes are not random. Every injury record in the system carries up to ten of them — q1_injury_description_1_id through _10_id — plus a free-text narrative field, q2_injury_occurrence, where the attorney typed what the injury was in plain English: "Applicant sustained injury to left forearm and left wrist while lifting boxes." The codes are formal; the narrative is descriptive. If a code consistently co-occurs with the word "wrist" in the narrative, that code is wrist.

This is the canonical setup for statistical lift. For each code c and each token t, compute:

lift(t | c) = P(t | record has code c) / P(t | any record)

If lift("wrist" | 25) is large — i.e., records carrying code 25 mention "wrist" far more often than the base rate — then 25 is the wrist code. The math is undergraduate; the discipline is in the data preparation.

Walked all 222 cases firm-wide. Pulled every injury record. Collected 234 (codes[], narrative) pairs. Computed lift on every (token, code) combination across the full vocabulary. The codes with high-lift single-token associations resolved immediately: 17→cervical, 25→wrist, 26→hand, 32→lumbar, 40→knee. The ambiguous ones — codes used in multi-body-part injuries where the narrative names three things — resolved with the next pass, grouping by code-co-occurrence patterns (the code that appears with 25 and 27 is probably "forearm").

58 distinct codes appeared in the firm's caseload. 58 labels recovered.

The cross-check that gave the labels a name

A statistical inference is not a fact. High-lift labels could be wrong in a way the rest of the math couldn't catch — coincidental co-occurrence in a small sample. So the inferred catalog was sanity-checked against the DWC Form 5020 standard, the form California employers use to report an injury. The form has a published body-part list; the codes the case-management system stores look structurally aligned with that list (same numeric range, same broad ordering — head/neck, upper extremity, trunk, lower extremity, body systems).

The empirical labels were consistent with what the standard taxonomy would predict for the high-frequency codes: 17 reads as cervical, 32 reads as lumbar, 40 reads as knee. That alignment is what the catalog notes when it calls the mapping "derived from DWC Form 5020 standard plus empirical correlation against 234 firm-wide injury records." The empirical work is what produced the labels; the published standard is what made them recognizable as the right labels.

Five codes (4, 9, 13, 36, 62) didn't appear in the firm's caseload at all. They sit in the gaps between observed codes (between Brain=2 and Ears=3, between Ribs=33 and Hip=34). The catalog labels them by inference from adjacent codes and flags them as not-yet-verified — when the first case carrying one of those codes appears, the inferred label should be checked against the actual case narrative before being trusted.

What the attorney sees now

The same skill, same case:

INJURY: {"doi":"2024-08-15",
         "body_parts":["L Elbow","L Forearm","L Hand","L Fingers/Thumb","L Wrist","Vestibular/Inner ear (dizziness)"],
         "body_part_codes":[21,22,26,27,25,54],
         ...}

The codes are still there, unchanged, for anything downstream that needs the structural data. The labels are alongside, with laterality prefixes (L/R/Bilateral) resolved from a separate code field that was already in the record but never being read. The attorney sees six body parts they can quote. The QME report can be compared against this line directly — "the QME treated right shoulder and the case carries left forearm; that's a mismatch worth investigating."

A code that isn't in the catalog (a new code, or an inferred one not yet verified) falls through as "code 35" rather than disappearing. The attorney still sees something they can act on; nothing silently drops.

Why this matters more than it sounds

A settlement-value line is one of the highest-stakes outputs the system produces. The attorney quotes it back to the client. The client makes settlement decisions on the basis of it. If the line says "six body parts" without naming them, the attorney has to walk to the case management UI, look up the codes manually, transcribe them, and quote those. That's the browser-detour pattern again — except this one isn't a statute lookup, it's the case's own facts in the same system the line came from.

It also matters because the codes feed the body-part-mismatch settlement gap check. If the QME treated a body part that's not in the Application, that's a $30K-$50K gap in PD value the attorney can recover by amending the Application before settlement. The mismatch check is more useful when both sides — what the Application says and what the QME treated — are in attorney-readable form.

What ships now and what's deliberate about it

The catalog lives at reference/knowledge/body-part-codes.json. It ships with the package, gets loaded by the settlement skill at runtime, and gets resolved against. If a firm uses a different injury-coding system, the catalog can be overridden by placing a copy at ~/.aaicase/body-part-codes.json — the skill checks the user-level override before the shipped fallback. The override survives package upgrades.

The catalog is display-only. The structural code is still the source of truth — the JSON output preserves body_part_codes next to body_parts so any downstream consumer (export, audit, rating math) still has the codes it needs. The label is for the attorney to read; the code is for the system to compute on. The two never substitute for each other.

Codes 4, 9, 13, 36, 62 are labeled by inference from neighboring codes but were not observed in the 234-record sample. When one shows up live, the inferred label gets verified against the actual case narrative. The catalog notes which codes are inferred versus empirically validated, so the discipline is documented in the data file itself.

The honest list of what this didn't fix

What was verified before this shipped

The catalog passes check-knowledge-base-freshness, which checks the extraction timestamp against the system clock and confirms the file is parseable with the expected schema. The settlement skill passes check-strip-fn-sync and check-no-inline-tag-strip — the existing entity-decoding discipline that keeps — em-dashes from leaking into the attorney's reading copy. The codes-to-labels resolution was tested on the case that first surfaced the bug; the line that previously read body_part_codes:[21,22,26,27,25,54] now reads body_parts:["L Elbow","L Forearm","L Hand","L Fingers/Thumb","L Wrist","Vestibular/Inner ear (dizziness)"]. The structural codes field is unchanged. Nothing downstream broke.

A skill output the attorney can't read is a skill output that doesn't ship. Six numbers isn't a settlement-value report. Six body parts with laterality is.