FU-2a: idempotent ingest + write-time normalization + searchable flag (GAP-03/06/13) #12

Merged
chaim merged 9 commits from fix/fu2a-idempotent-ingest into main 2026-05-30 21:06:33 +00:00
Owner

Summary

GAP-03/06/13 (FU-2a, pure-code). מאמת מול 3+ מקורות (PostgreSQL ON CONFLICT, DDD write-boundary normalization, materialized validity flag).

  • GAP-03INSERT … ON CONFLICT … DO UPDATE אטומי בשתי פונקציות ה-create, עם חזרה על ה-predicate של ה-partial-index (V15) + COALESCE ממוקד. מחליף SELECT-then-INSERT (race-prone) וגם את קידום cited_only→external_upload. אומת מול DB אמיתי (idempotent).
  • GAP-06_canonical_case_number בכתיבה, type-aware: internal/cases מנרמל (trim·prefix-strip·/→-, ללא הוספת/הסרת חודש); external שומר את ה-citation (המזהה הקנוני שלו).
  • GAP-13 — עמודת searchable (V21) נגזרת מחוזה-השלמות (INV-DM1), recompute בסיום קליטה/חילוץ-metadata, חשיפה ב-health-check, וסינון בחיפוש הפסיקה.

מספק INV-ING2/G3/G1/ID1/DM1.

Decision gate (searchable filter)

ה-dry-run גילה ש-2 פסקי בג"ץ חוצי-תחום (33/16 chunks) היו נופלים בגלל practice_area ריק. במקום לזייף תחום — חוזה-השלמות תוקן לדרוש practice_area רק ל-internal/cases (לא לפסיקה חיצונית). backfill סימן 80 רשומות searchable (24 external + 56 internal); cited_only (49) לא-searchable וממילא מוחרג מחיפוש הפסיקה ע"י source_kind. הפילטר הופעל ב-0 הפלות לגיטימיות.

Boundary / out of scope

  • אין מיגרציית-מזהים. GAP-07/08 (תיאום ~52 מזהים מבולגנים + dedup של 8047-23) פוצלו ל-#67 / FU-2b — data-migration שמערב היו"ר.
  • migration V21 + backfill הורצו על ה-DB המשותף (תוספתי, הפיך). הקוד נפרס עם המיזוג.

Test Plan

  • 13 בדיקות offline חדשות (normalize, completeness predicate, ingest wiring, external-empty-practice_area)
  • כל החבילה ירוקה — 90 passed
  • smoke מול DB אמיתי: ON CONFLICT idempotent + נרמול-בכתיבה
  • סקירת-קוד סופית (spec+quality) עברה — param/predicate נכונים, פילטר מוגבל לנתיבי case_law בלבד

🤖 Generated with Claude Code

## Summary GAP-03/06/13 (FU-2a, pure-code). מאמת מול 3+ מקורות (PostgreSQL ON CONFLICT, DDD write-boundary normalization, materialized validity flag). - **GAP-03** — `INSERT … ON CONFLICT … DO UPDATE` אטומי בשתי פונקציות ה-create, עם חזרה על ה-predicate של ה-partial-index (V15) + COALESCE ממוקד. מחליף SELECT-then-INSERT (race-prone) וגם את קידום cited_only→external_upload. אומת מול DB אמיתי (idempotent). - **GAP-06** — `_canonical_case_number` בכתיבה, type-aware: internal/cases מנרמל (trim·prefix-strip·/→-, ללא הוספת/הסרת חודש); external שומר את ה-citation (המזהה הקנוני שלו). - **GAP-13** — עמודת `searchable` (V21) נגזרת מחוזה-השלמות (INV-DM1), recompute בסיום קליטה/חילוץ-metadata, חשיפה ב-health-check, וסינון בחיפוש הפסיקה. מספק INV-ING2/G3/G1/ID1/DM1. ## Decision gate (searchable filter) ה-dry-run גילה ש-2 פסקי בג"ץ חוצי-תחום (33/16 chunks) היו נופלים בגלל practice_area ריק. במקום לזייף תחום — חוזה-השלמות תוקן לדרוש practice_area רק ל-internal/cases (לא לפסיקה חיצונית). backfill סימן 80 רשומות searchable (24 external + 56 internal); cited_only (49) לא-searchable וממילא מוחרג מחיפוש הפסיקה ע"י source_kind. הפילטר הופעל ב-0 הפלות לגיטימיות. ## Boundary / out of scope - **אין מיגרציית-מזהים.** GAP-07/08 (תיאום ~52 מזהים מבולגנים + dedup של 8047-23) פוצלו ל-#67 / FU-2b — data-migration שמערב היו"ר. - migration V21 + backfill הורצו על ה-DB המשותף (תוספתי, הפיך). הקוד נפרס עם המיזוג. ## Test Plan - [x] 13 בדיקות offline חדשות (normalize, completeness predicate, ingest wiring, external-empty-practice_area) - [x] כל החבילה ירוקה — 90 passed - [x] smoke מול DB אמיתי: ON CONFLICT idempotent + נרמול-בכתיבה - [x] סקירת-קוד סופית (spec+quality) עברה — param/predicate נכונים, פילטר מוגבל לנתיבי case_law בלבד 🤖 Generated with [Claude Code](https://claude.com/claude-code)
chaim added 9 commits 2026-05-30 21:06:22 +00:00
FU-2 split (chair decision 2026-05-30): FU-2a = pure-code (GAP-03 ON CONFLICT
upsert, GAP-06 write-time type-aware normalization, GAP-13 materialized
searchable flag); FU-2b (#67) = data-migration for GAP-07/08 (identifier
reconciliation + dedup) deferred as separate chair-involved task.

DB check 2026-05-30: ~52/56 internal_committee rows hold full citation in
case_number, >=1 duplicate (8047-23). Architecture verified vs 3+ sources
(PostgreSQL ON CONFLICT, DDD write-boundary normalization, materialized
validity flag). No identifier migration in FU-2a.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add SCHEMA_V21_SQL (searchable boolean column + index on case_law), wire it
into _run_schema_migrations, and implement _compute_searchable (pure predicate)
+ recompute_searchable (idempotent async backfill/update). All 5 unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire db.recompute_searchable into the ingest pipeline (after statuses are set) and into
extract_and_apply (after fields are persisted to DB, success path only).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
chaim merged commit 3b758850e0 into main 2026-05-30 21:06:33 +00:00
chaim deleted branch fix/fu2a-idempotent-ingest 2026-05-30 21:06:33 +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#12