תיקון: כל העלאת קובץ עם שם עברי נכשלה ב-500 תחת backend s3-only. השורש:
`ingest._stage_file` מצרף את שם-הקובץ המקורי כ-S3 object metadata
(`metadata={"filename": src.name}`), ו-`S3Backend.put_bytes` העביר אותו כמו-שהוא
ל-`put_object`. botocore אוכף ASCII-only על S3 metadata → ParamValidationError →
500. שם עברי כמו "יומון 5167 - 11.6.26.pdf" שבר כל upload. נחשף ב-cutover ל-s3-only
(2026-06-11): קליטת היומונים (וגם כל מסמך/פסיקה עם שם עברי) הפסיקה לעבוד; היומון
האחרון שנקלט (5165, 9.6) היה לפני ה-cutover.
התיקון (נרמול-במקור, G1; בשכבת-האחסון היחידה, INV-STG2):
- `_ascii_metadata` מקודד ערכי-metadata לא-ASCII ב-percent-encoding (lossless,
שחזור עם urllib.parse.unquote); ASCII רגיל עובר ללא שינוי (קריאוּת).
- `S3Backend.put_bytes` מחיל אותו על כל ערכי ה-Metadata.
בדיקות: test_ascii_metadata_encodes_hebrew (helper) +
test_s3_put_bytes_sends_ascii_metadata (משחזר את מסלול-הכשל מול fake put_object).
16 עוברות בקובץ.
Invariants: מקיים G1 (נרמול-במקור, לא תיקון-בקריאה), INV-STG2 (שם-קובץ עברי
כ-metadata ולא ככ-key), G2 (אין מסלול-אחסון מקביל — תיקון ה-choke-point היחיד).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The host pm2 supervisor imports legal_mcp.services.db from the host repo checkout,
which can lag main by many commits. Depending on the just-added db.set_drain_burst/
get_drain_burst would require the host checkout to be current. Use raw SQL via the
stable db.get_pool() instead — the supervisor now depends only on get_pool + the
drain_controls.burst_until column (the shared contract with the /operations API).
The container-side API keeps using the typed helpers (it ships the code in-image).
Invariants: G1/G2 unchanged (same single DB column, no parallel path).
The halacha-extraction backlog needs to be worked off the chair's leftover weekly
Claude quota on demand. This adds a MANUAL, time-boxed "burst" — run the drain
continuously now until a chosen deadline (default the upcoming Saturday 18:00 IL),
managed interactively from /operations — plus the permanent health-supervisor that
enforces it.
Backend (this PR; deploys via Coolify + host pm2):
- db: drain_controls.burst_until (SCHEMA_V37) + set_drain_burst/get_drain_burst/
get_drain_bursts. Single source of truth shared by the container-side /operations
API and the host-side supervisor.
- web: POST /api/operations/drains/{name}/burst (on→until|next-Sat-18:00, off→NULL),
and burst_until surfaced per-service in the /operations snapshot.
- scripts/halacha_drain_supervisor.py + legal-halacha-supervisor.config.cjs: pm2 cron
(*/15, zero Claude quota) — re-triggers idle drain, restarts a HUNG run (liveness =
per-chunk checkpoints, NOT log mtime), backs off on 429 until the parsed reset
(fresh-gated), verifies crash-safe staging. Reads burst_until from the DB; burst
auto-expires at the deadline (never bleeds into a fresh week).
UI (separate follow-up PR, after Claude Design approval): the /operations toggle +
date-picker that calls the burst endpoint.
Invariants: G1 (normalize at source — burst lives once in the DB, read by both
surfaces), G2 (no parallel control path — CAPTURE field on the existing
drain_controls + orchestrates the existing drain, not a new one), G12 (no Paperclip
touch), §6 (no silent error-swallow — burst-clear failure is surfaced as a note).
Picks up GET /api/cases/{case_number}/learning-status (PR #233) plus accumulated
schema drift from prior backend changes that never regenerated types.ts. tsc clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
אחרי העלאת החלטה סופית והרצת שני הפייפליינים האוטומטיים (למידת-קול,
חילוץ/אימות-הלכות), התיק לא הציג אם כל תהליך בוצע/הצליח/למה-נכשל. במיוחד
תקלת chair_name ריק (2026-06-12) שמפילה בשקט את העתק-ה-case_law → חילוץ-הלכות
לא מתחיל בכלל, בלי שזה גלוי. כעת מוצגות שתי אינדיקציות ליד כפתורי-ההרצה.
Backend (גזירה ממקור-יחיד, ללא מסלול-מעקב מקביל):
- SCHEMA_V36: draft_final_pairs.learning_run (JSONB) — שדה-תיעוד על פנקס-ההתאמה
(INV-LRN4), חותם את תוצאת-הריצה של פייפליין-הלמידה (succeeded/failed+סיבה+at).
- set_learning_run_outcome() — חיתום הצלחה/כישלון על ה-pair האחרון.
- case_learning_status() — גזירה read-only מ-draft_final_pairs/style_corpus/
decision_lessons/case_law/halachot: בוצע? הצליח? למה-לא? כמה הלכות חולצו.
- final_learning_pipeline.py — חותם outcome בהצלחה וב-except (surfaced, לא בלוע).
- חשיפה: case_get מוסיף learning_status (→MCP + /api/cases/{case}/details) +
endpoint ייעודי GET /api/cases/{case}/learning-status (אותה פונקציה — בלי כפילות).
UI (אושר דרך שער-העיצוב Claude Design — כרטיס 21-final-learning-status):
- useCaseLearningStatus (api/learning.ts) — hook + polling עדין בזמן in-flight.
- LearningStatusBadges — 2 שורות (למידת-קול / חילוץ-הלכות) עם badge + תת-שורה
(מס' לקחים · רישום-קורפוס / מס' הלכות + פירוק אושרו/ממתינות/נדחו / סיבת-כישלון).
- שילוב ב-drafts-panel תחת "החלטה סופית של היו״ר" + אינוולידציה בכפתורי-ההרצה.
אומת מול ה-DB החי: הצליח+5 הלכות (8174-12-24) · נכנס-אך-pending (1200-12-25) ·
לא-נכנס-לקורפוס (8125-09-24) · round-trip חיתום-כישלון. tsc/eslint נקיים.
Invariants: G1 (נרמול-במקור — גזירה, לא טלאי), G2 (אין מסלול מקביל — שדה על
הפנקס הקיים + exposer יחיד), INV-LRN4 (פנקס-ההתאמה), INV-IA1 (מקור-אמת יחיד).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ה-wakeup המיידי ל-CEO לחילוץ-הלכות הוא best-effort; כשהוא נכשל
(למשל churn-פריסה), הבקשה נשענת רק על הדריינר-הלילי והפריט נשאר
'pending' בלי שאיש רואה — עד ~16-18 שעות. מוסיף קטגוריה חמישית
ל-api_chair_pending שמציפה case_law עם halacha_extraction_status=
'pending' שכבר עבר את חלון-הדריינר (requested_at < now()-6h), כך
שכשל-שקט הופך לפריט-יו"ר גלוי במרכז-האישורים ("שלא יישכח").
שאילתת-מקור ישירה (תואם הדפוס), href ל-/precedents (שם כפתור
request-halachot מעיר CEO = retry). אפס שינוי-frontend — דף-האישורים
מרנדר categories גנרית (ApprovalCard לפי label/severity/count/href).
gate-free (לוגיקה/נתון בלבד). הסף 6h תכוונן.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
FU-1 (#214) הוסיף ל-halacha_panel_approve.py את הדגל --no-capture
ואת השימוש `if not args.no_capture` בשלב-הלכידה. אבל
final_halacha_pipeline.py קורא ל-hpa.main() עם Namespace שנבנה ביד
(limit/concurrency/apply בלבד) — בלי no_capture. לכן הרצת הצינור
("הרץ הלכות") קרסה ב-AttributeError בדיוק בשלב שמירת-הסבבים, אחרי
שה-apply כבר רץ → 0 סבבים נלכדו לתיק.
תוקן: הוספת `no_capture=False` ל-Namespace. אומת מקצה-לקצה על
8174-12-24 → "captured 49 panel rounds, errors=0".
audit: רק 2 מקומות בונים Namespace ביד לקריאת main() של סקריפט אחר —
זה (תוקן), ו-final_learning_pipeline.py→style_lesson_panel (נבדק, כל
ה-args מסופקים, תקין). אין באגים נוספים מהמחלקה הזו.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
הבעיה: בדף /missing-precedents לא ניתן היה לאתר פסיקה חסרה לפי מספר ההחלטה
החסרה עצמה (למשל 85074). השדה היחיד לחיפוש-תיק עשה get_case_by_number על
מספר ה-ערר שבו צוטטה הפסיקה — ולכן הקלדת מספר-הפסיקה החזירה רשימה ריקה,
למרות שהרשומה קיימת (ערר (ת"א 85074-04-25) ... status=open).
התיקון (הרחבת השדה הקיים, ללא עמוד/שדה חדש — בהנחיית חיים):
- db.list_missing_precedents: פרמטר q חדש — ILIKE על mp.citation +
mp.case_name + cited-in c.case_number (אינדקס-פרמטר יחיד, additive;
שאר הקוראים לא נוגעים).
- GET /api/missing-precedents: פרמטר q; case_id/case_number נשארים
מסננים-מדויקים לקוראים תכנותיים.
- web-ui: התווית "תיק (מספר ערר)" → "מספר תיק", placeholder
"85074 או 1017-03-26"; השדה שולח q (חיפוש חופשי) במקום case_number.
Debounce 350ms נשמר.
api:types לא חודש: ה-hook בונה את ה-querystring ידנית וה-response לא
השתנה; חידוש מול prod (שעוד לא נפרס) רק היה מושך drift לא-קשור.
בדיקות: tsc --noEmit נקי, eslint נקי על הקבצים שהשתנו, py_compile נקי.
Invariants: G2 (הרחבת היכולת הקיימת, לא מסלול-חיפוש מקביל), INV-IA1
(שער/דף יחיד לפסיקה-חסרה — בלי עמוד חדש), §6 (ללא בליעת-שגיאות).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
תיקון: העלאת פסיקה/החלטת-ועדה (precedent-library + internal-decisions) נכשלה
תחת backend s3-only עם "Package not found at '/data/...docx'" / "Converted file
not found". השורש: `ingest._stage_file` כותב את הקובץ דרך `storage.put_file`
ומחזיר נתיב-DATA_DIR, אבל תחת s3-only ה-blob נכתב רק ל-MinIO ואין עותק בדיסק —
ואז הצינור קרא את הנתיב ישירות מהדיסק (extract_text) → קובץ לא קיים. מסלול
תיקי-המקרה לא נפגע כי הוא שומר עותק-דיסק + mirror_file; רק מסלול _stage_file
המשותף קרא את ה-key כאילו הוא על הדיסק.
התיקון (נרמול-במקור, G1; קריאה דרך שכבת-האחסון, INV-STG1):
- `_stage_file` מחזיר עכשיו את ה-KEY (נתיב יחסי-DATA_DIR), לא Path.
- `ingest_document` ו-`digest_library` מאתרים נתיב-קריאה מקומי דרך
`storage.ensure_local` (עותק-דיסק תחת filesystem/dual; הורדה ל-temp תחת
s3-only) ומנקים את ה-temp ב-finally — בלי דליפה ל-/tmp.
- מולטימודל (PDF) קורא את אותו נתיב מקומי מאומת.
בדיקות: test_unified_ingest::test_ingest_reads_via_ensure_local_when_no_disk_copy
מדמה backend ללא עותק-דיסק ומוודא שהצינור משלים (נכשל מול הקוד הישן). 55 עוברות.
Invariants: מקיים INV-STG1 (קריאה/כתיבה רק דרך שכבת-האחסון), G1 (נרמול-במקור,
לא תיקון-בקריאה), G2 (אין מסלול מקביל — תיקון הצינור הקנוני).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
מבטל את ה-toggle "תור נקי / דורש תיקון-חילוץ" שבו "תור נקי" ריק
לגמרי (כל ההלכות-הנקיות נפתרו), והעבודה האמיתית חבויה מאחורי
הכפתור השני שגם מערבב התלבטות-פאנל עם פגמי-חילוץ. אושר ב-Claude
Design (כרטיס 19-halacha-queue-unified).
במקום זה — תור אחד, fetch אחד, פיצול client-side לפי **סוג-הפעולה**:
- "להכרעתך" = הלכות שהפאנל דן בהן (יש panel_round) או נקיות →
אשר/דחה, עם טבלת-ההתלבטות; ממוין פיצול-פאנל-תחילה (FU-3).
- "דורש תיקון-חילוץ" = מסומנות-דגל שלא עברו התלבטות → תיקון-חילוץ.
`useHalachotPending` אוחד לקריאה אחת (exclude_low_quality=false +
order_by_priority + cluster + include_equivalents + include_panel_round);
נוסף `isExtractionFixItem(h)` (= !panel_round && יש דגל). PendingPanel
מפצל ב-useMemo, segmented-control עם מוני שני הדליים. אפס שינוי-backend
(הפרמטרים כבר קיימים מ-#220/#222).
display-only, שער-אישור יחיד (INV-IA/G10). ולידציה: tsc + eslint נקי.
חלק מ-#133.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
תור-אישור-ההלכות הקיים (order_by_priority, #84.3) מקדם עכשיו את ההלכות
שהפאנל התלבט עליהן: split קודם, אחר-כך incomplete — התוויות בעלות-הערך
הגבוה ביותר ללולאת-הלמידה (הכרעת-היו"ר מפרקת אי-ודאות אמיתית ומזינה את
זיקוק-ה-rubric ב-FU-4). uncertainty-sampling על סיגנל-המחלוקת האמיתי של
הפאנל, לא רק confidence-החילוץ.
- list_halachot: LEFT JOIN לאחרון-הסבבים (DISTINCT ON latest round_ts מ-
halacha_panel_rounds) + מפתח-מיון ראשי CASE verdict split→0/incomplete→1/
else→2, לפני מפתחות #84.3 (corroboration→confidence→age). סבבים פה-אחד
ופריטים-ללא-סבב נשארים בזנב עם הסדר הקיים.
- panel_verdict נחשף בכל שורה (UI יכול לתייג "פיצול" + ביקורת-סדר).
- שימוש חוזר בדגל order_by_priority הקיים ובטאב הקיים — בלי מסלול/דגל
מקביל (G2). ה-UI כבר מבקש order_by_priority=true → אפס שינוי-UI, אין
צורך בשער-עיצוב.
- test_halacha_priority_panel_order.py: 3 בדיקות offline (SQL-capture) —
מפתח-מחלוקת ראשי בעדיפות, FIFO ללא דליפת-CASE, panel_verdict נבחר.
Invariants: INV-G10 (capture-only, לא משנה review_status) · G1/G2 ·
INV-IA (אותו שער/טאב). רגרסיה: 76 בדיקות עברו.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
One-time host migration (executed 2026-06-12): adds the missing 2-digit month
to 11 case numbers (and corrects 1046-26 → 1024-02-26, a wrong serial).
All legal-ai FKs are on cases.id (UUID) → untouched. The script atomically
migrates, per case, everything that embeds the number as TEXT:
· cases.case_number + every column containing 'cases/{old}/' (file_path AND
image_thumbnail_path — the latter is a DATA_DIR-relative storage key with
no '/data' prefix, hence the slash-less needle)
· disk dir + case.json
· MinIO keys across 3 buckets (legal-immutable = WORM, copy-only)
· Gitea repo rename + local .git remote + description
· Paperclip project name
For the 4 archived cases whose final was ingested, the canonical number is
propagated to the precedent + style corpora identifier fields (case_law,
style_corpus, style_exemplars, citations) per chair decision — document
content / full_text / OCR text is left as the historical record.
Verified: 0 stale identifier/path refs across all 11; documents, thumbnails,
drafts, Gitea, Paperclip all resolve under the new numbers. Per-case backups
in data/audit/renumber-*.json.
Invariants: G1 (normalise at source — single rename op, not read-time patch),
G2 (no parallel path — reuses the app's DB pool + storage semantics),
G12 (Paperclip touched only via its declared surface).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
מציג את התלבטות 3-השופטים (הצבעה+נימוק לכל לינאז' + ה-verdict)
בתוך כרטיס-האישור הקיים של דפנה ב-/precedents → "ממתין לאישור",
כדי שהכרעתה — תווית-הזהב שהלולאה לומדת ממנה — תהיה מיודעת ב*למה*
הפאנל נחלק. אושר ב-Claude Design (כרטיס 18-halacha-deliberation).
Backend (opt-in, ברירת-מחדל off — קוראים קיימים לא מושפעים):
- db.list_halachot(include_panel_round=True) → _annotate_panel_rounds
מצרף את הסבב האחרון מ-halacha_panel_rounds (DISTINCT ON, latest).
- GET /api/halachot?include_panel_round=true.
Frontend:
- Halacha.panel_round (טיפוס ידני; ה-endpoint מחזיר dict).
- תור-הסקירה (useHalachotPending) מבקש include_panel_round בשני
הדליים (clean=keep, needsFix=nli/entailed).
- רכיב PanelDeliberation: טבלת 3-שופטים (✓נתמך/✗הכלל-חורג + נימוק),
תג-ורדיקט "פיצול 2:1", ושורת "שורש המחלוקת" (קפדני↔תמצית) רק
בפיצול-entailment. מוזרק אחרי רשת הכלל/ציטוט.
שער יחיד — אין עמוד/שער חדש (INV-IA/G10); display-only, לא נוגע
ב-review_status. ולידציה: py_compile + tsc --noEmit + eslint נקיים;
בדיקה פונקציונלית: panel_round מצורף ל-6 שיש להן סבב, 1994 בלי.
חלק מ-#133 (FU-2). דורש deploy + (אופ') npm run api:types אחרי.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
נוהל-יו"ר (2026-06-11): מבנה מספר-תיק = <סידורי>-<חודש>-<שנה>, ואורך הסידורי
מקודד את סוג-ההליך — 4 ספרות = ערר, 5 ספרות = בל"מ. הספרה הראשונה ממשיכה
לקבוע תחום בשני האורכים (1→רישוי, 8→היטל, 9→פיצויים). הכלל חד-כיווני:
5-ספרתי הוא תמיד בל"מ; 4-ספרתי אינו מחייב ערר (בל"מ-מורשת מזוהה מהנושא).
הבאג שדיווח עליו היו"ר: חיפוש פסיקה-חסרה לפי מספר-תיק החזיר 404 על כל ערך
שאינו תיק קיים — שבר את הטבלה תוך כדי הקלדה ועל מספרי 5-ספרות.
תיקונים:
- web/app.py: GET /api/missing-precedents — מסנן case_number שלא תאם תיק מחזיר
רשימה ריקה (200), לא 404. סמנטיקה תקינה ל-collection-filter.
- missing-precedents/page.tsx: debounce (350ms) על שדות-הסינון — קוורי אחד
אחרי שמפסיקים להקליד, לא אחד לכל הקשה.
- practice_area.py: regex סידורי \d{4}→\d{4,5}; case_serial_digits() +
is_blam_by_number() (5⇒בל"מ); derive_subtype_with_blam ו-derive_proceeding_type
מזהים בל"מ גם מ-5-ספרות (בנוסף לנושא). callers: cases.py, internal_decisions.py.
- proofreader.py: דפוסי חילוץ-שם-קובץ \d{3,4}→\d{3,5}.
- web-ui: practice-area.ts (מראָה ל-backend), schemas/case.ts (regex
serial-month-year, 4-or-5 ספרות, superRefine 5⇒בל"מ), placeholder בוויזרד.
- תיעוד: docs/spec/X1-identifiers.md §1א + legal-ai/CLAUDE.md.
Invariants: מקיים G1 (נרמול-במקור — ספרה ראשונה כמקור-אמת יחיד לתחום),
G2 (מסלול-סיווג יחיד, אין כפילות), INV-DM/X1 (מפתח קנוני + proceeding_type).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
המשך ל-#215. תור-הסקירה האמיתי (list_halachot) מסנן pending_review בלבד —
deferred ("נדחה למועד", #84 snooze) מוסט במכוון מהתור הפעיל. לכן ספירתו
כ"ממתין" צבעה שורות אדום על עבודה שדפנה כבר הסיטה הצידה — בדיוק ההטעיה
ש-#215 בא לתקן.
- backend: pending_count = pending_review בלבד (היה pending_review+deferred);
deferred_count חדש ונפרד. אותה שאילתה, מקור-אמת יחיד (G2).
- UI: deferred מוצג כמקטע מושתק (⏸ N) רק כשקיים — לא צובע אדום, לא נספר
בממתינות. הצבע האדום + רקע-השורה מונעים מ-pending_count (=pending_review)
בלבד, בעקביות עם התור.
Invariants: G2 (ספירה ממקור-אמת יחיד תואמת-תור). שינוי-UI לפי החלטת היו"ר.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
דף /archive הציג תיקים בסדר updated_at במקום לפי תאריך-הארכוב, למרות
שעמודת "תאריך ארכוב" סומנה כממוינת. השורש: list_cases() החזיר תמיד
ORDER BY updated_at DESC, וההסתמכות על מיון-בדפדפן (TanStack) לא הבטיחה
את הסדר בטעינה הראשונית.
התיקון: כש-archived_only=True → ORDER BY archived_at DESC NULLS LAST.
הסדר הופך server-authoritative; לא נוגע ברשימה הפעילה ולא ב-MCP tool
(שאינו מעביר archived_only).
Invariants: G1 (נרמול-במקור — סדר נקבע בשאילתה, לא תיקון-בקריאה),
G2 (לא מסלול-מקביל — אותו list_cases), INV-IA* (מקור-אמת יחיד לרשימה).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
כל הכרעת keep/drop חדה של היו"ר על הלכה שהפאנל כבר שפט (יש לה שורה
ב-halacha_panel_rounds) פולטת seed gold-set מתויג-יו"ר — הסיגנל היחיד
שמותר ללולאת הלמידה ללמוד ממנו. לימוד מהצבעות-הפאנל-עצמן = echo-chamber
ואסור; לכן הזרע נטבע אך-ורק מהכרעה אנושית.
- db.seed_goldset_from_chair(): capture-only, idempotent (UPSERT על
batch='chair-live', tagged_by='chair'), לעולם לא נוגע ב-halachot ולא
זורק שגיאה לתוך השער (INV-G10). ממפה approved/published→keep,
rejected→drop; deferred/pending_review = נודניק, בלי seed.
- db._chair_seed_label(): שער טהור (בלי DB) → guard echo-chamber
unit-testable; מסנן reviewer מכונה (panel:* / corroborated*).
- מחובר ב-db layer (update_halacha + update_halachot_batch) כך שכל
מסלולי-השער מתכנסים (G1 נרמול-במקור, G2 בלי מסלול מקביל). הפאנל
משתמש ב-SQL גולמי ולא ב-update_halacha → אין echo-chamber מבני.
- מצריך שורת-פאנל קודמת: ערך-הזרע הוא זוג (הצבעות-פאנל ⋈ הכרעת-יו"ר)
שמזין זיקוק-rubric (FU-4) ומדידה (FU-5).
- test_chair_seed_gate.py: 10 בדיקות offline על מדיניות-השער + guard.
Invariants: INV-G10 (שער-אישור יחיד, capture-only) · INV-LRN1
(propose-only — אין auto-commit) · G1/G2 · anti-echo-chamber (#133).
אין UI/שער חדש (INV-IA). תצוגת-הצבעות-הפאנל ב-HalachaReviewPanel
(אופציונלי) נדחית — מצריכה שער-עיצוב Claude Design.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
התג בספריית-הפסיקה הציג "approved/total" — total כלל גם הלכות שנדחו,
כך ש-17/27 נקרא כאילו 10 ממתינות בעוד שבפועל הן נדחו. כעת:
- backend: list_external_case_law מחזיר pending_count (pending_review+deferred)
ו-rejected_count לצד approved_count (approved+published). מקור-אמת אחד
לספירה, אותה שאילתה — אין מסלול מקבילי (G2).
- UI: התג מציג 17/0/10 (מאושר/ממתין/נדחה), צבעי-משמעות, tooltip מפרש.
ממתין נצבע אדום-בולט רק כשגדול מ-0.
- UI: שורה עם הלכות ממתינות (pending_count>0) מקבלת רקע אדמדם דרך
rowClassName() — חל על שורות פסיקה ועל שורות ועדות-ערר.
Invariants: G2 (ספירה ממקור-אמת יחיד, ללא מסלול מקבילי). שינוי-UI ויזואלי
לפי אפיון מפורש של היו"ר (שער-עיצוב).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
לולאת ה-active-learning זקוקה לסיגנל ללמוד ממנו, אבל הפאנל
(halacha_panel_approve.py) זרק עד כה את הצבעות-3-השופטים ואת
ההנמקות — שרד רק review_status הסופי על halachot. בלי
ההצבעות+הנימוקים אין דרך לזקק rubric משופר.
FU-1:
- טבלה חדשה halacha_panel_rounds (SCHEMA_V35) — שורה לכל
(הלכה, סבב): הצבעה+נימוק לכל לינאז' (claude/deepseek/gemini),
ה-verdict, ומה הריצה עשתה (applied_action), apply_mode.
במתכונת עמודות-הפאנל של halacha_goldset.
- db.insert_panel_round() — helper כתיבה (capture-only).
- halacha_panel_approve.py: שומר את התשובות הגולמיות (במקום
לזרוק את הנימוק), מוסיף reason ל-NLI_SYSTEM, וכותב סבב לכל
פריט בשני המצבים (dry-run ו---apply). --no-capture לדילוג.
capture-only: לעולם לא נוגע ב-halachot — שער-היו"ר ב-/precedents
נשאר מקור-האמת היחיד (INV-G10). ה-seed ללמידה נוצר בהצלבה מול
הכרעת-היו"ר המאוחרת על אותה הלכה (FU-2).
Invariants: מקיים INV-G10 (capture-only, שער-יו"ר יחיד),
INV-LRN1/3 (לכידה-מבנית; propose-only — אין auto-commit),
G1 (לכידה-במקור), G2 (יכולת חדשה, לא מסלול-מקביל),
G12 (לא נוגע ב-Paperclip port). חלק מ-#133.
smoke (dry-run --limit 8): 6 nli captured, errors=0, נימוקים
מלאים מ-3 השופטים.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>