docs(spec): WS7 — reconcile 01/02/03/04/06 + gap-audit; verify 7 workflow-redesign leaks closed (#207)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 3s
Lint — undefined names / undefined-names (pull_request) Successful in 10s

WS7 of the workflow-redesign initiative required closing 7 known leaks along
the way. Cross-code audit verified ALL 7 were already closed in prior cycles
(FU-1/4/5/6/7 + IA waves); the spec still carried stale "known violation" text.
This PR aligns the spec to actual code state and verifies each closure with a
test. No new code path created — this is a spec-alignment audit, not a re-solve.

7 leaks → status (all closed/gated, each with a test):
1. cross-corpus halachot (#56, GAP-10/FU-4) — cl.source_kind in halacha_filters
   (db.py:7516,7519); test_precedent_corpus_isolation.py
2. invisible halacha backlog (GAP-14/FU-5) — health halacha_backlog
   (app.py:2352-2364) + extraction_status/halachot_pending
3. no eval harness (GAP-11/FU-5, G8) — scripts/eval_retrieval.py
   (P/R/MRR/nDCG vs gold-set+baseline); --self-test ALL PASS
4. export gate not hard-block (GAP-15/FU-6, INV-EX3) — export_docx checks
   qa_run_exists + get_critical_qa_failures before exporter (drafting.py:462-494);
   test_export_qa_gate.py
5. metadata on internal path (GAP-02/FU-1, INV-ING3) — unified ingest.ingest_document
   queues metadata+halacha together (ingest.py:233-234); test_unified_ingest.py
6. DOCX creep to source-of-truth (GAP-17/FU-7, INV-EX1) — active_draft_path is
   revision-anchor only; drift caught by cases.blocks_stale flag (V22)
7. UI cache-invalidation (GAP-33/FU-10) — qc.invalidateQueries on mutations

Also added forward-pointer notes for the workflow-redesign additions owned by
sibling tasks (02 documents is_primary/doc_category → #200; 04 re-analysis /
summarize_party_claims / analyze_protocol → #200/#202/#203), kept additive to
avoid line conflicts. block-schema.md interim/template edits deferred to #204/#205.

Invariants: maintains G2 (single source of truth, no parallel path — all leak
closures extend the canonical path), G8 (eval harness now exists), G10 (human
gates visible: halacha backlog + hard export gate), INV-ING3 (unified metadata
queue), INV-EX1 (DOCX is derived; blocks_stale drift flag), INV-RET1/G5 (#56
cross-corpus halacha isolation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-30 11:22:11 +00:00
parent 61e6be4b90
commit 9ef0547997
6 changed files with 102 additions and 54 deletions

View File

@@ -79,11 +79,12 @@ quality / conformance) | סטטוס: verified
**אכיפה:** תנאי-`source_kind` בכל ענף-SQL בשכבת-החיפוש; בדיקת-בריאות שמריצה שאילתת-ביקורת
(חיפוש מכוון-קורפוס שמחזיר פריט בעל `source_kind` זר = כשל). אוכף את
[G5](00-constitution.md#inv-g5-metadata-מלא--הפרדת-קורפוס-נאכפת-בכל-query).
**הפרה ידועה:** משימה #56 `halacha_filters` **אינם** כוללים `cl.source_kind` ב-
`search_precedent_library_semantic` (`db.py:3168`, ענף ה-halacha; לעומת `chunk_filters` שכן —
`db.py:3169`) **וב**-`search_precedent_library_lexical` (`db.py:3401` מול `db.py:3402`). שני
ה-`halacha_sql` עושים `JOIN case_law cl` בלי לסנן `source_kind` (`db.py:3236-3238`, `db.py:3475-3477`)
→ הלכות מהקורפוס הפנימי דולפות לתוצאות החיפוש בקורפוס החיצוני ולהפך → ממצא ל-[audit](../audit-report.md).
**הפרה ידועה — ✅ נסגרה (FU-4, GAP-10, משימה #56):** בעבר `halacha_filters` לא כללו
`cl.source_kind` (בניגוד ל-`chunk_filters` שכן) → הלכות מהקורפוס הפנימי דלפו לחיפוש בקורפוס
החיצוני ולהפך. **נסגר:** שני ה-`halacha_filters` (semantic + lexical) מתחילים כעת ב-
`cl.source_kind = '{source_kind}'` בדיוק כמו `chunk_filters` (`db.py:7516,7519` ומקבילו ב-
`search_precedent_library_lexical`). מאומת ב-`test_precedent_corpus_isolation.py` (semantic+lexical,
שני ה-source_kind) → תיעוד-מקור: [audit](../audit-report.md).
### INV-RET2: אין החזרה/אינדוקס בלי metadata מלא + locator פתיר
**כלל:** פריט אינו מוחזר מ-search (ואינו נחשף לאחזור) אלא אם **שדות-החובה שלו מולאו**
@@ -121,10 +122,13 @@ relevance judgments, precision/recall) · RAG evaluation literature (Lewis et al
Elastic — *relevance evaluation guidance* | סטטוס: verified
**אכיפה:** eval harness עם gold-set מתויג + בדיקת-בריאות תקופתית; שער-CI על שינוי שכבת-האחזור.
אוכף את [G8](00-constitution.md#inv-g8-איכות-אחזור-נמדדת--precision--recall).
**הפרה ידועה (GAP):** אין כיום eval harness ולא gold-set — קיים רק `telemetry.log_search_bg`
(`search.py:62,118,190,271`; `precedent_library.py:280`) שמתעד שאילתות בפועל, אך **אינו מודד
precision/recall מול תיוג** (תצפית, לא הערכה). היעד: harness שמריץ סט קבוע ומחזיר metrics →
ממצא ל-[audit](../audit-report.md).
**הפרה ידועה — ✅ נסגרה (FU-5, GAP-11):** בעבר היה רק `telemetry.log_search_bg` (תצפית, לא
הערכה). **נסגר:** `scripts/eval_retrieval.py` מריץ את **מסלול-האחזור בייצור** (אותן פונקציות-
שירות שכלי-ה-MCP קוראים) מול gold-set מתויג (`data/eval/gold-set.jsonl`, נבנה ב-
`scripts/eval_gold_bootstrap.py`) ומחזיר precision/recall/MRR/nDCG@{5,10} — סך-הכול, פר-קורפוס
ופר-`practice_area` — מול baseline מקובע (`data/eval/baseline.json`). מטריקות-הליבה נבדקות
offline ב-`eval_retrieval.py --self-test` ("ALL PASS"). **משמעת-CI:** להריץ לפני/אחרי כל שינוי
שכבת-אחזור (משקלי-RRF/`k`/סף-chunk/embedder/rerank) ולהשוות ל-baseline. תיעוד-מקור: [audit](../audit-report.md).
### INV-RET5: כל span מוחזר עקיב למקורו
**כלל:** כל קטע מוחזר נושא **עקיבוּת-מקור מלאה** — מזהה-מסמך/פסק-דין (`case_law_id`/`document_id`/
@@ -156,16 +160,15 @@ re-embed; בדיקת-בריאות מגלה embeddings מיושנים. אוכף
ההבדלים בין הקוד בפועל ל-TARGET. **אלו תסמינים, לא התנהגויות תקינות.** כל פריט אומת מול הקוד.
- **דליפת-הלכות חוצת-קורפוס (משימה #56).** `halacha_filters` נפתחים רק עם `review_status`
(`db.py:3168`, `db.py:3401`) ואינם מוסיפים `cl.source_kind`, בעוד `chunk_filters` כן
(`db.py:3169`, `db.py:3402`). שני ה-`halacha_sql` עושים `JOIN case_law` בלי סינון
(`db.py:3236-3242`, `db.py:3463-3482`). **תסמין:** חיפוש בקורפוס החיצוני
(`search_precedent_library`, `source_kind="external_upload"`) יכול להחזיר הלכה שמקורה
בהחלטת-ועדה פנימית — ולהפך עבור `search_internal_decisions` (`source_kind="internal_committee"`,
`internal_decisions.py:418`). **יעד:** `halacha_filters` יתחילו ב-`cl.source_kind = '{source_kind}'`
בדיוק כמו `chunk_filters` ([INV-RET1](#inv-ret1-הפרדת-קורפוס-נאכפת-ב-100-ממסלולי-ה-query)).
- **אין eval harness — מדידת-איכות לא קיימת.** רק `telemetry.log_search_bg` מתעד שאילתות
(`search.py:62,118,190,271`); אין gold-set מתויג ואין precision/recall. **יעד:** harness עומד
- **דליפת-הלכות חוצת-קורפוס (משימה #56) — ✅ נסגר (FU-4, GAP-10).** בעבר `halacha_filters` לא
כללו `cl.source_kind` (בניגוד ל-`chunk_filters`) → הלכה מהקורפוס הפנימי יכלה לחזור בחיפוש
בקורפוס החיצוני, ולהפך. **נסגר:** `halacha_filters` מתחילים כעת ב-`cl.source_kind = '{source_kind}'`
+ `cl.searchable = true` בדיוק כמו `chunk_filters` (`db.py:7514-7519`), בשתי הפונקציות
(semantic+lexical). מאומת ב-`test_precedent_corpus_isolation.py`
([INV-RET1](#inv-ret1-הפרדת-קורפוס-נאכפת-ב-100-ממסלולי-ה-query)).
- **eval harness — ✅ נסגר (FU-5, GAP-11).** בעבר רק `telemetry.log_search_bg` (תצפית).
**נסגר:** `scripts/eval_retrieval.py` (precision/recall/MRR/nDCG מול `data/eval/gold-set.jsonl`
+ baseline; `--self-test` עובר offline) — מדידה אמפירית מול תיוג קבוע
([INV-RET4](#inv-ret4-איכות-אחזור-נמדדת-ב-eval-harness-עומד-precision--recall)).
- **`search_decisions` מתעד אזהרה כשאין `practice_area` אך לא חוסם.** ללא פילטר-תחום החיפוש
עלול לערבב תחומים משפטיים (`search.py:45-49,172-176``logger.warning`, ממשיך). **יעד:** הפרדה