Skip to content

Latest commit

 

History

History
139 lines (124 loc) · 10.2 KB

File metadata and controls

139 lines (124 loc) · 10.2 KB

HANDOFF — 2026-07-08

Session focus: shipped two deterministic proofing passes, set the pre-1997 proofing strategy (the ~104-fleet question), ran + resolved the P59 A/B, applied P59, and started the segment-B Westlaw conversion. Read this top-to-bottom before resuming; the one-line state lives in memory project_ongoing_work.md (2026-07-08 section).

0. Status at a glance

  • Corpus 19,807; invariants 29 ok / 2 known / 0 regressed; quick_check ok; FTS 19,807/19,807; 162 tests; footnote 176/0.
  • EVERYTHING today is DB-APPLIED but UNCOMMITTED (git) and UNRELEASED. Last release = v1.2.2 (P53–P58). Owe: git commit + release build (regenerates opinions.db.zip) to make today's work live. Working tree is dirty (new scripts + docs + DB).
  • Backups made today: opinions.db.bak-{ellipsis,roman-headings,p59}-2026-07-08.
  • Fleet cursor: P59 DONE → next P60 (OFFSET 4990, after 2006 ND 210).

1. Two deterministic passes shipped (§ absorb recurring fleet manual load)

Built to stop the fleet re-discovering the same mechanical classes every 120-opinion window. Both dry-run by default, back up the DB, log one full-text changelog row per opinion (revertible).

  • scripts/normalize_ellipsis.py → batch normalize-ellipsis-modern-2026-07-08: 1,189 opinions / 3,991 spaced ellipses → compact (. . . .....). MODERN (≥1997) only, 3/4-dot runs only (pre-1953 uses spaced omission-lines; >4-dot excluded). Safe by construction (only interior whitespace removed). Residual modern 3/4-dot runs after apply: 0.
  • scripts/fix_roman_headings.py → batch fix-roman-headings-2026-07-08: 1,037 opinions / 1,072 OCR-garbled headings (IllIII 1008, rv/TV/IYIV, HIIII, YIVI). Triple guard: blank-flanked heading slot + DB's own roman sequence pins the value + PDF has the target as a bare-line numeral. All 64 non-Ill verified vs PDF, 0 false positives. 16 no-PDF cases skipped for manual.
  • DEFERRED (not built): [[Image here]] — 639 opinions, heterogeneous (dropped list-items needing PDF text restoration vs genuine figures). See TODO-image-reconstruction.md. NOT a blind pass. User priority: recover lost text, few real images.

2. Pre-1997 proofing strategy — THE BIG ONE (~12,590 opinions, ~104 fleets)

Investigation (background agent, evidence in memory + below). Verifying DB against the file it was ingested from is circular — it only catches ingestion defects, never source errors. Segmented by primary source:

Seg Source N % Plan
A West .doc (RTF, keyed from published reporter) 7,234 57% Deterministic .doc diff, NOT LLM fleets
B archive.ndcourts.gov HTML 4,769 38% Convert via Westlaw, don't proof the HTML
C N.W. OCR markdown 584 5% LLM+human + 2 deterministic pre-passes

