Commit Graph

111 Commits

Author SHA1 Message Date
2972ef74a4 Merge pull request 'feat(digests): digest_kind classification — robust extraction for all issue types (X12)' (#141) from worktree-digest-kind into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m58s
2026-06-08 06:02:36 +00:00
83d1a8253c feat(digests): digest_kind classification — robust extraction for all issue types (X12)
~2% מגיליונות "כל יום" הם לא-הכרעות (עדכוני-חקיקה/הודעות/ברכות) ללא ruling →
החילוץ ה-decision-centric החזיר ריק → both-empty → מחזורי ב-self-heal.

- SCHEMA_V32: `digest_kind` (decision/announcement/other) + backfill legacy בזול
  (יש citation→decision, אחרת announcement) — לפני שה-self-heal מסתמך עליו.
- extractor: prompt מסווג + מחלץ תמיד concept/headline/summary; underlying_* רק
  ל-decision. extract מנרמל digest_kind.
- enrich: שומר digest_kind; חילוץ מוצלח תמיד מסתיים ב-kind לא-ריק (ברירת-מחדל
  לפי citation אם המודל השמיט).
- drain self-heal: הגדרת-כשל = completed עם digest_kind='' (במקום both-empty) →
  הודעות לא מנוסות-מחדש לנצח.
- db: digest_kind ב-_DIGEST_COLS + update-whitelist (זורם ל-search/list/API).
- X12 spec: תיעוד digest_kind + הגדרת-הכשל המתוקנת.

אומת: V32 סיווג 533 (525 decision + 8 announcement, 0 unclassified — self-heal
לא נוגע בהם). extract: 5163→decision+citation · 5060→announcement+concept,
citation ריק (לא both-empty).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 06:02:08 +00:00
5eeff24889 docs(graph): document the corpus-graph feature (/graph)
Records the now-complete corpus citation graph: why native not Obsidian (G2),
the 6 opt-in node layers (precedent/topic/practice-area · halacha · gaps ·
digests), node size/color semantics, the Graph Analysis metrics
(PageRank/betweenness/community via web/graph_metrics.py), navigation, the
/api/graph/* endpoints, the key files, a how-to-extend recipe, the invariants
(G2/G5/UI2/UI4), and the PR history.

Adds docs/corpus-graph.md + a reference-table row in legal-ai/CLAUDE.md.
Docs only — no code change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 06:02:02 +00:00
d95a36f310 feat(extraction): precedent metadata via Gemini Flash + scheduled drainer
The /precedents metadata queue was stuck — 24 rows requested, nothing draining
them — and the agentic claude CLI hit error_max_turns on what is a single
structured text→JSON task (slow + flaky). Metadata extraction is bounded
extraction, the wrong fit for an agentic loop.

- gemini_session.py: query_json drop-in (gemini-2.5-flash, JSON mode, httpx —
  no new SDK dep). Reads GEMINI_API_KEY (~/.env; SoT Infisical
  nautilus:/external-apis/gemini). Host-side only — no LLM from the container.
- precedent_metadata_extractor: claude_session.query_json → gemini_session.
  Validated live: rich, accurate fields (case_name/summary/appeal_subtype/tags).
- process_pending_extractions: kind-aware cooldown — metadata 2s (Gemini, fast),
  halacha keeps 30s (Claude rate limits).
- drain_metadata_queue.py + legal-metadata-drain.config.cjs (pm2 cron */15) so
  the queue never clogs again. SCRIPTS.md.
- X8 INV-FP5 updated: per-task engine choice (Gemini=bounded metadata,
  claude_session=agentic halacha), both host-side, single canonical queue (G2).

