fix(extraction): reconcile לתיקים-יתומים בתור — pending+requested_at=NULL (#139) #264

Merged
chaim merged 1 commits from worktree-extraction-orphan-reconcile into main 2026-06-15 04:11:19 +00:00
Owner

הבעיה (#139)

תיק יכול להיות <kind>_extraction_status='pending' עם _requested_at IS NULLמעולם-לא-נכנס-לתור (מסלולי bulk/מיגרציה, או status שנכתב לפני החותם). הדריינר סורק requested_at IS NOT NULL → עיוור אליו לנצח, וה-backlog מתנקז בשקט. requeue_stale_processing_extractions מרפא רק 'processing'. נצפה 2026-06-14: 96 תיקים pending אך 0 בתור (תוקנו ידנית).

התיקון (G1 — שחזור invariant במקור · G2 — predicate יחיד · kind-agnostic)

  1. db.reconcile_orphaned_pending_extractions(kind=) — מחזיר את invariant "שורה ברת-חילוץ ⇒ בתור": חותם requested_at ל-rows שהם pending + requested_at IS NULL + EXTRACTION_ELIGIBLE_PREDICATE (אותו מסנן של #140 — cited_only/chunkless לעולם לא נדחפים). אידמפוטנטי.
  2. process_pending_extractions קורא reconcile אחרי requeue_stale ולפני list — תיקים-משוחזרים נקלטים באותו pass. מנגנון-ריפוי יחיד (G2): requeue_stale='processing', reconcile='pending'.
  3. request_halacha_extraction מציב status='pending' עם החותם (סימטרי ל-request_metadata_extraction) — סוגר את חלון-ה-drift שמייצר pending+NULL מלכתחילה.

המצב החי נקי (0 יתומים-כשירים אחרי התיקון-הידני של 14.6); זהו תיקון מונע — הדריינר יְרַפֵּא יתומים עתידיים אוטומטית, לשני התורים.

בדיקות

  • test_extraction_orphan_reconcile (חדש) — predicate משותף, pending+NULL בלבד, מובחן מ-requeue_stale (לא נוגע ב-processing), request_halacha סימטרי. פרמטרי לשני ה-kinds.
  • כל 349 בדיקות mcp עוברות. undefined-names + leak-guard נקיים.

Invariants

  • G1 / INV-DUR1 (X16) — שורה כשירה שהתייתמה מהתור משוחזרת אוטומטית
  • G2EXTRACTION_ELIGIBLE_PREDICATE משותף עם #140; מנגנון-ריפוי יחיד (לא מסלול מקביל)
  • INV-G4 — אין בליעה שקטה (reconcile מתעד logger.warning)
  • G12 — leak-guard נקי

🤖 Generated with Claude Code

## הבעיה (#139) תיק יכול להיות `<kind>_extraction_status='pending'` עם `_requested_at IS NULL` — **מעולם-לא-נכנס-לתור** (מסלולי bulk/מיגרציה, או status שנכתב לפני החותם). הדריינר סורק `requested_at IS NOT NULL` → עיוור אליו לנצח, וה-backlog מתנקז בשקט. `requeue_stale_processing_extractions` מרפא **רק** `'processing'`. נצפה 2026-06-14: 96 תיקים `pending` אך 0 בתור (תוקנו ידנית). ## התיקון (G1 — שחזור invariant במקור · G2 — predicate יחיד · kind-agnostic) 1. **`db.reconcile_orphaned_pending_extractions(kind=)`** — מחזיר את invariant "שורה ברת-חילוץ ⇒ בתור": חותם `requested_at` ל-rows שהם `pending` + `requested_at IS NULL` + `EXTRACTION_ELIGIBLE_PREDICATE` (**אותו מסנן של #140** — cited_only/chunkless לעולם לא נדחפים). אידמפוטנטי. 2. **`process_pending_extractions`** קורא reconcile אחרי `requeue_stale` ולפני `list` — תיקים-משוחזרים נקלטים באותו pass. מנגנון-ריפוי **יחיד** (G2): `requeue_stale`='processing', `reconcile`='pending'. 3. **`request_halacha_extraction`** מציב `status='pending'` עם החותם (סימטרי ל-`request_metadata_extraction`) — סוגר את חלון-ה-drift שמייצר `pending`+NULL מלכתחילה. המצב החי נקי (0 יתומים-כשירים אחרי התיקון-הידני של 14.6); זהו **תיקון מונע** — הדריינר יְרַפֵּא יתומים עתידיים אוטומטית, לשני התורים. ## בדיקות - `test_extraction_orphan_reconcile` (חדש) — predicate משותף, `pending`+NULL בלבד, מובחן מ-`requeue_stale` (לא נוגע ב-processing), `request_halacha` סימטרי. פרמטרי לשני ה-kinds. - כל **349** בדיקות mcp עוברות. `undefined-names` + `leak-guard` נקיים. ## Invariants - ✅ **G1 / INV-DUR1 (X16)** — שורה כשירה שהתייתמה מהתור משוחזרת אוטומטית - ✅ **G2** — `EXTRACTION_ELIGIBLE_PREDICATE` משותף עם #140; מנגנון-ריפוי יחיד (לא מסלול מקביל) - ✅ **INV-G4** — אין בליעה שקטה (reconcile מתעד `logger.warning`) - ✅ **G12** — leak-guard נקי 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chaim added 1 commit 2026-06-15 04:10:19 +00:00
fix(extraction): reconcile לתיקים-יתומים בתור — pending+requested_at=NULL (#139)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 4s
Lint — undefined names / undefined-names (pull_request) Successful in 11s
2343892220
תיק יכול להיות <kind>_extraction_status='pending' עם _requested_at=NULL —
מעולם-לא-נכנס-לתור (מסלולי bulk/מיגרציה, או status שנכתב לפני החותם), והדריינר
(סורק requested_at IS NOT NULL) עיוור אליו לנצח → ה-backlog מתנקז בשקט לאפס.
requeue_stale_processing_extractions מרפא רק 'processing'. נצפה 2026-06-14:
96 תיקים pending אך 0 בתור (תוקנו ידנית).

תיקון (G1 — שחזור invariant במקור, G2 — predicate יחיד):
- db.reconcile_orphaned_pending_extractions(kind=) — kind-agnostic, מחזיר את
  invariant "שורה ברת-חילוץ ⇒ בתור": חותם requested_at ל-rows שהם pending +
  requested_at IS NULL + EXTRACTION_ELIGIBLE_PREDICATE (אותו מסנן של #140 —
  cited_only/chunkless לעולם לא נדחפים). אידמפוטנטי (rows מסומנים לא נתפסים).
- precedent_library.process_pending_extractions קורא reconcile אחרי requeue_stale
  ולפני list — תיקים-משוחזרים נקלטים באותו pass. מנגנון-ריפוי יחיד (G2), לא מסלול
  מקביל; requeue_stale='processing', reconcile='pending'.
- request_halacha_extraction מציב status='pending' עם החותם (סימטרי ל-metadata)
  — סוגר את חלון-ה-drift שמייצר pending+NULL מלכתחילה.

מצב חי נקי (0 יתומים-כשירים אחרי התיקון-הידני); זהו תיקון מונע — הדריינר יְרַפֵּא
יתומים עתידיים אוטומטית.

בדיקות: test_extraction_orphan_reconcile (predicate משותף, pending+NULL בלבד,
מובחן מ-requeue_stale, request_halacha סימטרי), שני ה-kinds. כל 349 עוברות.

Invariants: G1, G2 (predicate משותף עם #140, ריפוי יחיד), INV-G3/INV-DUR1 (X16),
INV-G4 (אין בליעה שקטה — reconcile מתעד), G12.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chaim merged commit ce86821393 into main 2026-06-15 04:11:19 +00:00
chaim deleted branch worktree-extraction-orphan-reconcile 2026-06-15 04:11:19 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ezer-mishpati/legal-ai#264