docs(spec): 05-qa-review — QA gates + human gates
This commit is contained in:
195
docs/spec/05-qa-review.md
Normal file
195
docs/spec/05-qa-review.md
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
# 05 — בקרת איכות ושערים אנושיים (QA & Human Review)
|
||||||
|
|
||||||
|
קובץ-תחום זה כפוף ל-[חוקת המערכת](00-constitution.md) ומפרט את שלב **הביקורת** לפני
|
||||||
|
ייצוא: (1) **שערי-QA אוטומטיים** (`validate_decision` — 6 בדיקות) ו-(2) **שערים אנושיים**
|
||||||
|
(אישור הלכה, בחירת תוצאה, פידבק היו"ר). הוא אוכף את
|
||||||
|
[INV-G10](00-constitution.md#inv-g10-המערכת-מסייעת--שערים-אנושיים-הם-invariant)
|
||||||
|
(שערים אנושיים) ואת [INV-G11](00-constitution.md#inv-g11-תוכן-החלטה-מנומקת) (תוכן מנומק).
|
||||||
|
|
||||||
|
> **⚠ קובץ מעורב — שני מודלי-סמכות.** לפי החוקה (§3, §5):
|
||||||
|
> - **שערי-הממשל** (שערים אנושיים, שער-הייצוא) הם **invariants הנדסיים** במודל
|
||||||
|
> הממשל-שיפוטי → נושאים `מקורות:` (NCSC/JTC · CEPEJ 2018 · FJC) + `סטטוס: verified`.
|
||||||
|
> - **מכניקת בדיקות-התוכן** (מה הבדיקה האוטומטית בוחנת בפועל — רקע ניטרלי, ללא כפילות,
|
||||||
|
> כיסוי-טענות) היא **תוכן-משפטי** → נושאת `מקור-סמכות:` (היו"ר + מסמכי-הפרויקט +
|
||||||
|
> [04-analysis-writing.md](04-analysis-writing.md)), **ללא** מקורות חיצוניים וללא סטטוס.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. שערי-QA אוטומטיים — `validate_decision`
|
||||||
|
|
||||||
|
`validate_decision(case_number)` (wrapper ב-`tools/drafting.py:363`, נחשף ב-`server.py:551`)
|
||||||
|
טוען את בלוקי-ההחלטה והטענות מה-DB ומריץ **6 בדיקות**, אז כותב את התוצאות לטבלת
|
||||||
|
`qa_results` ומחזיר `passed` / `critical_failures` / `export_blocked`. הליבה:
|
||||||
|
`services/qa_validator.py:292` (`validate_decision`). כל בדיקה מחזירה
|
||||||
|
`{name, passed, errors, severity}`; `severity ∈ {critical, warning}`.
|
||||||
|
|
||||||
|
> **חישוב החסימה:** `critical_failures = Σ(not passed ∧ severity=="critical")`
|
||||||
|
> (`qa_validator.py:338`), ו-`export_blocked = critical_failures > 0`
|
||||||
|
> (`qa_validator.py:362`). בדיקת `warning` שנכשלת מורידה `passed=False` אך **אינה** חוסמת
|
||||||
|
> ייצוא. ראה [§3 / INV-QA3](#inv-qa3-החלטה-לא-מיוצאת-עם-כשל-קריטי-governance--g10).
|
||||||
|
|
||||||
|
### 1.1 ששת השערים
|
||||||
|
|
||||||
|
| # | בדיקה | מה בוחנת | severity | פונקציה (file:line) |
|
||||||
|
|---|-------|----------|----------|---------------------|
|
||||||
|
| 1 | `neutral_background` | רקע (בלוק ו) ללא מילות-שיפוט (`VALUE_WORDS`) וללא ציטוט-צד (`QUOTE_INDICATORS`) | **warning** | `check_neutral_background` — `qa_validator.py:66` |
|
||||||
|
| 2 | `claims_coverage` | כל טענה מבלוק ז נענתה בבלוק י (בדיקה סמנטית דרך Claude) | **critical** | `check_claims_coverage` — `qa_validator.py:107` |
|
||||||
|
| 3 | `weight_compliance` | משקל-מילים של כל בלוק בטווח לפי סוג-ערר (`WEIGHT_RANGES`) | **warning** | `check_weight_compliance` — `qa_validator.py:177` |
|
||||||
|
| 4 | `structural_integrity` | בלוקי-חובה קיימים (ה, ז, י, יא) + בלוק י הוא הכבד ביותר | **critical** | `check_structural_integrity` — `qa_validator.py:206` |
|
||||||
|
| 5 | `no_duplication` | אין משפט מבלוק ו (>30 תווים) שחוזר מילה-במילה בבלוק י | **warning** | `check_no_duplication` — `qa_validator.py:235` |
|
||||||
|
| 6 | `sequential_numbering` | מספור-סעיפים רציף בכל הבלוקים, מתחיל ב-1, ללא פערים | **warning** | `check_sequential_numbering` — `qa_validator.py:261` |
|
||||||
|
|
||||||
|
### 1.2 דקויות חשובות (אל תניח — מהקוד)
|
||||||
|
|
||||||
|
- **רק 2 שערים קריטיים** חוסמים ייצוא: `claims_coverage` ו-`structural_integrity`. שאר
|
||||||
|
הארבעה הם `warning` (כולל `neutral_background`!) — `qa_validator.py:86, 202, 240, 286`.
|
||||||
|
- **`claims_coverage` סובלני ל-20%:** עובר אם `len(missing) ≤ total*0.2`
|
||||||
|
(`qa_validator.py:170`). מסנן לטענות `appellant`/`respondent` שאינן מבלוק-ז
|
||||||
|
(`qa_validator.py:120-129`), כי טענות `committee`/`permit_applicant` הן עמדות-הגנה ולא
|
||||||
|
דורשות מענה. כשל-פענוח של Claude → fallback `passed=True` כדי לא לחסום ייצוא על תקלת-LLM
|
||||||
|
(`qa_validator.py:148-152`).
|
||||||
|
- **`neutral_background` ריק = עובר:** בלוק ו ריק/חסר מחזיר `passed=True`
|
||||||
|
(`qa_validator.py:69`). הבדיקה היא lexical (רשימת-מילים + regex), לא סמנטית.
|
||||||
|
- **`no_duplication` תופס רק חזרה מילה-במילה** (substring) — לא פרפרזה.
|
||||||
|
- כל ריצה **מנקה** את `qa_results` הקודמות של התיק ואז כותבת מחדש (`qa_validator.py:344-357`).
|
||||||
|
|
||||||
|
### 1.3 שערי-התוכן מתפעלים את WR1–WR3
|
||||||
|
|
||||||
|
שלוש מ-6 הבדיקות הן ההפעלה האוטומטית (חלקית) של ה-invariants של התוכן ב-
|
||||||
|
[04-analysis-writing.md](04-analysis-writing.md):
|
||||||
|
|
||||||
|
| שער QA | invariant-תוכן | פער (אוטומטי מול הגדרה) |
|
||||||
|
|--------|----------------|--------------------------|
|
||||||
|
| `neutral_background` | [INV-WR1](04-analysis-writing.md#inv-wr1-רקע-ניטרלי-בלוק-ו--עובדות-בלבד) | lexical בלבד — לא תופס שיפוט עקיף; warning, לא critical |
|
||||||
|
| `no_duplication` | [INV-WR2](04-analysis-writing.md#inv-wr2-ללא-כפילות-בלוק-י-מפנה-לא-חוזר) | מילה-במילה בלבד — לא תופס כפילות מנוסחת-מחדש |
|
||||||
|
| `claims_coverage` | [INV-WR3](04-analysis-writing.md#inv-wr3-מענה-לכל-טענה-של-הצד-המפסיד) | סמנטי (Claude), סובלני ל-20% חוסר |
|
||||||
|
|
||||||
|
ראה [INV-QA4](#inv-qa4-שערי-התוכן-האוטומטיים-אוכפים-את-wr1wr3-content--g11). WR4 (טענות
|
||||||
|
מקוריות) ו-WR5 ("מבחן-השופט") **אינם** מכוסים על-ידי `validate_decision` — WR4 נאכף
|
||||||
|
בנקודת-החילוץ (`extract_claims`), WR5 הוא שער-איכות אנושי/agent. הסוכן `legal-qa`
|
||||||
|
(ראה [X4-agents.md](X4-agents.md)) מוסיף שערים ידניים מעבר ל-6 הקוד-יים (קול-דפנה,
|
||||||
|
שאילתות-קורפוס, צירוף-פסיקה) — `.claude/agents/legal-qa.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. שערים אנושיים — היו"ר מכריעה
|
||||||
|
|
||||||
|
המערכת מסייעת; ההכרעה היא של היו"ר. שלושה שערים אנושיים מובנים בקוד-הזרימה ואינם ניתנים
|
||||||
|
לעקיפה אוטומטית (זהו [INV-G10](00-constitution.md#inv-g10-המערכת-מסייעת--שערים-אנושיים-הם-invariant)).
|
||||||
|
|
||||||
|
### 2.1 אישור הלכה (halacha approval)
|
||||||
|
|
||||||
|
הלכות מחולצות אוטומטית מפסיקה (`halacha_extractor.py`), אך **נכנסות כ-`pending_review`
|
||||||
|
ובלתי-נראות לחיפוש** עד אישור היו"ר:
|
||||||
|
|
||||||
|
- **כתיבה:** `db.add_halacha` קובע `review_status = "approved" if auto_approve else
|
||||||
|
"pending_review"` (`db.py:3003`), כאשר `auto_approve` נגזר מסף-ביטחון
|
||||||
|
`HALACHA_AUTO_APPROVE_THRESHOLD` (ברירת-מחדל `0.80`, `config.py:111`). הלכות מתחת לסף
|
||||||
|
נשארות `pending_review`.
|
||||||
|
- **שער-האישור:** `halacha_review(halacha_id, status, reviewer="דפנה", …)`
|
||||||
|
(`tools/precedent_library.py:291`, נחשף ב-`server.py:298`) — היו"ר מאשרת/דוחה/עורכת.
|
||||||
|
`status ∈ {pending_review, approved, rejected, published}` (`precedent_library.py:311`).
|
||||||
|
- **תור-ההמתנה:** `halachot_pending(limit=100)` (`precedent_library.py:335`) מחזיר את
|
||||||
|
`review_status='pending_review'`.
|
||||||
|
- **חשיפה רק לאחר אישור:** החיפוש מסנן `h.review_status IN ('approved','published')`
|
||||||
|
(`db.py:3168` ו-`db.py:3401`) — הלכה שלא אושרה **לעולם** לא עולה בתוצאות.
|
||||||
|
|
||||||
|
### 2.2 בחירת תוצאה (outcome selection)
|
||||||
|
|
||||||
|
`set_outcome(case_number, outcome, reasoning="")` (`tools/workflow.py:145`,
|
||||||
|
`server.py:646`) — היו"ר קובעת `outcome ∈ {rejected, accepted, partial}`
|
||||||
|
(`workflow.py:163`). זוהי **הכרעה משפטית**: היא קודמת לכתיבת-הטיוטה וקובעת את מסלול-הדיון
|
||||||
|
(ראה [04-analysis-writing.md](04-analysis-writing.md) §3). אין נתיב שבו המערכת בוחרת תוצאה
|
||||||
|
לבד — אם לא סופק נימוק, המערכת מציעה כיווני-נימוק (`brainstorm`), אך הבחירה נשארת אנושית.
|
||||||
|
|
||||||
|
### 2.3 פידבק היו"ר (chair feedback)
|
||||||
|
|
||||||
|
- `record_chair_feedback(case_number, feedback_text, block_id, category, …)`
|
||||||
|
(`tools/workflow.py:348`, `server.py:896`) — מתעד הערת-דפנה; `category` מתוך
|
||||||
|
`{missing_content, wrong_tone, wrong_structure, factual_error, style, other}`
|
||||||
|
(`workflow.py:367`).
|
||||||
|
- `list_chair_feedback(case_number, category, unresolved_only=True)`
|
||||||
|
(`tools/workflow.py:393`, `server.py:910`) — שליפה לסקירה.
|
||||||
|
|
||||||
|
הפידבק מזין את לולאת-הלמידה ([07-learning.md](07-learning.md)) ואת
|
||||||
|
[legal-decision-lessons.md](../legal-decision-lessons.md). זהו שיפוט-אנושי על איכות —
|
||||||
|
לעולם לא מוסק או מוחל אוטומטית.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Invariants של התחום
|
||||||
|
|
||||||
|
### INV-QA1: אישור הלכה הוא שער אנושי (governance →G10)
|
||||||
|
**כלל:** אישור הלכה הוא **הכרעה ידנית של היו"ר**. הלכות שחולצו אוטומטית הן
|
||||||
|
`pending_review` עד שהיו"ר מאשרת; **רק הלכות מאושרות** (`approved`/`published`) עולות
|
||||||
|
בחיפוש. תור-ההמתנה חייב להיות **נראה** (`halachot_pending`) כדי שאישור-חסר לא יישאר סמוי.
|
||||||
|
**מקורות:** NCSC/JTC — *Principles & Practices for AI Use in Courts* (human-in-the-loop) ·
|
||||||
|
Council of Europe / CEPEJ (2018, under user control) · Federal Judicial Center —
|
||||||
|
*Judicial Writing Manual* (2d ed.) | סטטוס: verified
|
||||||
|
**אכיפה:** ברירת-מחדל `pending_review` בכתיבה (`db.py:3003`) + סינון
|
||||||
|
`review_status IN ('approved','published')` בכל query (`db.py:3168`, `db.py:3401`) + שער-אישור
|
||||||
|
`halacha_review` (`precedent_library.py:291`).
|
||||||
|
**הפרה ידועה:** 10/19 הלכות מאושרות — שער-ידני שקוף בלי נראות-backlog; ההפרש התגלה במקרה →
|
||||||
|
ממצא ל-[audit](../audit-report.md) (ראה גם [INV-G10](00-constitution.md#inv-g10-המערכת-מסייעת--שערים-אנושיים-הם-invariant)).
|
||||||
|
|
||||||
|
### INV-QA2: בחירת-תוצאה ופידבק הם שערים אנושיים (governance →G10)
|
||||||
|
**כלל:** **בחירת התוצאה** (`set_outcome`) ו**פידבק-היו"ר** (`record_chair_feedback`) הם
|
||||||
|
שערים אנושיים — **לעולם לא אוטומטיים**. המערכת מסייעת (מציעה כיווני-נימוק, מתעדת הערות),
|
||||||
|
אך ההכרעה והשיפוט-על-האיכות הם של היו"ר.
|
||||||
|
**מקורות:** NCSC/JTC — *Principles & Practices for AI Use in Courts* ("never replace human
|
||||||
|
judgment") · Council of Europe / CEPEJ (2018, under user control) · Federal Judicial
|
||||||
|
Center — *Judicial Writing Manual* (2d ed.) | סטטוס: verified
|
||||||
|
**אכיפה:** `set_outcome` דורש `outcome` מפורש מהיו"ר (`workflow.py:145-165`);
|
||||||
|
`record_chair_feedback`/`list_chair_feedback` מתעדים בלבד (`workflow.py:348, 393`) — אין
|
||||||
|
מסלול-קוד שמסיק תוצאה או פידבק לבד.
|
||||||
|
**הפרה ידועה:** —
|
||||||
|
|
||||||
|
### INV-QA3: החלטה לא מיוצאת עם כשל קריטי (governance →G10)
|
||||||
|
**כלל:** החלטה **אינה ניתנת לייצוא** כל עוד שער-QA **קריטי** נכשל
|
||||||
|
(`claims_coverage` או `structural_integrity`). `export_blocked` חייב להיבדק לפני ייצוא;
|
||||||
|
ייצוא בכשל-קריטי הוא הפרה. שערי-`warning` שנכשלים מתועדים אך אינם חוסמים.
|
||||||
|
**מקורות:** NCSC/JTC — *Principles & Practices for AI Use in Courts* (controlled, auditable
|
||||||
|
AI 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`); נאכף בשער-הזרימה
|
||||||
|
של הסוכן `legal-exporter` ("לעולם אל תייצא בלי `validate_decision` קודם", "בדוק שאין
|
||||||
|
כשלים קריטיים" — `.claude/agents/legal-exporter.md:71, 149`). קושר ל-[06-export.md](06-export.md).
|
||||||
|
**הפרה ידועה:** `export_docx` (`drafting.py:384`) **אינו** מריץ `validate_decision` בעצמו —
|
||||||
|
החסימה היא ברמת-הזרימה/agent, לא hard-block בקוד-הייצוא. פער זה → ראה [§4](#4-current-vs-target--ממצאי-audit) (audit).
|
||||||
|
|
||||||
|
### INV-QA4: שערי-התוכן האוטומטיים אוכפים את WR1–WR3 (content →G11)
|
||||||
|
**כלל:** שערי-התוכן האוטומטיים מתפעלים את invariants-התוכן: `neutral_background`↔
|
||||||
|
[WR1](04-analysis-writing.md#inv-wr1-רקע-ניטרלי-בלוק-ו--עובדות-בלבד) (רקע ניטרלי) ·
|
||||||
|
`no_duplication`↔[WR2](04-analysis-writing.md#inv-wr2-ללא-כפילות-בלוק-י-מפנה-לא-חוזר)
|
||||||
|
(ללא כפילות) · `claims_coverage`↔[WR3](04-analysis-writing.md#inv-wr3-מענה-לכל-טענה-של-הצד-המפסיד)
|
||||||
|
(מענה-לטענות). האכיפה האוטומטית היא **רצפה, לא תקרה** — WR4/WR5 וההבטים העדינים (שיפוט-עקיף,
|
||||||
|
כפילות מנוסחת-מחדש) נשארים בשיקול-הדעת האנושי (INV-QA1–QA3).
|
||||||
|
**מקור-סמכות:** היו"ר (עו"ד דפנה תמיר) + [04-analysis-writing.md](04-analysis-writing.md)
|
||||||
|
(INV-WR1–WR3) + `mcp-server/src/legal_mcp/services/qa_validator.py` (הבדיקות בפועל).
|
||||||
|
**אכיפה:** `check_neutral_background` (`qa_validator.py:66`), `check_no_duplication`
|
||||||
|
(`qa_validator.py:235`), `check_claims_coverage` (`qa_validator.py:107`).
|
||||||
|
**הפרה ידועה:** —
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Current vs Target — ממצאי-audit
|
||||||
|
|
||||||
|
- **Halacha backlog בלתי-נראה (INV-QA1):** 10/19 הלכות מאושרות; 9 נשארו `pending_review`
|
||||||
|
ולא עלו בחיפוש. השער עבד כשורה — אך חוסר-נראות של ה-backlog הסתיר את הפער עד שהתגלה
|
||||||
|
במקרה. **Target:** מדד-נראות (count `pending_review`) כחלק מבדיקת-בריאות, לא רק
|
||||||
|
`halachot_pending` בדרישה. ראה [audit](../audit-report.md).
|
||||||
|
- **שער-ייצוא אכוף-זרימה ולא אכוף-קוד (INV-QA3):** `export_docx` לא קורא ל-`validate_decision`;
|
||||||
|
החסימה תלויה במשמעת הסוכן `legal-exporter`. **Target:** hard-block בתוך `export_docx`
|
||||||
|
(בדיקת `qa_results`/`export_blocked` לפני כתיבת DOCX) כדי שלא יהיה ניתן לעקיפה.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. הפניות-אחיות
|
||||||
|
|
||||||
|
- [00-constitution.md](00-constitution.md#inv-g10-המערכת-מסייעת--שערים-אנושיים-הם-invariant) —
|
||||||
|
INV-G10 (שערים אנושיים) + INV-G11 + הבחנת שתי-הסמכויות.
|
||||||
|
- [04-analysis-writing.md](04-analysis-writing.md) — INV-WR1–WR5 שהשערים האוטומטיים מתפעלים.
|
||||||
|
- [06-export.md](06-export.md) — ייצוא DOCX (השלב אחרי המעבר בשער הקריטי).
|
||||||
|
- [07-learning.md](07-learning.md) — לולאת פידבק-היו"ר + Hermes שמעדכנת lessons/SKILL.
|
||||||
|
- [X4-agents.md](X4-agents.md) — הסוכן `legal-qa` (שערים ידניים נוספים) ו-`legal-exporter`.
|
||||||
|
- [X5-audit-provenance.md](X5-audit-provenance.md) — audit-trail לפלטי-AI ועקיבוּת-מקור.
|
||||||
Reference in New Issue
Block a user