Skip to content

feat(live): provision petition documents into predict inputs (#474)#534

Merged
modelmirror merged 4 commits into
mainfrom
dev/474-document-provisioning
Jul 10, 2026
Merged

feat(live): provision petition documents into predict inputs (#474)#534
modelmirror merged 4 commits into
mainfrom
dev/474-document-provisioning

Conversation

@modelmirror

Copy link
Copy Markdown
Collaborator

Closes #474. The input-richness half of the live-sources design, on top of #472/#473.

Decisions the issue asked for

  • Extraction path: pypdf (pure-Python, one small dependency) over pdfplumber/Doctor — SCOTUS filings are born-digital under the 2017 e-filing mandate, and the real-site check extracts them cleanly; a scanned paper filing degrades to an empty-text row, never a crash.
  • What is provisioned vs linked: full extracted text per document, capped at live.document_text_cap (~40 dense pages, truncation flagged in the manifest) — petition + BIO fetched, questions presented derived from the petition's own QP section (Rule 14.1(a) fronts it). Document metadata (URL, kind, entry date, pages) rides in documents.json.
  • Which documents, when: petition + BIO fetched on the distribution transition — the same trigger that queues prediction (feat: conference detection and the live cert watchlist #473), i.e. the record-complete moment, and near filing time since the probe showed links are a rolling ~5-Term window. Idempotent per (kind, url): relists with unchanged filings cost nothing; a re-filed BIO supersedes (latest-wins storage).
  • Storage discipline: a new corpus documents table (DVC-backed, access-gated — never the git ledger, respecting no-republication). provision-snapshot materializes text + manifest into the cell's gitignored record/documents/, so every workflow already provisions documents with zero workflow changes and agents get the content with no fetch rights. A pre-documents remote blob reads as "no documents" on the ranged backend rather than failing the cell.

Found by fetching for real

  • QPLink leaks the outcome. The /qp/ page is generated when certiorari is granted and literally opens with "THE PETITION … IS GRANTED … CERT. GRANTED 5/1/2023" — which also explains the probe's 1/64 QPLink coverage (the one granted case). It is never fetched, and it joins the replay-redaction blocklist.
  • The real BIO caption needs a wide match: "Brief of respondents Gina Raimondo, Secretary of Commerce, et al. in opposition filed." (62 chars mid-caption); amicus "in opposition" briefs are excluded.

Verified

Real-site run on the Loper Bright docket: petition 49pp/74k chars, BIO 37pp/65k, derived QP 1.8k chars — none truncated — stored, then materialized via provision-snapshot. Prompt wiring: predict.md points agents at record/documents/ (anchor on the QP, weigh petition vs BIO, cite in reasoning.md); the cert-prompt-tuning follow-up the issue mentions stays separate.

Gate: ruff, mypy, pytest (812 passed, +15), export-schemas no drift. Out of scope, per the issue: circuit documents (RECAP Fetch/PACER).

🤖 Generated with Claude Code

Closes #474. The input-richness half of the live-sources design — the step
that moves cert predictions past base-rate calls.

- Pipeline-side fetch + extraction, never agent-side: the live poller fetches
  the petition and the brief in opposition on the same distribution transition
  that queues prediction (record-complete moment; near filing time, since
  document links are a rolling ~5-Term window upstream). Idempotent per
  (kind, url) — a relist with unchanged filings costs nothing; a re-filed BIO
  supersedes.
- Extraction: pypdf (born-digital filings under the e-filing mandate; a
  scanned paper filing degrades to empty text, never a crash), capped at
  live.document_text_cap (~40 dense pages) with truncation flagged.
- QPLink is an outcome artifact, never an input — verified live: the /qp/
  page is generated when certiorari is GRANTED and opens with the grant order
  (this also explains the probe's 1/64 QPLink coverage). The questions
  presented are derived from the petition PDF's own QP section instead, and
  QPLink joins the replay-redaction blocklist.
- Storage discipline: extracted text lands in the corpus's new documents
  table (DVC, access-gated) — never the git ledger. provision-snapshot
  materializes it into the cell's gitignored record/documents/ with a
  documents.json manifest (metadata only), so cells read identical content
  with no fetch rights; an older remote blob reads as "no documents" on the
  ranged backend.
- Prompt wiring: predict.md points agents at record/documents/ (anchor on the
  questions presented, weigh petition vs BIO, cite in reasoning.md), with the
  data-not-instructions guard extended to documents.

Verified against the live site on the real Loper Bright docket: petition
(49pp/74k chars), BIO (37pp/65k — the entry caption needed a 120-char window;
amicus briefs excluded), and the derived questions presented (1.8k chars),
none truncated, materialized through provision-snapshot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread tests/test_documents.py Fixed
modelmirror and others added 2 commits July 10, 2026 13:05
Resolves the CodeQL implicit-string-concatenation finding on #534: adjacent
bytes literals inside the _pdf helper's object list are the classic
missing-comma bug shape — a real miss there would silently merge two PDF
objects. The intended concatenation is now an explicit `+`.

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

Copy link
Copy Markdown
Collaborator Author

CodeQL's implicit-string-concatenation finding is fixed in 93eb4a1: the split PDF-object bytes literal in the _pdf test helper is now joined with an explicit + (in a list display, an accidental missing comma there would silently merge two PDF objects — the exact bug the query hunts). I swept the rest of the PR's files for the same shape; the only other occurrences in the repo are two pre-existing prose strings in ops.py on main, outside this PR's scope. Alert should auto-close on the next scan.

@modelmirror modelmirror merged commit 52b31a6 into main Jul 10, 2026
7 checks passed
@modelmirror modelmirror deleted the dev/474-document-provisioning branch July 10, 2026 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: provision petition documents into predict inputs

2 participants