Cascadia Portfolio · Matter Ledger

Can this number be trusted?

A governed model of the public federal civil docket — 10,960,173 case records — and what happens to one ordinary legal-operations question when the governance is missing.

The question

How long does it take to resolve a contract dispute in federal court?

It is a question a legal-operations team gets asked, and the data to answer it is public. Below, it is answered twice from the same file, retrieved once, on the same day. Neither query contains a mistake anyone would call obvious.

Against the raw file

-742.3 days

32,767 matters behind this figure have a negative duration. Nothing errors, nothing warns, and no null appears anywhere to hint that something is wrong.

Against the governed model

208.0 days

Median, over 1,370,419 closed contract matters. Every figure on this page is re-derived from the frozen source down a second, independently written path before it is published.

Why the two answers differ

Chart 1 data table
Chart 1 data — each rule's effect on the answer, in days
StepRule appliedEffect, daysRunning answer, days
1correct the encoding+0.0-742.3
2disable quoting-0.0-742.3
3quarantine field-shifted records+0.0-742.3
4exclude pending matters+1062.0319.8
5one record per matter (reopenings)-0.1319.6
6the subject-matter control-0.1319.5
7median, not mean-111.5208.0
One rule out of seven does nearly all of the work, and that is the honest reading of this chart. The other six move the answer by less than a day between them. They are drawn at true scale rather than dropped or rescaled, because their cost is not bounded by this particular question — the 638 records quarantined by one of them carry disposition codes that are fragments of dates, and they would corrupt a different measure instead.

The trap

Both versions of the trend agree. That is not reassurance — it is the reason this class of error survives review.

Chart 2 data table
Chart 2 data — median and mean days to termination by statistical year
Statistical yearUngoverned mean, daysGoverned median, days
2001285.1174.0
2002327.5223.0
2003340.4242.0
2004356.1250.0
2005331.5227.0
2006330.7219.0
2007317.1217.0
2008304.6218.0
2009311.4208.0
2010313.1223.0
2011310.6214.0
2012317.9221.0
2013330.9229.0
2014321.0217.0
2015337.3243.0
2016338.4231.0
2017330.2224.0
2018338.6222.0
2019336.1238.0
2020355.1243.0
2021353.7249.0
2022371.5267.0
2023357.0257.0
2024359.1268.0
2025362.0263.0
An analyst who sanity-checks the headline against the trend chart finds a plausible line going the right way, and ships the number. The same defect, in the same file, on the same day, is invisible in one cut of the data and catastrophic in another. Ungoverned answers are not reliably wrong — they are wrong inconsistently, and inconsistent wrongness is what defeats a review that relies on someone noticing.

And there is no obvious correct filter

Suppose the analyst does notice the pending records and reaches for the obvious fix — keep only the rows the source marks as terminated. That gives 332.0 days, and silently discards 637,118 records, 45.0% of the slice, because the status field did not exist before statistical year 2001. Both reasonable choices are wrong, in opposite directions. Only a closure rule that is effective-dated is right, and that rule is not derivable from the data — it comes from a sentence in the publisher's codebook.

What the governed layer actually is

Three things, each of which caught something. A written rule mapping a court docket onto a matter-shaped entity, stating what it loses. Conformed dimensions loaded from the published codebook rather than written as CASE WHEN blocks. And five certified measures, each with a definition, a named owner and source lineage.

Chart 3 data table
Chart 3 data — procedural progress at termination
Progress at terminationGroupMattersShareMedian days
other, after issued joinedafter issued joined254,52118.6%274
no court action, before issue joinedbefore issue joined245,28917.9%108
order entered, before issue joinedbefore issue joined244,64117.9%120
judgement on motion, after issued joinedafter issued joined188,83313.8%279
pretrial conference held, after issued joinedafter issued joined171,32612.5%388
no court action, after issued joinedafter issued joined134,0769.8%274
order decided, before issue joinedbefore issue joined92,3636.7%118
after court trial, after issued joinedafter issued joined13,1301.0%654
after jury trial, after issued joinedafter issued joined12,6630.9%641
hearing held, before issue joinedbefore issue joined6,8720.5%154
during jury trial, after issued joinedafter issued joined3,0510.2%581
during court trial, after issued joinedafter issued joined2,3020.2%495
request for trial de novo after, after issued joinedafter issued joined1,3520.1%372
Two of the procedural-progress codes read identically in the codebook's code list. Both say "no court action"; one means before the defendant's answer was filed, the other means after. The distinction lives in a heading above the list, not in the code descriptions — so a dimension built from code and description alone merges them, and a quarter of the slice lands under one meaningless label. The dimension here carries the group, and the chart reports the qualified form.