Agentic/voice-sensitive work (writing, analysis, halacha) stays on claude_session
(Daphna's subscription). Gemini cost ≈ $0.10/1M tokens — negligible.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 05:13:49 +00:00
6882ccfcf1 docs(X13): sync spec to route-by-format reality + Tier-0 limitation
The spec said "supreme → Tier-0"; reality (PR #124) routes by נט-format
availability — נט המשפט (Tier-1) serves all courts incl. Supreme-with-נט-format,
and only serial-only Supreme falls to the (still-unbuilt) Tier-0 → manual.
Updated §0 source-distinction, §1 routing diagram, §5 risks (Tier-0 limitation
+ scheduled drain). Docs-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 20:51:38 +00:00
fb40ec8565 refactor(digests): single source of truth — drop processed/ folder state (X12)
ה-DB (`digests`) הוא מקור-האמת היחיד למצב-קליטה. ingest_digests_batch.py העביר
קבצים incoming→processed/ — state מבוסס-תיקיות מקביל ל-DB (הפרת-G2 קטנה).

- הוסר ה-move ל-processed/ + import shutil + PROCESSED. הסקריפט מסתמך על
  dedup ב-content_hash (ingest_digest מחזיר 'exists' לקיימים) → הרצה חוזרת בטוחה.
- תיקיות (incoming/) = staging בלבד, לא state.
- X12 INV-DIG2: תועד מקור-אמת-יחיד + ההפרה-שתוקנה (processed/).
- SCRIPTS.md עודכן.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 20:33:18 +00:00
f56309da5a feat(X13): auto-trigger court fetch from digests + drain tool
סוגר את הלולאה — יומון שמצביע על פס"ד בית-משפט שלא בקורפוס מזניק אחזור
אוטומטי, וקושר את היומון חזרה אחרי הקליטה (INV-DIG3 + INV-CF2).

- digest_library.try_autolink: בכשל-קישור, אם הציטוט מסווג כפס"ד-בימ"ש
  (supreme/admin) → _enqueue_court_fetch יוצר court_fetch_jobs(pending);
  ועדת-ערר (skip) לא מוזנק. never-raises (לא שובר קליטת-יומון).
- orchestrator.drain_pending(limit): מנקז pending/failed סדרתי (cooldown,
  INV-CF4), fetch+ingest לכל אחד; בהצלחה מקשר את היומון ל-case_law שנקלט.
- כלי-MCP court_fetch_drain + רישום ב-server.py.
- X13 spec: עודכן (הפער ב-INV-CF2 סומן כמתוקן).

נבדק מול ה-DB: עת"מ 46111-12-22 → job tier=admin pending digest-linked;
ערר 1110/20 → לא מוזנק. כלי מקומי בלבד (ingest = claude CLI).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 20:04:12 +00:00
e186183527 fix(X13): harden court-fetch against browser leaks + reaper for task-master-mcp leak
שלוש שכבות-הגנה נגד דליפת-זיכרון מדפדפנים יתומים, + טיפול בדליפה הגדולה
בפועל בשרת (task-master-mcp).

- camofox_client.py:
  - asyncio.wait_for קשיח סביב כל ה-fetch (COURT_FETCH_HARD_TIMEOUT_S=180ש')
    — hang → ביטול → async-with tear-down → reap.
  - _reap_orphan_browsers(): הורג camoufox-bin יתומים (ppid=1) לפני ואחרי כל
    fetch. סדרתיות (INV-CF4) → כל ppid=1 הוא שארית בטוחה.
- scripts/reap_orphan_procs.py: reaper כללי ל-task-master-mcp (~3GB יתומים)
  + camoufox-bin. רק ppid=1; /proc טהור. --dry-run / --loop N.
- scripts/legal-reaper.config.cjs: דמון pm2 (loop 180s, max_memory_restart 100M).
- X13 spec + SCRIPTS.md: תיעוד שכבות-ההגנה.

max_memory_restart בשירות (1.5G) כבר נותן רשת-ביטחון ברמת-התהליך.
Invariants: מקיים INV-CF4 (politeness/serial) — ללא שינוי חוזה.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 19:43:53 +00:00
781f24c643 feat(X13 Tier-1): calibrate נט המשפט fetch — Camoufox python, proven on 46111-12-22
אומת end-to-end: פס"ד 34 עמ' של עת"מ 46111-12-22 הורד אוטונומית מלא, נטו
קוד-פתוח, ללא כרטיס-חכם וללא פתרון-CAPTCHA.

ממצאי-כיול עיקריים:
- החיפוש+הניווט-לתיק ללא reCAPTCHA כלל. reCAPTCHA קיים רק בצופה ורק על
  שמירה/הדפסה מפורשת — לא על הצגת המסמך.
- הצופה מגיש עמודים כ-PNG דרך PageMethod GetImages (4/batch); משיכה ב-fetch
  עם הכותרת X-Requested-With: XMLHttpRequest (חובה — F5 WAF חוסם בלעדיה) →
  הרכבת PDF (Pillow).

שינויים:
- camofox_client.py: שכתוב מלא — Camoufox דרך חבילת-הפייתון (in-process,
  לא שרת-Node REST). מסלול מכויל: home→btnExternalSearchCases→Bama fields→
  CaseDetails→פסקי דין→DecisionList→NGCSViewerPage→GetImages→PDF.
- pm2 config: app Xvfb :99 + DISPLAY=:99 (Camoufox קורס headless בלי צג וירטואלי).
- pyproject: extra [court-fetch] = camoufox + faster-whisper (host-only; הקונטיינר
  לא מריץ דפדפן). Pillow כבר בבסיס.
- X13 spec + SCRIPTS.md: עודכנו לממצאים (image-API, Xvfb, אימות).

reCAPTCHA audio (Whisper) נשמר כ-fallback למסלול-השמירה-המפורש בלבד; המסלול
הראשי אינו זקוק לו. Invariants: מקיים INV-CF1/CF4/CF6 (ללא שינוי).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 19:32:13 +00:00
f3740fef68 Merge pull request 'fix(halacha): split authority (derived) from rule_role — stop source-conflation (INV-DM7)' (#112) from worktree-halacha-authority-split into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m32s
2026-06-07 18:19:43 +00:00
2e33cac043 fix(halacha): split authority (derived) from rule_role — stop source-conflation (INV-DM7)
The extractor classified rule_type by SOURCE bindingness (higher-court→binding,
committee→persuasive) instead of by rule KIND. The gold-set proved it: 'binding'
appeared on 19/19 external rulings & 0 committees; 'persuasive' on 13/13
committees & 0 external — only 58% agreement with the human role tags. The two
axes (authority vs rule role) were crammed into one enum.

This splits them per INV-DM7:
- authority (binding/persuasive) — DERIVED from case_law.precedent_level
  (עליון/מנהלי→binding, ועדת_ערר_מחוזית→persuasive), never stored, never
  LLM-guessed. New helper halacha_quality.derive_authority; surfaced read-only
  in list_halachot / goldset_list / search results.
- rule_type — now the rule ROLE only: holding/interpretive/procedural/
  application/obiter. Both extractor prompts unified to this vocabulary;
  _coerce_halacha no longer defaults rule_type from the source; legacy
  binding→holding / persuasive→interpretive fold for safety.

UI: authority shown as a separate read-only badge (gold=מחייב / muted=משכנע)
across the review queue, precedent detail, and gold-set; the gold-set role
selector drops binding/persuasive and adds מהותי (holding).

Migration: scripts/halacha_rule_role_backfill.py re-classifies the 276 pre-split
binding/persuasive rows into a genuine role via local claude_session (run after
deploy). Gold-set correct_type/ai_correct_type 'binding'→'holding' via SQL.

Sources (≥3, per research-decision policy): OASIS LegalRuleML v1.0
(appliesAuthority/Strength as metadata orthogonal to rule logic) · SemEval-2023
Task 6 LegalEval (rhetorical roles by function, authority kept separate) ·
Bluebook signals (weight-of-authority is a separate dimension).

Invariants: ESTABLISHES INV-DM7. Upholds G1 (normalize at source — extractor
classifies role, system derives authority) and G2 (single source of truth —
authority derived, not a parallel stored field). Tests: 211 pass + new
derive_authority/coerce coverage. web-ui build + tsc clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 18:18:41 +00:00
0990db7a3c feat(X13): auto-fetch court verdicts from נט המשפט → corpus (Tier 0 + scaffold)
תת-מערכת אחזור-פסיקה אוטומטי: כשיומון מצביע על פס"ד בית-משפט, מסווגים את
הערכאה, מורידים מהמקור הציבורי המתאים, וקולטים דרך צינור-הקליטה הקנוני.

- spec-first: docs/spec/X13-court-fetch.md (INV-CF1..CF7) + אינדקס
- מסווג court_citation.py (supreme/admin/skip) + 10 בדיקות (עת"מ 46111-12-22 → admin)
- Tier 0: court_fetch_supreme.py — supremedecisions API (reverse-engineered), httpx
  + browser-headers (אומת 200) + politeness
- תור court_fetch_jobs (SCHEMA_V30) + DB helpers + court_fetch_orchestrator.py
- Tier 1 scaffold: legal-court-fetch-service (aiohttp+Bearer, מראת legal-chat-service)
  + camofox_client (Camoufox open-source) + recaptcha_audio (Whisper מקומי) + pm2
- Tier 2 fallback חינני: manual + missing_precedent (INV-CF2/CF3 — אין drop שקט)
- כלי-MCP court_verdict_fetch / court_fetch_status; SCRIPTS.md

Invariants: מקיים G2 (מסלול-קליטה יחיד, INV-CF1) · G3/G1 (idempotent+נרמול, INV-CF5)
· G4/§6 (אין בליעה שקטה, INV-CF2) · G10 (שער-אנושי, INV-CF3) · G5 (source_type,
INV-CF6) · G9 (provenance+audit, INV-CF7). מקורות INV-CF4: RFC 9309 · Google
crawler · OWASP OAT.

Follow-ups (טרם אומתו חי): live Tier-0 validation · התקנת camofox-browser+whisper
· כיול selectors Tier-1 · COURT_FETCH_SHARED_SECRET (Infisical+Coolify) · טריגר
מ-digest try_autolink (worktree-digests-radar). V30 עלול להתנגש עם digests-radar.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 18:12:13 +00:00
8171572cdd feat(digests): קורפוס יומונים כשכבת-גילוי (radar) — X12
מאגר חדש ליומוני "כל יום" (עפר טויסטר) כשכבת-גילוי מעל קורפוסי-הפסיקה:
מקור-משני המצביע על פסק הדין המקורי, נקלט לטבלה נפרדת `digests`, נחפש
סמנטית, ומקושר לפסק המקורי בספריית הפסיקה — אך לעולם אינו מצוטט בהחלטה
ואינו מחלץ הלכות.

Phase 0 (spec):
- docs/spec/X12-digests-radar.md — INV-DIG1 (מצביע לא מצוטט) /
  INV-DIG2 (מסלול-קליטה נפרד, לא מקביל — מקיים G2) / INV-DIG3 (קישור-לפסק
  הוא הגשר; חוסר-קישור = פער גלוי). עדכון אינדקס 00/03/README.

Phase 1 (MVP):
- SCHEMA_V30: טבלת `digests` (HNSW על embedding — לא ivfflat, להימנע מ-recall
  cliff בקורפוס קטן/צומח) + GIN/FTS + UNIQUE חלקי ל-idempotent.
- services/digest_metadata_extractor.py — חילוץ-LLM (claude_session local-only,
  ייבוא lazy): תג-מושג, כותרת-הלכה, מראה-מקום, שני-תאריכים מובחנים, תגיות.
- services/digest_library.py — מסלול קצר עצמאי (INV-DIG2): extract→hash→LLM→
  embedding יחיד→autolink. לא משתמש ב-ingest.ingest_document.
- tools/digests.py + רישום 7 כלים ב-server.py (digest_upload/list/get/link/
  relink/delete + search_digests).
- scripts/ingest_digests_batch.py — קליטה ידנית מ-data/digests/incoming.
- legal-researcher.md: שלב 2ב.0 (סריקת-radar לפני אימות) + סעיף-דוח ט +
  3 כלים ב-frontmatter. HEARTBEAT §8: ניתוב יומון→digest_upload.

אומת end-to-end: 4 יומונים נקלטו (מטא-דאטה מדויק), חיפוש סמנטי מדרג נכון
("היטל השבחה"→5160, "תמא 38"→5158), link/relink/autolink/revert + מעטפת-MCP.

Invariants: מוסיף INV-DIG1/2/3 (X12). מקיים G2 (bounded context נפרד, לא
מסלול מקביל), G3 (idempotent upsert), G4 (אין בליעה שקטה — פער-קישור מוצף),
G9 (עקיבוּת — היומון מצביע על מקור עקיב). נוגע G7 (RRF) — נדחה, חיפוש
סמנטי-בלבד בשלב 1 (FTS index מוכן).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 17:49:00 +00:00
e239915fd3 docs(paperclip-quirks): §5 — pruned npx cache → 500/crash-loop + fix
Document the failure mode hit on 06/06/26: a pruned npx cache makes the
running paperclip serve GET / → 500 (deleted ui-dist) and, on restart,
crash-loop because the server's startup assertCloudDatabaseContract()
out-races the post-exec patch loop.

Records the synchronous pre-extract+patch gate now in start-paperclip.sh
(paperclip-config c824e0f), the `--help` clean-extract trick, the three
bugs found while building the fix (ui-dist vs dist marker, set -e on patch
failure, pkill -f self-match), the manual recovery runbook, and the e2e
verification.

Invariants: docs-only; touches no G*/INV-* code paths.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 21:24:12 +00:00
a571ad535b fix(#88+#87): סנכרון DB↔file אוטומטי + claims_coverage מבחין כתב-ערר מתכתובת
#88 (DB↔file, lessons #35): drafts/decision.md דרסה את עצמה רק ב-save_block_content;
renumber_all_blocks + נתיבי store_block אחרים השאירו את הקובץ stale → QA נכשל
פעמיים על אותה בעיה (CMPA-62). תיקון: _update_draft_file הפך ל-hook אוטומטי
(מקבל decision_id, מאתר case פנימית) שנקרא מ-store_block (כל persist) ומ-
renumber_all_blocks. legal-qa ממילא קורא מ-DB → שני הצדדים זהים תמיד.

#87 (claims_coverage, 1033-25): טענות מתכתובת (claim_type='reply' — תגובה/
השלמת-טיעון) סומנו "לא נענו" כ-false-positive. תיקון: check_claims_coverage
דורש מענה רק לטענות כתב-הערר (claim_type='claim', appellant); reply/תכתובת
מוחרגות. בקבלה מלאה הסף מוקל (0.2→0.4) כי העורר זכה במלואו.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 20:54:31 +00:00
32a6e2b57b Merge pull request 'fix(style-acq T9): מספור-אוטומטי אמיתי בייצוא DOCX' (#88) from worktree-style-acquisition-mvp into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m28s
2026-06-06 19:24:02 +00:00
3c68383e86 fix(style-acq T9): מספור-אוטומטי אמיתי בייצוא DOCX (היה ללא מספור)
באג: ה-exporter הסיר את הקידומת "N." והחיל סגנון "List Paragraph" — שאין לו
numPr בתבנית (אין numbering.xml) → ההחלטות יצאו **ללא מספור** כלל.

- docx_exporter._ensure_decision_numbering: מזריק abstractNum עשרוני (RTL,
  lvlJc=right) + num לחלק-המספור פעם אחת; _apply_list_numbering מחבר כל
  פסקת-גוף לרשימה הרציפה. מספור Word אמיתי — מתעדכן בעריכה, copy/paste נקי.
  אומת מבנית: numId יחיד, decimal, שתי פסקאות→אותו numId, docx נשמר.
- התאמת ANTI_PATTERNS (T7): הוסר manual_paragraph_numbers — "N." בתחילת-שורה
  הוא ה-signal הנדרש לייצוא, לא אנטי-דפוס. נשאר inline (1)..(2)/markdown/bullets.
- voice-fingerprint §3.1: תוקן — הכותב כן מקדים "N. " בתחילת-שורה (signal),
  הייצוא ממיר ל-auto-numbering. סתירה קודמת ("אל תקליד מספרים") יושבה.

⚠️ אימות-מבנה עבר; אימות ויזואלי ב-Word מומלץ על ייצוא ראשון. G11.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 19:23:29 +00:00
37dcb30604 docs: FU-14 GAP-54 — סגירה כ-resolved-by-FU-1 (איחוד קליטת-פסיקה)
אימות (G2 — לא לפתור מחדש): קליטת-הפסיקה כבר מאוחדת ע"י FU-1. שני מסלולי-
הפסיקה (precedent_library + internal_decisions) עוברים דרך
ingest.ingest_document הקנוני עם ולידציית-enums + citation-guard סימטריים
(מתועד ב-01-ingest §4). המסלול ה-3 (training→style_corpus) הוא קורפוס נפרד
במכוון. מאומת ב-test_unified_ingest (9/9). אין קוד — רק תיעוד סגירה.

Invariants: מאשר INV-ING1 + G2 מקוימים. doc-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 19:02:55 +00:00
a2236363d4 feat(mcp): FU-14 GAP-50 — deprecate draft_section לטובת get_block_context
INV-TOOL2. מיפוי הראה ש-6 כלי-הבלוק אינם כפילות מיותרת: write_block/
write_all_blocks/save_block_content/write_interim_draft משרתים זרימות שונות
(CLI/initial-draft מול תהליך-ה-writer "התיקון בקובץ, לא ב-DB"). הכפילות
האמיתית היחידה — draft_section (הקשר לפי-סעיף, granularity ישן) חופף ל-
get_block_context (לפי-בלוק, תואם 12-הבלוקים הקנוני).

הכרעת-יו"ר: draft_section סומן deprecated (docstring ב-server.py + drafting.py
מפנה ל-get_block_context; draft-decision.md עודכן). ללא הסרה, ללא מיזוג כלי-
הכתיבה — שמירת תהליך-הכתיבה המכוון.

בדיקות: 182/182 עוברים. GAP-49+50 סגורים.

Invariants: מקדם INV-TOOL2 + G2. מתועד ב-X9 (נסגר) + gap-audit פרוסה 9.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 18:57:02 +00:00
14568fdd15 feat(mcp): FU-14 GAP-49 — תיקון שם-הכלי המטעה (precedent_search_library)
INV-TOOL2: `precedent_search_library` (שמחפש ציטוטים מצורפים-לתיק) היה הפוך
וכמעט-זהה ל-`search_precedent_library` (ספריית-הפסיקה הסמכותית, מקור CREAC),
מה שסיכן ציטוט מהמקור הלא-נכון בהחלטה. שונה ל-`search_case_precedents` (שם
ברור: case-attached). השם הישן נשמר כ-@mcp.tool() alias deprecated המנתב לחדש
→ אפס שבירה לסוכנים חיים.

docstrings של שני כלי-הפסיקה הובהרו (case-attached מול authoritative).
עודכנו: web/app.py (typeahead), legal-researcher/legal-writer docs, precedent_library docstring.

5 כלי-החיפוש הנותרים (search_decisions/case_documents/find_similar/internal/
precedent_library) מחפשים קורפוסים מובחנים בשמות סבירים — לא בוצע rename המוני
(churn גבוה, ערך נמוך מול הסיכון).

בדיקות: 182/182 עוברים. אחרי deploy — סנכרון cross-company של doc-הסוכן.

Invariants: מקדם INV-TOOL2 + G2. מתועד ב-X9 + gap-audit פרוסה 8.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 18:51:17 +00:00
29af008271 feat(mcp): FU-14 GAP-48 פרוסה 3 — envelope למשפחת drafting (סגירת GAP-48)
הפרוסה האחרונה של GAP-48 (INV-TOOL1). 18 כלי drafting הומרו ל-{status,data,message}
דרך tools/envelope.py — כולל מסלול הפקת-ההחלטה הקריטי.

עיקרון לכלים עם כשל משמעותי (export_docx/revise_draft/apply_user_edit): err()
ברמת-המעטפת — כך שהסוכן והמשתמש רואים את הכשל; failed_gates רוכב ב-data.
שאר הכלים: ok(data=payload) להצלחה, err להיעדר-תיק/קלט-שגוי/חריגה.

6 צרכני-app.py חוּוטו (get_decision_template, apply_user_edit ×2, revise_draft,
list_bookmarks, export_docx) עם envelope_unwrap + בדיקת status=="error"→4xx,
לשמירת חוזה-ה-API (X6) ללא-שינוי. test_export_qa_gate עודכן לחוזה החדש.

בדיקות: 182/182 עוברים (כולל שערי-QA של הייצוא).

GAP-48 סגור: כל ~12 משפחות-הכלים אחידות. נותר ב-FU-14: GAP-49/50 (שובר), GAP-54.

Invariants: משלים INV-TOOL1 + G2. מתועד ב-X9 (נסגר) + gap-audit פרוסה 7.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:51:56 +00:00
79b9c37301 feat(mcp): FU-14 GAP-48 פרוסה 2 — envelope אחיד ל-11 משפחות-כלים
המשך מיגרציית INV-TOOL1 מעבר למשפחת-החיפוש (#71). הומרו ל-{status,data,message}:
precedent_library, citations, internal_decisions, missing_precedents,
training_enrichment, precedents, legal_arguments, cases, documents, workflow
(~55 כלים). בוטלו 5 עותקי _ok/_err משוכפלים (alias ל-tools/envelope.py — SSoT, G2).

עיקרון: envelope-status = הצלחת-הקריאה-לכלי; תוצאה-עסקית (idempotent_existing,
noop, completed...) נשמרת בתוך data. err רק לכשל אמיתי (not-found/invalid/exception).

תאימות-API: צרכני web/app.py של cases/workflow/precedents חוּוטו דרך
envelope_unwrap + בדיקת status=="error"→4xx — תשובת ה-HTTP זהה, web-ui לא מושפע.
(documents/legal_arguments/citations/... אינם נצרכים מ-app.py — agent-only.)

בדיקות: 182/182 עוברים (test_corpus_constraints עודכן לחוזה החדש).
נותר: משפחת drafting (מסלול הפקת-ההחלטה) בפרוסה נפרדת עם שער טסט-ייצוא.

Invariants: מקדם INV-TOOL1 + G2 (SSoT, ביטול כפילות). מתועד ב-X9 + gap-audit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 17:41:39 +00:00
014eb4937e Merge pull request 'feat(style-acq T15): הכותב צורך את כל הלמידה (/methodology + /training) + תיקון-מספור' (#72) from worktree-style-acquisition-mvp into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m56s
2026-06-06 16:37:01 +00:00
b9bdca0572 feat(style-acq T15): הכותב צורך את כל הלמידה (/methodology overrides + /training lessons) + תיקון-מספור
עונה ל"להתחשב במה שכבר למדנו": הכותב התעלם מעריכות היו"ר ב-/methodology
(נשמרו ב-appeal_type_rules אך block_writer קרא רק קבועי lessons.py) ומ-
decision_lessons של /training. עכשיו הכל מגיע לכתיבה.

- db.get_methodology_overrides(category) — overrides של היו"ר (יחסי-זהב,
  כללי-דיון, צ׳קליסטים) מ-appeal_type_rules (כמו merge של ה-API).
- db.get_recent_decision_lessons(limit, practice_area) — לקחי /training.
- _build_style_context(practice_area): מוסיף סעיף " למידה מצטברת — גובר
  על ברירת-מחדל" עם שניהם, אחרי voice-fingerprint (T0). שני ה-callers מעבירים
  practice_area. עובד יחד עם הלולאה (T4/T5) שתזין לאותן טבלאות.

תיקון-מספור (חלק מ-T9, דחוף כי T0 הזריק את הטעות): voice-fingerprint §3.1
תוקן — ההחלטה ממוספרת תמיד (מספור-אוטומטי ב-Word); "ללא מספור" היה
ארטיפקט-חילוץ. האנטי-דפוס האמיתי: רשימת-מיני בתוך פסקה + מספרים ידניים.

INV-LRN4 (הזרמת למידה) · INV-LRN5 (טוהר). G11.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 16:36:32 +00:00
aa0a736a7b feat(mcp): FU-14 GAP-48 פרוסה 1 — envelope אחיד (SSoT) + משפחת-חיפוש
INV-TOOL1: כלי-ה-MCP החזירו 3 מוסכמות סותרות (raw payload / {error} /
{status,message} אד-הוק) + 5 עותקי _ok/_err משוכפלים. נוצר tools/envelope.py
כמקור-אמת יחיד: ok/empty/err → {status,data,message}, כש-status מבחין
מפורשות הצלחה/ריק/שגיאה.

פרוסה 1 ממירה את משפחת-החיפוש (search_decisions, search_case_documents,
find_similar_cases, search_internal_decisions). web/app.py מפרק את המעטפת
דרך envelope_unwrap כדי לשמר את חוזה-ה-UI↔API (X6) ללא-שינוי — תשובת ה-HTTP
זהה (list על hits, {"message"} על ריק/שגיאה). טסט test_search_domain_scope
עודכן לחוזה החדש (5/5 עוברים).

החלטה: הדרגתי לפי-משפחה ולא big-bang. מפת-צרכנים: server.py pass-through,
web-ui מבודד (/api/*), רק 17 כלים נצרכים ישירות מ-app.py → סיכון מינימלי
לסוכנים החיים. ~73 כלים נותרו לפרוסות הבאות.

Invariants: מקדם INV-TOOL1 (envelope עקבי) + G2 (SSoT, ביטול כפילות _ok/_err).
לא נוגע ב-G1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 16:32:07 +00:00
9c77123fa3 Merge pull request 'feat(spec): מערכת רכישת-הסגנון כיעד-על + ספ 07-learning §0 + משימות (PR1 יסודות)' (#67) from feat/style-acquisition-subsystem into main
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 9s
2026-06-06 16:02:53 +00:00
770d23b198 feat(spec): הגדרת מערכת רכישת-הסגנון כיעד-על + ספ + משימות (PR1 יסודות)
מגדיר במפורש את יעד-העל שמעולם לא הוגדר: שהסוכנים יכתבו וינתחו עררים
בדיוק כמו דפנה תמיר, דרך תת-מערכת Style-Acquisition נפרדת ממערכת-הכתיבה.

- CLAUDE.md: פרק "יעד-העל: רכישת-הסגנון" — הפרדה writing↔learning,
  Authorial Style Profiling (לא fine-tuning), מדיניות-העתקה לפי סוג-תוכן
- docs/spec/07-learning.md §0: תת-המערכת, 3 ערוצי-הזנה, צינור 7-שלבים,
  ניהול ב-UI, + INV-LRN4 (ניגוד-אמת draft↔final) + INV-LRN5 (טוהר-הקול)
- TaskMaster: 15 משימות T0-T14 (89-103) — MVP=T0+T4+T7

ללא שינוי-קוד runtime. 1130-25 כבר נקלט ל-internal_committee (תהליך מקביל).
INV: G9 (ידע מובנה), G10 (שער-יו"ר), G11 (סגנון דפנה).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 16:02:18 +00:00
40c1111e9b feat(mcp): FU-14 GAP-47 (חלק provenance) — draft_section מחזיר document_id+page+score
ה-provenance (document_id, page_number, score) כבר נשלף ב-search_similar אך
נזרק בבניית פלט draft_section. כעת מוחזר לכל קטע ב-case_documents/precedents,
כך שהכותב יכול לעקוב אחורה אל מסמך-המקור והעמוד ולצטטם, ולא לסמוך על תוכן
חסר-מקור. תוספתי בלבד — אין צרכן שמפרסר את מפתחות-הפלט, תואם-לאחור.

נותר ב-GAP-47: העברת הנחיות-יו"ר מ-analysis-and-research.md ל-DB
(get_chair_directions) — שינוי-מסלול גדול יותר, לפרוסה נפרדת.

Invariants: מקיים INV-TOOL4 (מקור-אמת נגיש) + G9 (provenance). לא נוגע ב-G2/G1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 15:58:39 +00:00
701efab726 feat(mcp): FU-14 GAP-51 — איחוד אוצר-המילים של תוצאת-תיק (set_outcome SSoT)
הכרעת-יו"ר: קנוני = 3 תוצאות אמיתיות (rejection/partial_acceptance/full_acceptance);
betterment_levy יוצא מהיותו "תוצאה" ועובר ל-override לפי practice_area.
+ עקרון "אנגלית-ב-DB, עברית-ב-UI": מפת-תוויות SSoT אחת.

lessons.py:
- VALID_OUTCOMES = 3 (הוסר betterment_levy).
- OUTCOME_LABELS_HE (SSoT לתצוגה) + LEGACY_OUTCOME_MAP + canonical_outcome().
- PRACTICE_AREA_OVERRIDES["betterment_levy"] מרכז את כל ה-guidance שהיה מפתוח כ-outcome
  (golden_ratios/opening/summary/discussion/template).
- get_lessons_for_outcome(outcome, practice_area) + format_ratios_comment(..., practice_area)
  מחילים override + מנרמלים legacy.

block_writer.py: STRUCTURE_GUIDANCE קנוני + תווית מ-OUTCOME_LABELS_HE + override betterment.
workflow.set_outcome: קנוני 3 + מיפוי-legacy סלחני; תווית מ-SSoT.
drafting.py: טבלת יחסי-זהב + get_decision_template מודעי-practice_area (override).
web-ui case.ts: הסרת betterment_levy מ-expectedOutcomes (הוא practice_area).
server.py: docstrings קנוניים.

מיגרציה: migrate_gap51_outcomes.py — 9 שורות נורמלו (rejected→rejection וכו'),
גיבוי ב-data/audit/. הקוד canonicalize בקריאה ⇒ backward-compatible גם בלי מיגרציה.

אומת: py_compile (5 קבצים) + בדיקות-יחידה offline (override/legacy/labels) + אימות-DB.
עודכנו X9 §3 + gap-audit (GAP-51 ).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 15:34:49 +00:00
ea8b48c6ac feat(mcp): FU-14 GAP-45 — extraction_status (חשיפת תור-החילוץ הסמוי)
INV-TOOL4 (visibility / persistence). תור בקשות-החילוץ (metadata/halacha) נשמר
ב-case_law.{metadata,halacha}_extraction_requested_at ומרוקן ע"י
precedent_process_pending — אבל לא היה כלי לראות את עומק-התור.

נוסף:
- db.extraction_queue_status() — count + גיל הבקשה הוותיקה לכל kind (read-only).
- plib.extraction_status() — tool wrapper (envelope _ok/_err).
- רישום extraction_status ב-server.py ליד precedent_process_pending.
- precedent_process_pending קיבל _clamp_limit (עקביות עם GAP-53).

תוספתי, read-only, אפס שבירה. עודכנו X9 (INV-TOOL4 ) ו-gap-audit (GAP-45 ).
py_compile עבר על 3 קבצי הקוד.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 15:00:25 +00:00
034b609bd3 feat(mcp): FU-14 GAP-52 — idempotency על case_create/precedent_attach/document_upload
INV-TOOL3 (idempotency על מפתח דטרמיניסטי). כל שלושת הכלים מחזירים את הרשומה
הקיימת במקום ליצור כפילות:

- case_create — מפתח case_number (כבר UNIQUE ב-schema): מחזיר את התיק הקיים
  במקום unique-violation.
- precedent_attach — מפתח (case_id, section_id, citation, quote): צירוף חוזר
  של אותו ציטוט לאותו סעיף מחזיר את הקיים.
- document_upload — מפתח (case_id, SHA-256 של בייטי הקובץ): העלאה חוזרת של אותו
  קובץ מחזירה את המסמך הקיים ו**מדלגת על copy+OCR+embed** (החלק היקר). נוספה
  עמודת documents.content_hash (תוספתי, DEFAULT '') + get_document_by_hash.

נבחרה בדיקת-מפתח ברמת-אפליקציה (SELECT-לפני-INSERT) ולא UNIQUE-constraint —
כדי לא לשבור startup אם קיימים נתונים-כפולים legacy. אין מיגרציה הרסנית.

עודכנו docs/spec/X9 (INV-TOOL3 ) ו-gap-audit (GAP-52 , פרוסה 2).
py_compile עבר על 4 קבצי הקוד. אימות runtime (restart MCP server) נדחה עד
שהחילוץ הפעיל יסתיים.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 14:52:33 +00:00
ebfe7f6a1d feat(mcp): FU-14 פרוסה 1 — get_appraiser_facts (GAP-44) + limit-caps (GAP-53)
תוספתי בלבד, אפס שבירת-תאימות. שני invariants מחוזה-כלי-ה-MCP (X9):

GAP-44 (INV-TOOL4, סימטריית extract/get): נוסף get_appraiser_facts — ה-get
המקביל ל-extract_appraiser_facts. קורא list_appraiser_facts + detect_appraiser_conflicts
מה-DB ללא חילוץ-LLM יקר ולא-דטרמיניסטי. מחזיר count=0 (לא שגיאה) אם טרם חולץ.

GAP-53 (INV-TOOL5, limit-caps / OWASP API4:2023): נוסף _clamp_limit (תקרה 200,
non-positive→max) על ~13 כלי list/search ב-server.py (case_list, search_*,
precedent_library_list, halachot_pending, missing_precedent_list, list_*_citations…).
list_chair_feedback קיבל param limit חדש (server→workflow→db עם LIMIT) — היה ללא תקרה כלל.

לא הוסף get_appraiser_facts ל-frontmatter של סוכנים (INV-AG3 "לא עודף" — ההוראות
עוד לא מפנות אליו; חיווט = follow-up). נותר ב-FU-14: GAP-45/48/49/50/51/52.

עודכנו docs/spec/X9 (INV-TOOL4/5) ו-gap-audit (סטטוס פרוסה 1).

אומת: py_compile על 4 קבצי הקוד. אימות runtime (restart MCP server) נדחה עד
שהחילוץ הפעיל של היו"ר יסתיים.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 14:37:30 +00:00
482f302d54 fix(security+agents): GAP-57 fail-loud PAPERCLIP_DB_URL + FU-13 analyst tool alignment
GAP-57 (אבטחה, CWE-798 / INV-ENV4): ה-default הקשיח
postgresql://paperclip:paperclip@... הוסר מ-3 קבצי web/. נוסף resolver משותף
require_paperclip_db_url() ב-paperclip_api.py שנכשל בקול אם PAPERCLIP_DB_URL לא
מוגדר — במקום ליפול בשקט ל-creds ידועים. Coolify מגדיר את המשתנה (אומת), אז
הייצור לא נפגע. (2 מופעים בסקריפטים מקומיים נותרו ל-FU-15 המלא.)

FU-13 (INV-AG3, GAP-46): יישור הרשאות-סוכן. התברר שהפער שמופה ב-31.5 היה רחב
מדי — יוחס לפי תיאור-תפקיד, לא ההוראות בפועל. הכרעת-יו"ר "היבריד":
- legal-analyst: נוסף aggregate_claims_to_arguments (frontmatter + שלב 7) — הכלי
  שמקבץ את הטענות שהוא חילץ לטיעונים משפטיים.
- extract_references/extract_internal_citations הם מטלת-researcher (שכבר מחזיק
  אותם), לא analyst — הוסרו מרשימת "החסרים".
- legal-researcher: כבר היה תקין; ה-spec היה מיושן.
עודכנו X4-agents.md (§2א, INV-AG3) ו-gap-audit.md (FU-13 , FU-15 חלקי).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 14:14:39 +00:00
dd0e754dad docs(lessons): קיפול ידני של 21 הערות יו"ר backlog לקבצי הידע
- legal-decision-lessons.md: סקשן "Chair Feedback Backlog (June 6, 2026)"
  לקחים #36-#46 (רקע תכנוני כארגומנטציה, ראיות ויזואליות, עררים מקבילים,
  שלד יו"ר, סדר ט-לפני-ז, להלן-מתוך, ציר זמן בלוק ו, תכנית נקודתית מול
  כוללנית, תנאי אי-רווח ס'19(ב)(4), הבחנת טענות כתב-ערר מתכתובת)
- block-schema.md: סדר בלוק ט לפני ז בתיקי רישוי 1xxx
- SKILL.md: תבנית "להלן מתוך [מסמך]:" כחובה
- TaskMaster: משימות 87 (claims_coverage), 88 (פער DB↔file)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 13:08:21 +00:00
ca959d4a9c feat(halacha): strict-rubric quality gate + dedup-on-insert (#81,#82)
Bake the 2026-06-03 strict-cleanup rubric into the extraction pipeline so the
corpus stays clean at the source instead of accumulating duplicates, obiter
dicta, truncated quotes and thin restatements that clog the review queue.

#81 — quality gate:
- New pure module halacha_quality.py with unit-tested validators:
  non-decision/obiter (Wambaugh markers), truncated-quote (mid-word cut),
  thin-restatement (rule≈quote), quote-unverified.
- Validators run in halacha_extractor._process; a non-decision is re-typed
  obiter; flags persist in new halachot.quality_flags column.
- Auto-approve now requires confidence>=threshold AND no quality flags;
  flagged items route to pending_review regardless of confidence.
- Both extraction prompts hardened: reject undecided dicta, exclude
  case-specific applications, require abstraction, forbid over-splitting.

#82 — dedup-on-insert (store_halachot_for_chunk):
- Within the same precedent, skip a halacha whose normalized supporting_quote
  already exists, or whose rule-embedding has cosine>=HALACHA_DEDUP_COSINE
  (0.93) against an already-stored one. Makes re-runs idempotent.

Migration: halachot.quality_flags TEXT[] (additive, idempotent ALTER).
Tests: 19 new unit tests; full suite 156 passed. Validated end-to-end against
dev DB (dedup skips dups, flag blocks auto-approve, re-run inserts 0).
Calibration: flags fire on only ~10% of current survivors (low false-positive).

Spec: docs/halacha-strict-rubric.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 12:30:38 +00:00
d790fb26e0 docs(lessons): weekly chair-feedback lessons #34-35 (week ending 2026-05-31)
#34 don't manufacture doubt about unambiguous statutes (s.19(ג)(2));
#35 writer/QA two-sources-of-truth sync gap (DB vs drafts/decision.md).
Output of the weekly-feedback-analysis job, pending commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 11:57:24 +00:00
df007784c9 feat(corroboration): approval_action decision fn + kill-switch (INV-COR2/COR4, X11 Phase 2)
- HALACHA_CORROBORATION_AUTO_APPROVE config (default ON, Dafna validated 2026-06-01)
- approval_action(agg, has_overruled): overruled→demote, corroborated→approve, else None
- 4 offline unit tests; Phase 2 plan + TaskMaster #75

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 04:34:23 +00:00
6ed5c9e99f docs(X11): foreground open-access sources; verify decision against open literature
החלפת מיקוד שורות-המקורות של INV-COR1–COR5 + תיקון-G10 ממוצרים סגורים (Shepard's/KeyCite)
למקורות פתוחים שאומתו בפועל — בהתאם ל-feedback_legal_db_authoritative_sources ולפרוטוקול
≥3-המקורות של החוקה:

- Fowler et al., Network Analysis and the Law (Political Analysis 2007) — ציטוטים-נכנסים =
  מדד-סמכות, מאומת בניבוי ציטוט עתידי (INV-COR1/COR4).
- Demir & Canbaz, Validate Your Authority (NLLP/ACL 2025) — LLM מסווג טיפול-תקדים ב-67.7–79.1%;
  הדיוק הלא-מושלם מצדיק את הסייגים השמרניים (≥N, שער-אנוש, שלילי→דגל) (INV-COR2/COR4/COR5).
- CaseHOLD (arXiv 2021) — סיווג ברמת holding (INV-COR3). LePaRD (arXiv 2023) — citation dataset.
- Hellyer (LLJ 2018, open-access), NCSC/JTC, CEPEJ, ISO 15489 — ללא שינוי, פתוחים.

מסקנה: הספרות הפתוחה תומכת בהחלטה (citator + סיווג-טיפול + סמכות-מבוססת-ציטוט), ודווקא
מחזקת את הגרסה השמרנית. אין גישה ל-Shepard's/KeyCite הסגורים — המידע עליהם הגיע ממקורות
משניים פתוחים בלבד.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 19:30:02 +00:00
beba24dfc5 docs(plan): X11 corroboration Phase 1 implementation plan
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 18:50:50 +00:00
887079535c feat(spec): X11 citation-corroboration + INV-G10 amendment + Opus 4.8 halacha extraction
ספ חדש לשכבת citator פנימית — תיקוף הלכות לפי טיפול-שיפוטי מצטבר (ציטוטים נכנסים),
לצמצום היקף האישור-הידני של היו"ר:

- docs/spec/X11-citation-corroboration.md — 6 invariants (INV-COR1–COR6), כל אחד עם
  ≥3 מקורות מקצועיים (Shepard's/KeyCite, Hellyer LLJ 2018, UNC Law, NCSC/JTC, CEPEJ).
- docs/spec/00-constitution.md — תיקון מבוקר ל-INV-G10: השער מסופק ע"י טיפול-שיפוטי-מצטבר
  לתת-הקבוצה החיובית, שער-היו"ר נשאר חובה לזנב ולשלילי. + X11 באינדקס.
- Opus 4.8 @ xhigh כמודל חילוץ הלכות (config HALACHA_EXTRACT_MODEL/EFFORT, env-tunable;
  claude_session model/effort params; halacha_extractor מחווט). מבוסס A/B 2026-05-31:
  פחות חילוץ-יתר, 100% quote-verified, ביטחון מכויל.
- scripts/ab_halacha_opus48.py — harness A/B לא-הרסני להשוואת מודל/effort בחילוץ הלכות.
- .taskmaster #70 (FU-2c-b) — תיעוד dedup שפר + סריקת-קורפוס (0 stubs תקועים נותרו).

תנאי-קדם (זהות נקייה) הושלם: שפר מוזג לרשומה קנונית + סריקת 128 רשומות.
audit-findings גלויים ב-X11 §7: קישור הלכה↔ציטוט + סיווג-טיפול = greenfield, ל-implementation plan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 18:42:13 +00:00
37c56ff22a docs(spec): cycle-2 — 8 application-surface domains (X6–X10) + ui-audit + GAP-24..62/FU-9..15
Extends the system spec beyond the core pipeline to the 8 surfaces outside it:
- X6 UI↔API contract + design rules (INV-UI1..6)
- X7 Paperclip client & connection params (INV-INT4..8)
- X8 field-population & extraction provenance (INV-FP1..5)
- X9 MCP tool contract — 71 tools (INV-TOOL1..6)
- X10 deploy/env/secrets (INV-ENV1..5)
- ui-audit.md — page-by-page UI audit (13 pages)
- 02-data-model: derived-entity invariants (INV-DM4..6)
- X4-agents: tool-grant map + INV-AG3
- gap-audit: GAP-24..62 → FU-9..15; cycle-1 (FU-1..8b) marked done
- constitution §7 + README index (X1..X10)

Planning/spec artifacts only — no application code. All engineering invariants
backed by ≥3 sources; every finding carries verified file:line.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:21:27 +00:00
a02a606f34 feat(agents): wire spec into agents — INV-AG1 read-before-act gate (FU-8b/GAP-23)
חיווט ספ-המערכת לסוכני-Paperclip כך שכל סוכן חייב לקרוא את 00-constitution
תחילה, ואז את ספ-התחום הרלוונטי לתפקידו (לפי טבלת X4 §2) — לפני עבודה מהותית.

- HEARTBEAT.md: סעיף עליון "קריאת-ספ — קודם החוקה (00), אז ספ-התחום" לפני §0–§8,
  עם טבלת תפקיד→ספ ל-8 הסוכנים.
- 8 קבצי-סוכן (ceo/proofreader/researcher/analyst/writer/qa/exporter/hermes):
  סעיף "קרא לפני פעולה (INV-AG1)" בראש הגוף.
- X4-agents.md: שדה "אכיפה" של INV-AG1 → "מחוּוט (פרוצדורלי)"; §5 → "בוצע".

אכיפה פרוצדורלית בכוונה — invariant פרויקטלי-תפעולי, אין שער-קוד שמכריח קריאה.
prereq לסוכני-התהליך (תת-פרויקט 5). gap-audit נשמר כ-snapshot (כמו FU-8a).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 16:02:04 +00:00
6ff2e36bf9 feat(eval): FU-5 — retrieval eval harness + halacha backlog visibility (#63)
Covers GAP-11 (INV-RET4/G8) and GAP-14 (INV-QA1/G10). Retrieval quality was
never measured (only telemetry observation) and the halacha review backlog was
invisible (the 10/19 gap was found by accident).

Unit B — backlog visibility (pure code, container):
- metrics.halacha_backlog(conn) → {pending_review, approved, rejected, published,
  total, oldest_pending_at}; surfaced in metrics.get_dashboard() (get_metrics MCP
  tool) and /api/system/diagnostics. Live count revealed 178 pending / 1552 total,
  oldest from 2026-05-03 — previously invisible.

Unit A — retrieval eval harness (host-side scripts):
- scripts/eval_gold_bootstrap.py — seeds data/eval/gold-set.jsonl. Two sources:
  citations (cited==relevant via search_relevance_feedback — empty until decisions
  cite precedents) and known_item (query=case_name → relevant=self; a real
  citation-free signal, the methodology #52 checked by hand). Idempotent; preserves
  source='chair' rows.
- scripts/eval_retrieval.py — runs the production retrieval path (search_library /
  search_internal) over the gold-set; computes precision@k, recall@k, MRR, nDCG@k
  (k=5,10); aggregates overall + per-corpus + per-practice_area; writes a report and
  a delta vs committed baseline.json (which records the retrieval_config it reflects).
  --self-test unit-checks the metric math offline.

Gold-set strategy = hybrid (chair decision): bootstrap + chair review. The citation
source is empty today (0 cited precedents in decisions), so the seed is known-item
(77 queries: 54 internal_decisions + 23 precedent_library). The gold-set is
PROVISIONAL until Dafna reviews it (the domain chair-gate).

Baseline (production config: multimodal+rerank on): R@10=0.987, MRR=0.837,
nDCG@10=0.872. Finding: MULTIMODAL_ENABLED=true slightly lowers known-item recall
(image-page results displace exact name matches) — relevant to #15. precedent_library
weaker than internal (R@10 0.957 vs 1.0) — one external precedent unfindable by name.

"CI gate" realized as discipline (re-runnable harness + committed baseline + run
before/after any retrieval-layer change) — retrieval needs prod DB + Voyage, no CI
runner has that access.

Spec: docs/superpowers/specs/2026-05-31-fu5-eval-harness-design.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 14:58:13 +00:00
adc196ac20 docs(plan): FU-8a process→code guards implementation plan (3 tasks, TDD)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 10:51:31 +00:00
e8431a2adf docs(spec): FU-8a process→code guards design (GAP-21/22) + split GAP-23 to #69
GAP-21: sync_agents --verify exits non-zero on drift; adapter_type mismatch
counted as drift (loud), not silent skip — makes it an enforceable gate (INV-MC1).
GAP-22: fitness-function pytest guarding against raw Paperclip HTTP + direct
agent_wakeup_requests INSERT (INV-INT1/INT3). Repo pre-scanned: 0 existing
violations → clean forward-fence. Verified vs 3+ sources (architectural fitness
functions; drift-verify non-zero exit). GAP-23 (spec→agents) split to #69.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 10:48:15 +00:00
c2de69272d docs(plan): FU-2b identifier-reconciliation implementation plan (chair-gated, TDD)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 08:09:22 +00:00
105d9626ca docs(spec): FU-2b internal identifier reconciliation design (GAP-07/08) + split external to #68
Deterministic migration of ~52 internal_committee rows whose case_number holds
a full citation → normalized bare number (citation_formatted already correct).
DB analysis (2026-05-31): clean 1-token extraction, 0 key-collisions, 0
citation↔case_number mismatches, no month-padding dups. Chair-gated reversible
migration (backup→dry-run→approve→apply). One edge for chair: 8047/23 ערר vs בל"מ.
External (#68/FU-2c) split out — its citation_formatted is inconsistent.
Verified all 11 case_law FKs use id(UUID), not case_number → rename is FK-safe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 06:12:43 +00:00
8b3f191c8b docs(plan): FU-3 re-index on content change implementation plan (6 tasks, TDD)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 22:00:02 +00:00
a62116a571 docs(spec): FU-3 re-index on content change design (GAP-09) + close #61.2 not-applicable
content_hash/indexed_hash change detection + reindex_case_law from stored
full_text (no re-OCR) + drift health-check. Verified vs 3+ sources (content-
hash change detection, RAG re-embed-on-edit). #61.2 multimodal backfill closed:
42 rows are text-ingested (document_id NULL, no source PDF) — page-images
impossible without a PDF to render.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 21:52:40 +00:00
2994a884e9 docs(plan): FU-7 audit-trail + provenance implementation plan (7 tasks, TDD)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 21:26:30 +00:00