feat(learning): חיווט אוטונומי לכפתורי מסלול-הסופי — סקריפט-תזמור אחד לכל שלב
הכפתורים "הרץ למידת-קול"/"הרץ אימות-הלכות" מעירים את הרמס, ובמקום שהסוכן (DeepSeek) ירכיב כמה קריאות-כלי (שביר), הוא מריץ עכשיו פקודה דטרמיניסטית אחת. חדש: - scripts/final_learning_pipeline.py — (1) ingest_final_version עם נתיב-הסופי (מדלג אם הזוג כבר analyzed; --force לחידוש), (2) רישום לקורפוס-הסגנון (idempotent — סוגר את הפער שפאנל-הסגנון דרש corpus_id), (3) style_lesson_panel --apply. --dry-run להרצה בטוחה. - scripts/final_halacha_pipeline.py — extract_internal_citations → corroboration.build_all → halacha_panel_approve --apply. --dry-run / --limit. briefs הרמס (web/paperclip_client._curator_task_brief) פושטו לפקודה-אחת לכל task — חסין מול הרצת-סוכן. תוקנו שני הפערים שזוהו: ingest דרש file_path, ופאנל-הסגנון דרש style_corpus. נלווה: תיקון help מיושן של halacha_panel_approve (--apply מחווט). SCRIPTS.md. אומת: שני ה-pipelines רצו dry-run על בל"מ 8126-03-25 (skip-ingest, קורפוס, פאנלים) בהצלחה. Invariants: INV-LRN1/LRN5/G10 (הפיך, שער-יו"ר ידני נשמר), INV-DM7. G2 — תזמור של יכולות קיימות, לא מסלול-מקביל. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
87
scripts/final_halacha_pipeline.py
Normal file
87
scripts/final_halacha_pipeline.py
Normal file
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env python3
|
||||
"""One-shot LOCAL pipeline for the 'run-halacha' button (halacha validation).
|
||||
|
||||
The /api/cases/{case}/final/run-halacha endpoint wakes the Hermes curator, which
|
||||
runs THIS single deterministic command (the 3-judge panel uses local DeepSeek+Gemini
|
||||
keys + the local claude CLI, so it can't run inside the container).
|
||||
|
||||
Steps:
|
||||
[1] extract_internal_citations(chair) → links the citation graph for the chair's
|
||||
decisions (idempotent; ON CONFLICT DO NOTHING).
|
||||
[2] corroboration_rebuild → builds the citation-treatment signal and applies the
|
||||
corroborated→approved / overruled→pending policy (X11 Phase 2).
|
||||
[3] halacha_panel_approve --apply → 3 judges (Opus+DeepSeek+Gemini); agreement
|
||||
auto-approves/rejects (reversible, CSV-backed); splits/defects → chair (INV-G10).
|
||||
|
||||
NB: per-precedent halacha extraction for newly-cited precedents is NOT automated here
|
||||
(it needs each cited precedent to be in the library with a known case_law_id) — the
|
||||
chair drives that from /precedents when a missing precedent is added.
|
||||
|
||||
Local-only. Idempotent. The panel pass over the full pending queue can take minutes.
|
||||
|
||||
cd ~/legal-ai/mcp-server
|
||||
.venv/bin/python ../scripts/final_halacha_pipeline.py --case 8126-03-25
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
from argparse import Namespace
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from legal_mcp.services import corroboration, db # noqa: E402
|
||||
from legal_mcp.tools.citations import extract_internal_citations # noqa: E402
|
||||
|
||||
|
||||
async def main(args: argparse.Namespace) -> int:
|
||||
case_number = args.case
|
||||
case = await db.get_case_by_number(case_number)
|
||||
if not case:
|
||||
print(f"✗ תיק {case_number} לא נמצא")
|
||||
return 1
|
||||
chair = case.get("chair_name") or "דפנה תמיר"
|
||||
|
||||
# [1] citation graph
|
||||
print(f"[1/3] extract_internal_citations (chair={chair})…", flush=True)
|
||||
raw = await extract_internal_citations(chair_name=chair, limit=0)
|
||||
try:
|
||||
d = json.loads(raw).get("data", {})
|
||||
print(f" ✓ extracted {d.get('extracted')} · linked {d.get('linked')} "
|
||||
f"· new {d.get('new')}")
|
||||
except Exception:
|
||||
print(f" (citations returned: {str(raw)[:160]})")
|
||||
|
||||
# [2] corroboration signal + policy (whole corpus backfill) — skipped on dry-run
|
||||
if args.dry_run:
|
||||
print("[2/3] corroboration_rebuild — מדולג (dry-run)")
|
||||
else:
|
||||
print("[2/3] corroboration_rebuild (backfill)…", flush=True)
|
||||
try:
|
||||
cr = await corroboration.build_all()
|
||||
print(f" ✓ {cr}")
|
||||
except Exception as e:
|
||||
print(f" ⚠ corroboration failed (non-fatal): {e}")
|
||||
|
||||
# [3] three-judge halacha panel
|
||||
apply = not args.dry_run
|
||||
print(f"[3/3] halacha_panel_approve {'--apply' if apply else '(dry-run)'} "
|
||||
f"(Opus+DeepSeek+Gemini)…", flush=True)
|
||||
import halacha_panel_approve as hpa
|
||||
rc = await hpa.main(Namespace(limit=args.limit, concurrency=6, apply=apply))
|
||||
print("\n✓ pipeline-אימות-הלכות הושלם" + (" (dry-run)" if args.dry_run else ""))
|
||||
return rc or 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
ap = argparse.ArgumentParser(description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument("--case", required=True, help="case_number, e.g. 8126-03-25")
|
||||
ap.add_argument("--limit", type=int, default=0,
|
||||
help="cap pending halachot judged (0 = full queue)")
|
||||
ap.add_argument("--dry-run", dest="dry_run", action="store_true",
|
||||
help="citations only; skip corroboration writes; panel in dry-run")
|
||||
raise SystemExit(asyncio.run(main(ap.parse_args())))
|
||||
Reference in New Issue
Block a user