Chart 4 data table
Chart 4 data — days from filing to termination by nature of suit
Nature of suitClosed matters25th pctMedian75th pct
Contract Product Liability13,652113307636
Stockholder's Suits12,26698280636
Insurance376,683130265446
Overpayments under the Medicare Act5,032106255516
Miller Act23,176115238444
Other Contract Actions588,952103234462
Negotiable Instruments42,084108224438
Marine Contract Actions72,80993202399
Franchise6,41597200378
Overpayments & Enforcement of Judgments15,87264159363
Recovery of Defaulted Student Loans166,98568106178
Recovery of Overpayments of Vet Benefits46,4936198157
The same defect appears one field over, and this chart shows it rather than smoothing it. Two dispositions carry the description "other" in the codebook's code list — one is a dismissal, the other a judgment — and the dimension does not carry the group that separates them. The bars below are disambiguated by their code because the code is in the certified measure; carrying the group properly is a change to the data layer, and it is recorded as owed rather than made quietly from the visual layer.

Chart 5 data table
Chart 5 data — disposition mix
DispositionMattersShare
settled421,27730.7%
voluntarily224,45816.4%
default169,36712.4%
other142,39110.4%
motion before trial107,6327.9%
remanded to state court52,6373.8%
lack of jurisdiction46,7723.4%
consent46,7433.4%
statistical closing32,8512.4%
transfer to another district31,6602.3%
other30,6992.2%
want of prosecution27,1232.0%
jury verdict12,2000.9%
court trial11,4190.8%
multi district litigation transfer4,5850.3%
stayed pending bankruptcy3,1530.2%
award of arbitrator2,1710.2%
remanded to U.S. Agency1,8270.1%
directed verdict1,1870.1%
appeal affirmed (magistrate judge)1780.0%
appeal denied (magistrate judge)890.0%

How it stays right

The frozen model is validated once. The live edge is not: it runs on a schedule, takes a bounded increment from a second source, re-asserts the module's invariants on every run, and reconciles itself against the frozen baseline. The surface below is the module's own record of that, rendered from the machine-readable health file the pipeline writes — not restated by hand.

Live edge — last run

Run state
failed
Started
2026-08-29 02:23:08 UTC
Assertions checked / failed
7 / 1
Last successful run
2026-08-28 18:26:59 UTC
  rows added on that run
578 from 36 dockets
Last run that was not "ok"
2026-08-29 02:23:08 UTC — failed: the source returned a server error mid-walk — an upstream fault, not a refusal and not a rate limit
Runs to date / recorded in the log
9 / 2
Dockets on roster
320
Dockets fully ingested / partial
58 / 1
Docket entries derived
2,176
Frozen baseline, same slice
954 matters
Reconciliation variance
-634

What has gone wrong, how it was caught, and what changed

A surface that has only ever shown green has demonstrated nothing. This pipeline has caught four defects in itself, every one of them a silent failure — nothing errored, and each would have under-collected or mis-stated while reporting success. Each row below is checkable in the repository's history.

Defects the module found in its own pipeline
What was wrongHow it surfacedFixed in
The watermark advanced past dockets whose rows were never written — 36 dockets marked done, zero rows persisted The run's own record showed the watermark had moved while the output file did not exist5ef5234
A docket was called complete on the strength of its first page; 29 of the first 36 had more than one Row counts did not reconcile against the roster5ef5234
The request budget read the daily rate-limit window while the hourly window was already exhausted The run spent itself on 90-second backoffs for requests that could not succeed5ef5234
A tie-break in the matter-grain rule depended on row order, which a parallel query engine does not guarantee The independent re-derivation disagreed with the build by one record in 1,370,419317d827
A rate-limit stop is a stop, not a failure, and the record says which it was. When the source's binding window has no headroom the run exits in seconds and names the window that bound it. That is the pipeline working as designed. The run log keeps stops, skips and genuine failures apart rather than colouring them all red.

Coverage is not completeness. 50.9% of ingested docket entries carry no description text at all — the source holds what someone has purchased from PACER. The unclassified rate of 76.9% is therefore a declared health metric, not a defect, and nothing derived from this feed is certified until coverage itself is modelled.

The derivation rule earns its keep here too. 333 ingested entries contain the word "motion" somewhere; 89 of them are motions filed. A naive text match counts every order that rules on a motion and inflates the count by 274% — so the rule requires the keyword at the start of the entry, and says so in writing before any output was produced.

Disclosure

An independent portfolio project by Aaron Robbins. Built from the Federal Judicial Center's Integrated Database — public federal civil case records — frozen at 2026-08-26 and verified by SHA-256 on every build, plus a bounded live increment from CourtListener's RECAP archive. No client data and no proprietary data of any kind. Nothing here is legal advice, and nothing here is an assessment of any identified party's litigation exposure: the model is aggregate by construction and carries no party column.

Source, governance documents and build scripts: github.com/RobbinsAnalytics/cascadia-matter-ledger. Every figure on this page is computed at build time from a certified measure; the independent re-derivation that gates publication is src/validate_measures.py.

Frozen as of 2026-08-26 · health surface generated 2026-08-29 02:44:00 UTC