Skip to content

fix(district): stop attributing docket uploads to a stale cached case id - #428

Merged
ERosendo merged 5 commits into
freelawproject:mainfrom
playfulart:fix-docket-upload-case-id-misattribution
Aug 4, 2026
Merged

fix(district): stop attributing docket uploads to a stale cached case id#428
ERosendo merged 5 commits into
freelawproject:mainfrom
playfulart:fix-docket-upload-case-id-misattribution

Conversation

@playfulart

@playfulart playfulart commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

What this fixes

When a district docket report page yields no case id from its own context (URL, inputs, referrer), handleDocketDisplayPage falls back to the per-tab cached case id and uploads the entire page HTML under it. That cached value can belong to a different case viewed earlier in the same tab — nothing invalidates it on navigation — so one case's full docket sheet gets uploaded under another case's pacer_case_id, and the archive faithfully merges one case's entire history (entries and parties) into the other's docket.

Real-world occurrence

This happened to a pro se litigant's case in D. Nev.: the complete docket of Empire Trust v. Cellura (nvd 3:25-cv-00553, pacer_case_id 177277) was uploaded under Mitchell v. Tate's id (nvd 2:26-cv-00720, pacer_case_id 180126). CourtListener docket 72456248 now contains ~165 entries byte-identical (same entry numbers, dates, text, and pacer_doc_ids) to entries on docket 71566874, including the foreign case's SDNY pre-transfer history and two of its parties. Both CL docket records carry correct, distinct pacer_case_ids, so the wrong id had to be attached client-side at upload time. A data-repair request for that docket was sent separately via the CourtListener contact form.

The fix

Before reaching for the cached id, derive the case id from the page itself: a district docket sheet carries its own case id in every document link's goDLS() onclick handler. New helper PACER.getCaseIdFromDocketDisplayLinks() tallies those ids, and the fallback path in handleDocketDisplayPage now prefers that evidence over the tab cache:

  • The plurality (most common) id wins, so a stray link to another case's document — legitimate on consolidated/MDL sheets (the existing comment in findAndStorePacerDocIds notes this corner case) — cannot outvote the sheet itself.
  • A tie counts as no evidence — the cached-id fallback applies as before rather than guessing.
  • An id the page context already provided is never overridden. On consolidated member dockets the document links legitimately point at the lead case, so the goDLS plurality is only trusted when there is no context id at all. This keeps the change strictly scoped to the previously-unprotected fallback path — behavior on every other path is byte-for-byte unchanged.
  • When the page id beats a conflicting cached id, a console warning says so, and the cached id is corrected, seeding the right id for a later docket-report load in the same tab.
  • Pages with no goDLS evidence behave exactly as before (some courts don't emit goDLS).

Tests

Five new specs in ContentDelegateSpec.js:

  • stale tab-cached id + page links assert another id → upload uses the page's id, nothing is sent under the stale id, and the cached id is corrected in storage;
  • consolidated member docket shape: context-derived id present + goDLS plurality pointing at the lead case → context id wins (never overridden);
  • consolidated plurality: three links to the lead case + one stray member-case link → most common id used;
  • tied ids → no guessing, cached-id fallback preserved;
  • fresh tab with no storage record at all → no throw, no upload (regression for the missing-record guard caught in review).

Full suite: 188/188 passing (183 pre-existing + 5 new). CHANGES.md updated under Upcoming → Fixes.

Review round 1 (@ERosendo)

All four suggestions adopted, one commit each: the sort-based rewrite of getCaseIdFromDocketDisplayLinks, the plurality (not strict-majority) doc wording, the corrected comment on what the tab-storage write feeds (a later docket-report load — attachment menus resolve via docsToCases, verified), and the || {} guard on getItemsFromStorage with the regression spec above.

@CLAassistant

CLAassistant commented Jul 21, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@playfulart
playfulart force-pushed the fix-docket-upload-case-id-misattribution branch 4 times, most recently from d45fdb8 to ba60de0 Compare July 21, 2026 23:27
@playfulart playfulart changed the title fix(district): attribute docket uploads by the page's own goDLS case id fix(district): stop attributing docket uploads to a stale cached case id Jul 21, 2026
@playfulart
playfulart marked this pull request as ready for review July 21, 2026 23:27
@mlissner
mlissner requested a review from ERosendo July 21, 2026 23:36
@mlissner mlissner moved this to To Do in Sprint (Web Team) Jul 21, 2026
The docket report upload fell back to the per-tab cached pacer_case_id
when the page context (url, inputs, referrer) yielded none. That cached
id can belong to a different case viewed earlier in the same tab, and a
docket sheet uploaded under another case's id merges one case's entire
history into the other's archive docket. Observed in the wild: all ~165
entries of nvd 3:25-cv-00553 were merged into nvd 2:26-cv-00720
(CourtListener docket 72456248), including the other case's parties.

Before reaching for the cached id, derive the case id from the page
itself: a district docket sheet carries its own case id in every
document link's goDLS() onclick handler. Use the strict majority of
those ids, so a stray link to another case's document (legitimate on
consolidated/MDL sheets) cannot outvote the sheet, and treat a tie as
no evidence. When the page id beats a conflicting cached id, warn on
the console and correct the cached id so later caseless pages in the
tab (e.g. attachment menus) inherit the right one.