2A. Segment A = deterministic diff (huge win: ~57% needs no LLM proofing)

  • scripts/doc_db_diff.py swept all 7,234: 96.7% byte-clean (6,997/7,234) vs the .doc.
  • The 237 "divergences" are NOT body defects — they're front-matter/metadata contamination: leaked # Case Name markdown headings, Decided/WL/reporter-cite preambles prepended to text_content, and West editorial blocks (Attorneys and Law Firms / Synopsis). The opinion bodies match the .doc.
  • CAVEAT / unfinished: textutil drops spaces in some RTF runs (e.g. Kuklokv.NorthDakotaWorkers'), which made the word-level diff produce false body divergences. A whitespace-insensitive re-check was started but the char-level find_longest_match timed out (macOS has no timeout; use gtimeout or cap iterations). TODO: finish the ws-insensitive body-clean confirmation to nail the true body-defect count (expected: near-zero), then build a deterministic front-matter-strip pass for the ~237 (strip leaked # headings + metadata preamble + West editorial blocks from text_content). Queue: triage/segA-divergences.tsv (+ segA-diff-summary.txt). Pilot: triage/segA-pilot-ids.txt (24 op, 100% clean by both LLM fleet and the diff — validates the approach).
  • scripts/verify_proofing_proposals_doc.py — the .doc gate (thin clone of the PDF gate, textutil in place of pdftotext). Ready if/when segment A needs proposal gating.

2B. Segment B = Westlaw conversion (see §4)

2C. Segment C — LLM+human; add deterministic pre-passes for the leaked-#-heading class and

the 66%-of-C bare-*NNN star-page residue. Small; lowest priority.

3. P59 A/B — VERDICT: DB-only rejected for modern fleets (settled, don't re-run)

Ran P59 twice on the same 120 opinions: current-method (reads PDF) vs --db-only (no source, proposes from DB text; same deterministic PDF gate confirms both).

Current DB-only
confirmed fixes 676 505
tokens 7.47M 5.80M (−22%)
recall vs current 65.2% (441/676)

−22% tokens for −35% recall = bad trade for authoritative text. Miss profile: DB-only missed missing_text (11/12), whitespace (39/51), ocr_char (83/233) — all need the source; but MATCHED split_join 218/251 (dehyphenation is inferable). Keep the PDF-reading method for modern. The segment-A plan is unaffected (it's deterministic-diff, cheaper than DB-only and no recall loss). gen_proofing_workflow.py gained --db-only (experiment flag; leave unused). Artifacts: triage/p59-{current,dbonly}.results*.json.

4. Segment-B Westlaw conversion — IN PROGRESS

Goal: replace non-authoritative archive HTML with West bound text, moving segment B into the segment-A .doc regime AND upgrading the DB text to authoritative reporter text.

  • Worklist: triage/westlaw-batches/batch-001.tsv … batch-048.tsv (100 each, newest-first, all have an N.W.2d pull cite).
  • Batch 1 DONE (westlaw-receive-2026-07-08): 98/98 promoted (0 ambiguous/errors, jaccard 0.85–0.91), now .doc-primary. 47 batches (~4,671 opinions) remain.
  • The loop: copy a batch's cites to clipboard (cut -f4 triage/westlaw-batches/batch-0NN.tsv | tail -n +2 | paste -sd';' - | pbcopy) → user runs Westlaw Find&Print → drops zip in ~/Downloads → stage: mkdir -p ~/refs/nd/opin/westlaw-incoming/<date> + copy + unzip, then rm the .zip from the incoming dir (the tool auto-extracts any .zip into a subdir → doubles the doc count; remove both the zip AND any Westlaw Precision …/ subdir so only loose .docs remain) → python -m ndcourts_mcp.receive_westlaw --incoming <dir> (dry-run) → review report (triage/westlaw-receive-<date>.tsv, want 98–100 promoted / 0 ambiguous) → --apply → invariants.
  • Westlaw rejects = free citation QA on segment B. Track in triage/segB-westlaw-rejects.tsv. Batch-1 reject rate: 2/100. Two kinds: (a) genuine wrong-page DB cite error → fix cite, re-pull; (b) unpublished disposition (§5) → keep+flag, no West text exists.

5. OPEN DECISION — unpublished per curiam dispositions

Batch-1's 2 rejects (id20421 Richmond v. Allstate Civil 960194; id20439 Kudrna v. Kudrna Civil 960091) are pre-1997 N.D.R.App.P. 35.1(a)(2) summary affirmances — user confirmed the N.W.2d pages are correct but the opinions were removed from the bound volume as not-designated- for-publication (advance-sheet list only). Full text (from archive.ndcourts.gov) IS present and complete (caption + disposition + rule + full panel). Class ≈ 11–36 (pre-1997 short archive per curiams).

  • RECOMMENDATION (mine, pending user's ruling): KEEP + flag unpublished, do NOT delete. They're real, complete, court-posted dispositions; the same type is published with a neutral cite post-1997; CourtListener carries them; deletion is irreversible. Add a precedential_status column (none exists — schema has case_type/notes/disposition) and annotate the cite as table/NDP.
  • Corpus policy this sets: a Westlaw reject that is an unpublished summary disposition → keep+flag, don't pull West text, don't "correct" the cite. Only wrong-page rejects get corrected. Decide before mass-converting the remaining 47 batches.

6. Next steps (priority order)

  1. User ruling on §5 (unpublished dispositions) — gates the segment-B reject policy.
  2. git commit + release today's work (P59 + 2 passes + Westlaw batch 1) — it's all unreleased. Prior release gotcha: gh release create flaked HTTP 422 on the 740M zip; create with the 5 small DBs + tag first, then gh release upload opinions.db.zip separately (memory project_server_deploy_ops).
  3. Continue segment-B pulls (batches 2–48) — user pulls, I process per §4.
  4. Finish segment-A — ws-insensitive body-clean confirm + front-matter-strip pass (§2A).
  5. Fleet P60 (OFFSET 4990) when returning to modern proofing — current PDF method.
  6. Work the P59 flag queue (194 flags + 77 rejects, triage/p59-current.results.*.json) — the high-value items (statute pinpoints, Sup.Ct.Sup. Ct. spacing, ¶6¶ 6) PDF-verified.

7. Carry-over queues (from 2026-07-07, still open)

[[Image here]] reconstruction (639, TODO-image-reconstruction.md); CL parallel-cite enrichment pass; 62-item markup HOLD (triage/proofing-p1p41-HOLD-for-review.json); flag-review backlog (malformed *Case**,* emphasis, case-name divergences); statutes #4 minor; full-corpus cite_extract re-run under jetcite 2.5.3. Detail in memory project_ongoing_work.md §"Open queues".

8. Durable traps (don't redo)

  • macOS has no timeout — use gtimeout or cap loop iterations (bit me on the seg-A ws diff).
  • receive_westlaw auto-extracts any .zip in the incoming dir into a subdir → doubles the doc count; remove the zip + any extracted subdir so only loose .docs remain before --apply.
  • Run everything via .venv/bin/python. Full ingest re-scan resurrects §6-merged dups — use --incremental.
  • apply_proofing_proposals.py logs field=text_content.<class> (NOT revertible via cleanup revert, which does SET <field>=old_value); the deterministic passes + receive_westlaw log field=text_content full old/new (ARE revertible). Backups (.bak-*) are the real safety net.
  • Preserve court typos present in BOTH sources ([[feedback_preserve_source_typos]]).