Skip to content

Extracting Parties and Fault Determination From a Police Report

9 min read · updated August 11, 2026

A crash report contains statements about who caused a collision, and they are not all the same kind of statement. Conflating them produces a database that says an officer found a driver at fault when the report says nothing of the sort, and that is a liability problem rather than a data quality problem.

Three things that all look like fault

Read almost any crash report and you will find three distinct things that an extractor can mistake for a fault determination.

  • A coded field the officer completed. Most state forms carry a per-unit element for contributing circumstances or driver actions, chosen from a fixed code list. This is the officer recording a finding, and it is the closest thing on the page to a determination — though in many jurisdictions it is explicitly statistical and not an assignment of legal liability.
  • A narrative summary of what each driver said. “Driver 1 stated that Driver 2 entered the intersection against a red signal” is a report of an assertion. The officer has vouched for the fact that the statement was made, and for nothing else.
  • An enforcement action. A citation issued to one driver is a charge, not a finding, and a report can show a citation with no contributing-circumstance code, or a code with no citation.

There is a fourth thing that is not fault at all and is misread as fault constantly: unit numbering. Unit 1 and Unit 2 are a listing order, generally the order in which the officer worked the scene. Nothing about the number implies causation, and no schema should let “unit_1” leak into a field named anything like primary_party.

The coded fields, and what they actually mean

State crash forms are not uniform, but most are aligned to some revision of the Model Minimum Uniform Crash Criteria, a voluntary data standard published by the National Highway Traffic Safety Administration with the Governors Highway Safety Association. It defines a common set of crash, vehicle, person and roadway elements with attribute lists, which is why a form from one state is recognisable in another even when the box numbers differ. NHTSA publishes the criteria and its revisions at nhtsa.gov/mmucc.

Two consequences follow for extraction. First, the code list is versioned: an attribute value is only interpretable against the form revision and the state, so store the state, the form identifier and the printed revision alongside every code. Second, the elements are about circumstances, not blame. A value recording that a driver was following too closely is an observation the officer coded; it is not the sentence “this driver is liable”, and several states print a disclaimer on the form saying as much.

Crash report forms and their code lists are revised on state timetables and MMUCC itself is reissued periodically. Any mapping table you build from attribute codes to meanings should be dated and scoped to a state and form revision, and revisited rather than assumed.

A schema with no at_fault field

The design that survives review is one where nothing in the party record asserts fault. Parties hold identity and role. Assertions live in their own collection, each one carrying who made it, where it appears, and its exact words.

{
  "parties": [
    {"party_id": "u1", "role": "driver", "unit": 1, "listing_order": 1}
  ],
  "claims": [
    {
      "claim_id": "c1",
      "text": "failed to yield right of way",
      "source": "officer_coded_field",
      "field": "CONTRIBUTING CIRCUMSTANCE - UNIT 1",
      "code": "<verbatim code as printed>",
      "about_party": "u1",
      "verbatim": "<exact span from the document>",
      "page": 2
    },
    {
      "claim_id": "c2",
      "text": "Unit 2 entered on a red signal",
      "source": "driver_statement",
      "asserted_by": "u1",
      "about_party": "u2",
      "verbatim": "<exact span from the document>",
      "page": 3
    }
  ]
}

The source enumeration is the load-bearing part, and it should be small and closed: officer coded field, officer narrative, driver statement, passenger statement, witness statement, citation issued. Anything the model cannot place into one of those is not extracted. Constraining an enumeration is one of the few places structured output genuinely helps here — see structured output support and testing enum constraint compliance for how far a schema can actually hold a model to a value set.

Store the verbatim span for every claim. It is what a reviewer opens when the extraction is challenged — the mechanics of putting it in front of them are review queue source highlighting — and it is the difference between a record that can be audited and one that has to be trusted. The general case for keeping spans and an audit trail is made in audit log schema and extraction field audit trail; on this document it is not optional.

Why the obvious prompt produces the wrong answer

Ask a model “who was at fault?” over a report whose narrative contains only two contradictory driver accounts, and it will answer with a party. It is doing what it was asked: the question presupposes an answer exists in the document, and a language model asked a presupposing question supplies the presupposition. Nothing about temperature, confidence scoring or a larger model fixes this, because the extraction is not uncertain — it is a well-formed answer to the wrong question.

The fix is at the prompt level and it is to stop asking. Ask for every statement in the document that attributes an action or a cause to a party, with its source and its span, and let the absence of a coded determination be visible as an absence. A report with no contributing-circumstance code and two conflicting accounts should come out as two claims of source driver_statement and no claim of source officer_coded_field, which is an accurate description of the document.

Two more cases that break naive extraction: a hit-and-run, where one unit has no identified driver and the party record must permit an unidentified party rather than dropping the unit; and a report where the officer explicitly records that fault was not determined, which is a coded finding of its own and is not the same as the field being blank.

Handling obligations that come with the document

Write this pipeline for an organisation that already holds the reports lawfully — an insurer, a fleet operator, a municipality. Two obligations attach regardless of which of those you are.

The first is minimisation before the document leaves your infrastructure. A crash report carries licence numbers, dates of birth, addresses, insurance policy numbers and sometimes injury detail, and most of that is irrelevant to a fault-claim extraction. Redacting before the page reaches a third-party model reduces both the contractual surface and the blast radius of a logging mistake; the mechanics are in PII redaction and PII in LLM logs. Where the document must go out intact, the processing agreement with the provider is the thing that makes that lawful, and it is worth knowing whether your traffic is retained.

The second is that a fault claim extracted from a report will be used in a decision about a person. Keep a human in the loop on anything adverse, keep the span, and keep the model version that produced the record — an extraction model version audit trail is the piece that survives a provider silently changing the model underneath you. That is not a compliance flourish; it is what makes the record defensible when someone disputes it a year later.