An id the page context already provided is never overridden: on
consolidated member dockets the document links legitimately point at
the lead case, so the goDLS majority only speaks when nothing else
does. Pages with no goDLS evidence behave exactly as before.
@playfulart
playfulart force-pushed the fix-docket-upload-case-id-misattribution branch from ba60de0 to 34b7fc6 Compare July 21, 2026 23:42
@ERosendo ERosendo moved this from To Do to In progress in Sprint (Web Team) Jul 30, 2026
Comment thread src/pacer.js
Comment thread src/pacer.js Outdated
Comment thread src/content_delegate.js Outdated
Comment thread src/content_delegate.js Outdated

@ERosendo ERosendo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting this together! it's a nice improvement, and it should address the stale cache issue from freelawproject/courtlistener#5247.

I left a few small suggestions, mostly around hardening and documentation, but I think the overall approach looks great.

@ERosendo ERosendo moved this from In progress to In review in Sprint (Web Team) Jul 31, 2026
playfulart and others added 4 commits July 31, 2026 09:40
Adopt the reviewer-suggested shape for getCaseIdFromDocketDisplayLinks:
count links per case id, sort the counts descending, then compare the
top two counts to detect a tie. Behavior is unchanged (single candidate
returns it, tie for first returns undefined, no evidence returns
undefined) - the single-pass tally-with-tie-flag just took more effort
to follow than the problem deserved.

Addresses review: freelawproject#428 (comment)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The doc comment claimed a strict majority, but the code returns the
most common case id - {A: 3, B: 2, C: 2} returns A with 3 of 7 links.
Use the reviewer's wording, and align the one other comment that said
majority. Comments only, no behavior change.

Addresses review: freelawproject#428 (comment)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The comment credited the write with helping attachment menus, but
attachment menus resolve their case id through the docsToCases map
(getPacerCaseIdFromPacerDocId), not the tab's cached caseId. What the
write really does is seed the correct id for a later docket-report
load in the same tab. Comment only, no behavior change.

Addresses review: freelawproject#428 (comment)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
getItemsFromStorage returns undefined for a fresh tab, so navigating
directly to a docket report in a new tab would throw on
tabStorage.caseId. Default to {} like the guarded reads elsewhere
(utils.js). The same unguarded read predates this branch, but this is
the right place to fix it.

Addresses review: freelawproject#428 (comment)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@playfulart

Copy link
Copy Markdown
Contributor Author

@ERosendo Thanks for the review! All four suggestions are in, one commit each: your rewrite of getCaseIdFromDocketDisplayLinks verbatim (121ecfa), the plurality wording (29e4871), the corrected tab-storage comment (8e8be8f), and the || {} guard plus a regression spec for the fresh-tab path (9d02f4d). Suite is 188/188 locally. Ready for another look — CI just needs a maintainer to approve the workflow runs.

@playfulart
playfulart requested a review from ERosendo July 31, 2026 16:57
@MargoSchlanger

Copy link
Copy Markdown

Another one of these: https://www.courtlistener.com/docket/63890699/american-civil-liberties-union-v-united-states-immigration-and-customs/
It combines the dockets for ACLU v. ICE, 3:18-cv-01200 (N.D. Cal.) (this is the one that should be there) and some other case against "GPL Servicing, Ltd.".

@mlissner

mlissner commented Aug 4, 2026

Copy link
Copy Markdown
Member

Thanks Margo. Can you please take a look, Eduardo?

@ERosendo
ERosendo merged commit 215316b into freelawproject:main Aug 4, 2026
7 of 8 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in Sprint (Web Team) Aug 4, 2026
@albertisfu

Copy link
Copy Markdown
Contributor

Thanks @MargoSchlanger! The reported case has been cleaned up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

6 participants