docs(spec): WS7 — יישור 01/02/03/04/06 + gap-audit; ווידוא סגירת 7 דליפות עיצוב-מחדש (#207) #359
@@ -96,10 +96,11 @@ idempotency-key pattern · ISO 8000 (Data quality) | סטטוס: verified
|
||||
בנקודת-סיום-הקליטה, לכל סוג; חוזה-שלמות יסמן רשומה ללא מטא-דאטה כלא-שמישה
|
||||
([G4](00-constitution.md#inv-g4-חוזה-שלמות-לפני-שמיש--ניתן-לחיפוש), מפורט ב-
|
||||
[02-data-model.md](02-data-model.md)).
|
||||
**הפרה ידועה:** המסלול הפנימי (`internal_decisions.py:208`) מתזמן **רק**
|
||||
`request_halacha_extraction` ואינו קורא ל-`request_metadata_extraction` (בניגוד
|
||||
ל-`precedent_library.py:292-293` שקורא לשניהם) → ערן סופר 8046/24 נקלטה **בלי
|
||||
metadata** (headnote/summary/tags ריקים) → ממצא ל-[audit](../audit-report.md).
|
||||
**הפרה ידועה — ✅ נסגרה (FU-1, GAP-02):** המסלול הפנימי דילג בעבר על חילוץ-המטא-דאטה
|
||||
(`internal_decisions.py:208` תיזמן רק `request_halacha_extraction`) → ערן סופר 8046/24 נקלטה
|
||||
בלי metadata. **נסגר:** שני מסלולי-הפסיקה זורמים כעת דרך `ingest.ingest_document` הקנוני, שמתזמן
|
||||
**את שני התורים יחד** בנקודה אחת (`ingest.py:233-234`) — תיזמון-המטא אינו מותנה במסלול עוד.
|
||||
מאומת ב-`test_unified_ingest.py` (9/9). תיעוד-מקור: [audit](../audit-report.md).
|
||||
|
||||
### INV-ING4: re-index בקליטה-חוזרת (upsert ⇒ re-embed)
|
||||
**כלל:** קליטה-חוזרת ששינתה את תוכן-הפריט מפעילה **re-index** — chunks ו-embeddings
|
||||
|
||||
@@ -73,6 +73,9 @@ proceeding_type)`. לכן המזהה הקנוני הוא **(`case_number` מנו
|
||||
### 2ב. חוזה תמציתי לישויות נוספות
|
||||
|
||||
- `documents` → usable: `file_path`+`doc_type`; searchable: `extraction_status=completed` ו-`extracted_text` לא-ריק ו-≥1 `document_chunk` עם embedding.
|
||||
> **עיצוב-מחדש זרימת-העבודה (WS2, #200):** `documents` מקבל `is_primary`/`doc_category` (רשימה
|
||||
> קנונית: ערר/תשובה/תגובה/פרוטוקול/שומה/החלטת-ועדה) + דגל-ניתוח per-מסמך (`claims_extraction_status`),
|
||||
> כדי לחשב "יש מסמך-עיקרי שלא-נכלל-בניתוח". השדות בבעלות #200; ניתוח-החילוץ עצמו ב-[04-analysis-writing](04-analysis-writing.md) §1.
|
||||
- `halachot` → usable: `rule_statement`+`supporting_quote`; **searchable: `review_status ∈ {approved, published}` בלבד** — `pending_review`/`rejected` מוסתרות מ-`search_precedent_library` (שער-הלכה ידני, `db.py:644-660`, [G10](00-constitution.md#inv-g10-המערכת-מסייעת--שערים-אנושיים-הם-invariant)).
|
||||
- `decision_blocks` → usable: `block_id`∈12-הבלוקים; "מוכן": `status=final` ו-`content` לא-ריק.
|
||||
- `chair_feedback` → usable: `feedback_text`+`category` מהמילון; "פתוח" עד `resolved=true`.
|
||||
@@ -176,18 +179,22 @@ RAG freshness (Lewis et al., 2020, NeurIPS) | סטטוס: verified
|
||||
(`case_number, source_kind, proceeding_type`, `db.py:904-909`), אך השדה `case_number TEXT
|
||||
UNIQUE NOT NULL` המקורי (`db.py:368`) הוסר רק ב-V15 (`db.py:902-903`) — מורשת שאפשרה את
|
||||
הפרת [INV-DM2](#inv-dm2-מזהה-קנוני-יחיד-לכל-ישות). **יעד:** נרמול-בכתיבה אכוף + ציטוט-מלא רק ב-`citation_formatted`.
|
||||
- **`summary` קיים על `case_law` אך לא בחוזה-הקליטה הפנימי.** העמודה קיימת (`db.py:373`) אך
|
||||
המסלול הפנימי אינו ממלא אותה (כפועל-יוצא מהיעדר חילוץ-מטא-דאטה, [INV-ING3](01-ingest.md#inv-ing3-תור-חילוץ-מטא-דאטה--הלכות-לכל-סוג)).
|
||||
**יעד:** searchable מותנה ב-metadata לא-ריק ([INV-DM1](#inv-dm1-searchable-רק-כשחוזה-השלמות-מתקיים)).
|
||||
- **שני שדות-סטטוס-חילוץ נפרדים, ללא דגל-`searchable` מפורש.** `extraction_status` +
|
||||
`halacha_extraction_status` (`db.py:603-605`) מתארים תהליך, אך אין שדה יחיד שמסמן "עבר
|
||||
חוזה-שלמות → searchable". **יעד:** דגל/view נגזר ש-search מסנן לפיו, מגובה health-check.
|
||||
- **`summary` קיים על `case_law` אך לא בחוזה-הקליטה הפנימי — ✅ נסגר (FU-1, GAP-02).** העמודה
|
||||
קיימת (`db.py:373`), והמסלול הפנימי לא מילא אותה בעבר (היעדר חילוץ-מטא-דאטה). **נסגר:** שני
|
||||
המסלולים זורמים דרך `ingest.ingest_document` הקנוני שמתזמן metadata לשני הסוגים
|
||||
([01-ingest INV-ING3](01-ingest.md#inv-ing3-תור-חילוץ-מטא-דאטה--הלכות-לכל-סוג)); `searchable`
|
||||
מותנה ב-metadata לא-ריק ([INV-DM1](#inv-dm1-searchable-רק-כשחוזה-השלמות-מתקיים)).
|
||||
- **דגל-`searchable` מפורש — ✅ קיים.** מעבר ל-`extraction_status` + `halacha_extraction_status`
|
||||
(`db.py:603-605`, תהליך), קיימת כעת עמודת `case_law.searchable` המסמנת "עבר חוזה-שלמות"; שכבת-
|
||||
החיפוש מסננת לפיה (`cl.searchable = true`, `db.py:7517,7519`) ו-`recompute_searchable_flag`
|
||||
מתחזק אותה. אוכף את [INV-DM1](#inv-dm1-searchable-רק-כשחוזה-השלמות-מתקיים) בשכבת-האחזור.
|
||||
- **`embedding` אינו `GENERATED` (בניגוד ל-tsvector).** ה-tsvectors מסונכרנים אוטומטית
|
||||
(`db.py:776,780,1083`), אך ה-`embedding vector(1024)` תלוי-טריגר חיצוני — נקודת-drift אפשרית
|
||||
ל-[INV-DM3](#inv-dm3-שינוי-תוכן--re-index). **יעד:** טריגר re-embed מובטח + health-check ל-drift.
|
||||
- **`halachot.review_status` כשער-searchable ללא נראות-backlog.** הסינון תקין (`pending_review`
|
||||
מוסתר, `db.py:659`), אך אין נראות כמה ממתינות — תואם את ההפרה הידועה ב-[G10](00-constitution.md#inv-g10-המערכת-מסייעת--שערים-אנושיים-הם-invariant)
|
||||
(10/19 מאושרות, התגלה במקרה). **יעד:** health-check חושף backlog-הלכות.
|
||||
- **נראות backlog-הלכות — ✅ נסגר (FU-5, GAP-14).** הסינון תקין (`pending_review` מוסתר,
|
||||
`db.py:659`); ההפרה הישנה היתה היעדר-נראות (10/19 מאושרות, התגלה במקרה). **נסגר:** ה-health-
|
||||
check חושף `halacha_backlog` (`web/app.py:2352-2364`, `metrics_service.halacha_backlog`),
|
||||
והכלים `extraction_status` + `halachot_pending` חושפים את עומק-התור — שער-היו"ר ([G10](00-constitution.md#inv-g10-המערכת-מסייעת--שערים-אנושיים-הם-invariant)) הופך נראה.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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`, ממשיך). **יעד:** הפרדה
|
||||
|
||||
@@ -47,6 +47,17 @@
|
||||
> מקוריות מהשלמות). הסינון לפי `party_role` מאפשר לזהות את הצד המפסיד ולוודא שכל טיעון
|
||||
> שלו מקבל מענה בבלוק י.
|
||||
|
||||
> **עיצוב-מחדש זרימת-העבודה (WS2–WS4) — מסלול-החילוץ אינו מתפצל ([G2](00-constitution.md#inv-g2-מקור-אמת-יחיד--אין-מסלולים-מקבילים-מתפצלים)):**
|
||||
> ניתוח-ערר-לבד כבר עובד (`extract_claims` רץ על `appeal` בנפרד). ההרחבות נשענות על אותו צינור-
|
||||
> חילוץ, **לא** על מסלול-ניתוח שני: (א) **ניתוח-מחדש מאחד** (WS2, #200/#201) — מחלץ מ-מסמכים
|
||||
> חדשים/מעודכנים בלבד ומאחד עם הקיים (לא מוחק-ומחשב-מחדש), על-בסיס דגל-הניתוח per-מסמך
|
||||
> ([02-data-model §2ב](02-data-model.md#2ב-חוזה-תמציתי-לישויות-נוספות)); (ב) **סיכום-מנהלים**
|
||||
> (WS3, #202, `summarize_party_claims`) — נגזר מ-`claims`/`legal_arguments`, **מסמך-פרוזה נפרד**
|
||||
> מטיוטת-הביניים (G2: תצוגה-נגזרת, לא מקור-אמת שני); (ג) **ניתוח-פרוטוקול** (WS4, #203,
|
||||
> `analyze_protocol`) — `protocol` נכנס לחילוץ ההשוואתי (ירד/חוזק/חדש) ומזין ידע-תיק, ונשאר
|
||||
> פוסט-דיון ([INV-WR4](#inv-wr4-בלוק-ז--טענות-מקוריות-בלבד): טענות-פוסט-דיון → בלוק ח, לא ז).
|
||||
> חוזי-הכלים המלאים בבעלות המשימות הנ"ל; כאן רק עיגון-הספ שהם מקיימים G2.
|
||||
|
||||
---
|
||||
|
||||
## 2. ארכיטקטורת 12 הבלוקים (סיכום)
|
||||
|
||||
@@ -101,10 +101,14 @@ Model / Single Source of Truth) · SSOT (Single Source of Truth principle) | ס
|
||||
פלט מגורסן + idempotent מבחינת-תוכן; אוכף את
|
||||
[INV-G2](00-constitution.md#inv-g2-מקור-אמת-יחיד--אין-מסלולים-מקבילים-מתפצלים) וכלל-ההנדסה
|
||||
"סימטריה" (חוקה §6).
|
||||
**הפרה ידועה:** אחרי `revise_draft`/`apply_user_edit`, ה-DOCX המסומן `active_draft_path` הופך
|
||||
ל"מקור-האמת" לעריכות-Track-Changes העוקבות (`db.py:185-188`), ו**בלוקי-ה-DB אינם מתעדכנים
|
||||
חזרה** — הנתון-הנגזר זוחל למקור-אמת בפועל בלי סנכרון לאחור. **יעד:** או re-sync מהבלוקים, או
|
||||
חוזה מפורש ש-`active_draft_path` הוא רק אנקור-revision ולא מקור-תוכן → ראה [§5](#5-current-vs-target).
|
||||
**הפרה ידועה — ✅ מגודרת (FU-7, GAP-17):** אחרי `revise_draft`/`apply_user_edit` ה-DOCX
|
||||
המסומן `active_draft_path` משמש כאנקור לעריכות-Track-Changes העוקבות, ובלוקי-ה-DB אינם
|
||||
מתעדכנים חזרה — סטייה אפשרית בין הבלוקים למסמך-החי. **התיקון שנבחר (חוזה מפורש, לא re-sync):**
|
||||
`active_draft_path` הוא **אנקור-revision בלבד, לא מקור-תוכן מתחרה** — ה-DB נשאר מקור-האמת. סטייה
|
||||
נלכדת בדגל `cases.blocks_stale` (V22, `db.py:1142-1148`): `revise_draft`/`apply_user_edit`
|
||||
מסמנים `mark_blocks_stale(case_id, True)` (`drafting.py:688,789`) ו-`export_docx` מנקה
|
||||
(`mark_blocks_stale(case_id, False)`, `drafting.py:504`) — הדגל הוא ה-drift-detection שחושף מתי
|
||||
ה-DOCX-החי נסחף מהבלוקים. ראה [§5](#5-current-vs-target).
|
||||
|
||||
### INV-EX2: עקיבוּת-מקור נשמרת בהחלטה המיוצאת (→G9)
|
||||
**כלל:** ההחלטה המיוצאת **שומרת על עקיבוּת-מקור** היכן שנדרש — סמכויות-משפטיות מצוטטות
|
||||
@@ -127,29 +131,29 @@ Lewis et al. (2020, NeurIPS — RAG attribution) | סטטוס: verified
|
||||
**מקורות:** NCSC/JTC — *Principles & Practices for AI Use in Courts* (controlled, auditable
|
||||
output) · Council of Europe / CEPEJ (2018, under user control) · Federal Judicial Center —
|
||||
*Judicial Writing Manual* (2d ed.) | סטטוס: verified
|
||||
**אכיפה:** `export_blocked = critical_failures > 0` (`qa_validator.py:362`); **נאכף ברמת-
|
||||
הזרימה/agent בלבד** — הסוכן `legal-exporter` מחויב להריץ `validate_decision` ולבדוק
|
||||
כשלים-קריטיים לפני ייצוא (`.claude/agents/legal-exporter.md:71,149`).
|
||||
**הפרה ידועה:** `export_docx` (`drafting.py:384`) **אינו** קורא ל-`validate_decision` בעצמו —
|
||||
הוא ניגש ישירות ל-`docx_exporter.export_decision` בלי לבדוק `export_blocked`. החסימה תלויה
|
||||
במשמעת-הסוכן ואינה hard-block בקוד-הייצוא → ראה [§5](#5-current-vs-target) (תואם
|
||||
[05-qa-review §4](05-qa-review.md#4-current-vs-target--ממצאי-audit)).
|
||||
**אכיפה — ✅ hard-block בקוד (FU-6, GAP-15):** `export_docx` (`drafting.py:462`) **בודק לעצמו**
|
||||
לפני כל ייצוא — `db.qa_run_exists` (אם QA לא רץ כלל → חסום) ו-`db.get_critical_qa_failures`
|
||||
(אם יש כשל-קריטי → חסום) — **לפני** הגישה ל-`docx_exporter.export_decision`. אלו `SELECT` זולים
|
||||
על ה-`qa_results` המאוחסנים (לא הרצת-LLM חוזרת). נוסף על `export_blocked = critical_failures > 0`
|
||||
ברמת-הזרימה ועל משמעת-הסוכן `legal-exporter` (`.claude/agents/legal-exporter.md:71,149`) — כך
|
||||
שאי-אפשר לעקוף את השער אפילו בקריאה ישירה ל-`export_docx`.
|
||||
**הפרה ידועה — ✅ נסגרה (FU-6, GAP-15):** בעבר `export_docx` ניגש ישירות ל-exporter בלי לבדוק
|
||||
`export_blocked` (אכוף-זרימה בלבד, ניתן-לעקיפה). נסגר ע"י ה-hard-block לעיל; מאומת ב-
|
||||
`test_export_qa_gate.py` (חסום ללא-QA · חסום בכשל-קריטי · עובר כשנקי).
|
||||
|
||||
---
|
||||
|
||||
## 5. Current vs Target
|
||||
|
||||
- **שער-ייצוא אכוף-זרימה ולא אכוף-קוד (INV-EX3 / INV-QA3).** אומת בקוד: `export_docx`
|
||||
(`drafting.py:384-419`) קורא ישירות ל-`docx_exporter.export_decision` (`:403`) ללא קריאה
|
||||
ל-`qa_validator.validate_decision` ובלי בדיקת `export_blocked`. החסימה מתקיימת רק כי הסוכן
|
||||
`legal-exporter` מחויב להריץ QA קודם (`legal-exporter.md:71,149`) — אדם/סוכן שיקרא
|
||||
ל-`export_docx` ישירות **יעקוף** את השער. **יעד:** hard-block בתוך `export_docx` — שליפת
|
||||
`qa_results`/`export_blocked` ודחייה לפני כתיבת ה-DOCX, כך שאי-אפשר לעקוף.
|
||||
- **`active_draft_path` כ-derived-שזוחל-למקור (INV-EX1).** ה-DOCX נגזר מהבלוקים בייצוא הראשון,
|
||||
אך אחרי עריכה (`revise_draft`/`apply_user_edit`) ה-DOCX הופך ל"מקור-האמת" לעריכות הבאות
|
||||
(`db.py:185-188`) בלי לעדכן את `decision_blocks` חזרה — סטייה אפשרית בין הבלוקים למסמך-החי.
|
||||
**יעד:** חוזה מפורש — או re-sync מהבלוקים, או הגדרת `active_draft_path` כאנקור-revision בלבד
|
||||
(לא מקור-תוכן), עם בדיקת-בריאות לגילוי drift בין הבלוקים ל-DOCX הפעיל.
|
||||
- **שער-ייצוא — ✅ hard-block בקוד (INV-EX3 / INV-QA3, FU-6 / GAP-15).** `export_docx`
|
||||
(`drafting.py:462-494`) בודק `db.qa_run_exists` + `db.get_critical_qa_failures` ודוחה לפני
|
||||
הגישה ל-`docx_exporter.export_decision` — לא ניתן לעקוף בקריאה ישירה. מאומת ב-
|
||||
`test_export_qa_gate.py` (3 מקרים: ללא-QA / כשל-קריטי / נקי).
|
||||
- **`active_draft_path` כ-derived (INV-EX1, FU-7 / GAP-17) — ✅ מגודר בחוזה מפורש.** ה-DB נשאר
|
||||
מקור-האמת; `active_draft_path` הוא אנקור-revision בלבד. ה-drift בין הבלוקים ל-DOCX-החי נלכד
|
||||
בדגל `cases.blocks_stale`: נדלק ב-`revise_draft`/`apply_user_edit` (`drafting.py:688,789`),
|
||||
כובה ב-`export_docx` (`drafting.py:504`). **שארית (low-pri):** health-check שמתריע על
|
||||
`blocks_stale=true` עתיק — תיעוד-המשך, לא חוסם.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -232,3 +232,25 @@ FU-7 אחרי FU-1; FU-5 אחרי FU-2; FU-8 אחרי ייצוב-הספ. **(מח
|
||||
אחרי FU-1. FU-11 (מילוי-שדות) עצמאי. FU-13 (סוכנים+skills) אחרי ייצוב-הספ.
|
||||
**סיווג:** pure-code — FU-9/10/11/13/14; +data-migration קל — FU-12; +chair-decision — FU-15 (rotation סודות).
|
||||
priority בפועל — של היו"ר.
|
||||
|
||||
---
|
||||
|
||||
## ✅ ווידוא-סגירה — 7 דליפות עיצוב-מחדש זרימת-העבודה (WS7, #207, 2026-06-30)
|
||||
|
||||
תת-פרויקט עיצוב-מחדש זרימת-העבודה (תוכנית `groovy-doodling-token`, WS7) דרש סגירת **7 דליפות
|
||||
ידועות** תוך-כדי. ביקורת חוצת-קוד (#207) אימתה שכל ה-7 כבר **נסגרו במחזורים קודמים** (בעיקר
|
||||
FU-1/4/5/6/7 + גלי-ה-IA), ושהספ נשא תיאורי-הפרה מיושנים. ה-PR מיישר את הספ למצב-הקוד בפועל
|
||||
ומאמת כל סגירה בבדיקה. **אין כאן GAP/FU חדש — זו ביקורת-יישור, לא פתרון-מחדש (G2).**
|
||||
|
||||
| # | דליפה | invariant | סטטוס | FU | סגירה (קוד) | בדיקה |
|
||||
|---|-------|-----------|-------|-----|-------------|-------|
|
||||
| 1 | הלכות חוצות-קורפוס (#56) | INV-RET1/G5 (GAP-10) | ✅ סגור | FU-4 | `cl.source_kind` ב-`halacha_filters` בשתי הפונקציות (`db.py:7516,7519`) | `test_precedent_corpus_isolation.py` |
|
||||
| 2 | backlog-הלכות בלתי-נראה | INV-QA1/G10 (GAP-14) | ✅ סגור | FU-5 | health `halacha_backlog` (`app.py:2352-2364`) + כלי `extraction_status`/`halachot_pending` | — (health-endpoint) |
|
||||
| 3 | אין eval-harness | INV-RET4/G8 (GAP-11) | ✅ סגור | FU-5 | `scripts/eval_retrieval.py` (P/R/MRR/nDCG מול gold-set+baseline) | `eval_retrieval.py --self-test` ("ALL PASS") |
|
||||
| 4 | שער-ייצוא לא hard-block | INV-EX3/QA3/G10 (GAP-15) | ✅ סגור | FU-6 | `export_docx` בודק `qa_run_exists`+`get_critical_qa_failures` לפני exporter (`drafting.py:462-494`) | `test_export_qa_gate.py` |
|
||||
| 5 | מטא במסלול-פנימי | INV-ING3/G2 (GAP-02) | ✅ סגור | FU-1 | מסלול קנוני `ingest.ingest_document` מתזמן metadata+halacha יחד (`ingest.py:233-234`) | `test_unified_ingest.py` |
|
||||
| 6 | DOCX זוחל למקור-אמת | INV-EX1/G2 (GAP-17) | ✅ מגודר | FU-7 | חוזה: `active_draft_path`=אנקור בלבד; drift בדגל `cases.blocks_stale` (V22) | (חוזה+דגל; שארית health-check low-pri) |
|
||||
| 7 | cache-invalidation ב-UI | INV-UI5/IA (GAP-33) | ✅ סגור | FU-10/IA | `qc.invalidateQueries` על מוטציות (`web-ui/src/lib/api/*.ts`) + גלי-IA #130-132 | (TanStack Query) |
|
||||
|
||||
**שאריות (low-pri, מתועדות לא-חוסמות):** דליפה #6 — health-check שמתריע על `blocks_stale=true`
|
||||
עתיק (הדגל קיים ונאכף; חסר רק התרעת-נראות). אינה חוסמת את WS7; ניתן ל-FU-7-המשך.
|
||||
|
||||
Reference in New Issue
Block a user