Follow-up to the status SSoT (#382): analyst_verified + research_complete are
now first-class canonical statuses, so refresh the docs that still framed them
as legacy/decorative.
- HEARTBEAT.md §7: rewritten to point at the single source
(case_status_model.py / GET /api/status-model), list the 12 canonical statuses
by phase, and state the two intermediates are canonical (not legacy); genuinely
old markers (proofread/analysis_enriched/…) are display-only fallbacks.
- legal-qa.md / legal-ceo.md status maps: dropped the "legacy/optional" framing
on research_complete; point to the canonical model.
- scripts/backfill_case_status_trim.py: removed analyst_verified +
research_complete from the downgrade map (they are valid statuses again — must
NOT be downgraded) + updated the docstring.
Docs/prompts only — no behaviour change. py_compile clean.
NOTE: the host ~/legal-ai needs `git pull` for the Paperclip agents to pick up
the refreshed prompts (they run on the host tree, not the container).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The summarize_party_claims tool (#202) generated a distilled executive
summary of party claims but was orphaned: not granted to any agent and
no CEO trigger. Wire it parallel to the interim-draft (שלב H).
- Grant mcp__legal-ai__summarize_party_claims in legal-ceo.md frontmatter.
- Add שלב H2 (סיכום מנהלים) mirroring שלב H: side-quest (no cases.status
change, no sub-agent issues), in_progress → run tool → in_review + notify.
Two triggers: chair comment ("סיכום מנהלים"/"סיכום טענות"/"סיכום לקראת
דיון"/"executive summary") OR structured action
$PAPERCLIP_WAKE_PAYLOAD_JSON action == "party_claims_summary".
- Add structured-action trigger to שלב H (interim draft):
action == "interim_draft" — same deterministic UI-button path.
- שלב 0 + HEARTBEAT.md: route structured actions deterministically.
- Spec note in docs/spec/04-analysis-writing.md §1.4.
Invariants: G2 (reuse existing summarize_party_claims tool/path, no parallel
route), G10 (chair-requested side-quest). Agent-prompt/docs only — no app code.
Note: CEO prompt is shared across CMP+CMPA via instructionsFilePath; after
merge the host tree needs `git pull` (agents run host-side reading
.claude/agents/*.md).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Root cause (proven 2026-06-30, legal-ai #164): the comment-sweep wakes the CEO
via ctx.agents.invoke, which does NOT populate $PAPERCLIP_WAKE_REASON or
payload.issueId. The run transcript showed "generic heartbeat with no scoped
wake" — the CEO's `user_commented` branch never fired, it ran a generic
heartbeat that scans only CEO-assigned issues, and chair comments on
chaim/sub-agent-owned issues (e.g. CMPA-116) were invisible → no-op. Two real
6-day-stale chair requests sat undelivered.
Fix: on any wake without a scoped reason, the CEO must DISCOVER pending chair
comments itself. Adds "סריקת הערות-יו"ר תלויות (company-wide)":
- enumerate all active company issues (/api/companies/{id}/issues)
- pending = newest user comment newer than newest agent comment (ignore
system); order-independent sort_by(createdAt) since the API is newest-first
- MANDATORY case binding from the STRUCTURED project.name ("ערר <case> — …"),
never from the title (CMPA-116 has none) nor the comment content (which may
name a different case, e.g. "ניסיתי ב-CMPA-89"). No confident case → do NOT
act; escalate to chair.
- handle each pending comment scoped to its own $ISSUE_ID/$CASE_NUMBER
Verified end-to-end against live data: 13 active issues → exactly 2 pending
(CMPA-116, CMPA-89), both resolved to case 8125-09-24 via project.name, zero
false positives. Step 0 + Step A wired to run the scan on blind wakes.
Refs #164. Pairs with the plugin sweep (delivery) — this is discovery+action.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Belt-and-suspenders to the plugin sweep (plugin-legal-ai #3). Comments that
arrive mid-run aren't re-read automatically — an agent reads comments once at
run start (§2), so a chair comment that lands after that point and before the
run closes the issue is never seen. That is exactly how a chair comment on
CMP-190 (2026-06-30) was dropped.
Adds a mandatory gate to HEARTBEAT §4ב: before PATCH status=done, re-read
comments and compare to the run-start list. If a new unaddressed chair comment
exists — do not close. Either handle it (and record a comment) or, if it
widens scope, keep the issue open and hand back to the CEO (§4ג). Never mark
done while a chair comment waits unanswered.
The plugin sweep catches orphaned comments within ~2 min; this gate prevents
the drop at the source. Refs legal-ai #164.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
תיקוני-מבנה ללולאת-הלמידה (TaskMaster #157):
1. כרטיס ה-curator (/training טאב "אוצֵר") ספר decision_lessons WHERE source='curator'
— ערך שאף מסלול-קוד לא כתב → תמיד 0. עוצב-מחדש (דרך שער-העיצוב Claude Design, אושר)
להציג ביושר את שלושת ערוצי-ההזנה לכותב: דיסטילציה→appeal_type_rules (180, זורם),
פאנל→decision_lessons (81, ממתין), אוצֵר→source='curator'. get_curator_stats שוכתב.
2. drift ספ↔סוכן: 07-learning.md §1.1 + INV-LRN3 קבעו שהאוצֵר רושם ממצאים כ-decision_lesson
source='curator', אך הסוכן כתב comments בלבד — הממצאים האיכותיים אבדו. נוסף כלי-MCP
record_curator_findings + §A.5b ב-hermes-curator.md (read-only נשמר; הצעה מגודרת-שער).
3. get_recent_decision_lessons(limit=15) חתך בשקט — נוסף WARN על מה שנחתך (חוקה §6);
הפתרון האמיתי = סינתזת-לקחים (TaskMaster #158).
Invariants: מקיים INV-LRN1/G10 (שער-יו"ר), INV-LRN3 (לכידה מובנית), INV-IA2/IA5 (מקור-אמת
יחיד), G12 (leak-guard עובר), G2 (אין מסלול מקביל — אותם מאגרים). פער-מימוש פתוח מתועד:
§A לא רץ אוטומטית על mark-final (pipeline-wake exits) → נדחה לתכנון נפרד.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The internal citation graph fed only RANKING (raw in-degree), and the per-citation
TREATMENT was never classified — so a precedent distinguished N times got the same
authority boost as one followed N times (INV-COR2 violation), and the signal never
reached the agents' reasoning. Wires the full path:
Phase 1 — scripts/classify_citation_treatments.py: classify each linked edge's
treatment (followed/distinguished/…) from its match_context via
corroboration.classify_treatment (Opus 4.8 @ xhigh, local), filling
precedent_internal_citations.treatment. Idempotent.
Phase 2 — db.refresh_verified_layer: count only NON-negative treatments toward
verified/cite_count (INV-COR2/COR4). Unclassified counts as neutral-positive so
the signal degrades gracefully before classification runs.
Phase 3 — db.citation_authority(ids): per-precedent {total, positive, negative,
unclassified, by_treatment}. Surfaced as `cited_by` in search_precedent_library
hits and precedent_library_get, and `treatment` per incoming citation.
Phase 4 — legal-researcher/analyst/writer prompts: weigh & ARGUE authority
("הלכה שאומצה ב-N החלטות ועדת-ערר"), flag distinguished/overruled, never invent
the count (INV-AH; writer is read-only of the analyst).
Auto-approval stays kill-switched off (chair gate preserved, INV-G10). No schema
change (treatment column already existed). Operational: run the classifier +
refresh_verified_layer over the 379 edges, then sync agents across companies.
Invariants: G2 (one classifier + one authority query, reused), INV-COR2/COR3/COR4
(negative never corroborates; point-specific; ≥N), INV-G10 (no auto-approval),
INV-AH (no invented numbers).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
update_task וקרוביו (update/expand/analyze/research/parse_prd/scope) קוראים
ל-backend-LLM של TaskMaster ונתקעים שוב ושוב. נחסמים ב-permissions.deny.
עדכוני-תוכן של משימות ייעשו בעריכה ישירה של .taskmaster/tasks/tasks.json
(אותו מאגר — תואם feedback_taskmaster_cli_cwd). הכלים הדטרמיניסטיים
(get_tasks/get_task/next_task/set_task_status/add_task/move_task/…) נשארים.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
המשך אבחנת ה-heartbeat-timeout (#120): שלב 4 בזרימת חילוץ-הספרייה של ה-CEO הורה
להריץ `corroboration_rebuild()` עם ארגומנט ריק = `build_all()` שעובר על כל הקורפוס
עם קריאת-LLM (Opus xhigh) לכל ציטוט-נכנס = שעות → חורג מ-heartbeat של שעה
(timeout/process_lost). זה רץ בכל ריצת חילוץ-ספרייה, מיד אחרי החילוץ — כך שגם אחרי
שהחילוץ הפך לתיק-בודד (#120), שלב הקורובורציה היה ממשיך ל-timeout.
תיקון: הפרומפט מורה כעת `corroboration_rebuild(case_law_id="<issue>")` — מסוקף לתקדים
הבודד (bounded, דקות), עם אזהרה מפורשת לא להריץ ריק. ה-backfill המלא של כל-הקורפוס
נשאר ב-pipeline המקומי הדורבילי (scripts/final_halacha_pipeline.py, X16 checkpoint/resume).
קובץ-פרומפט בלבד — נקרא חי דרך instructionsFilePath מהעץ הראשי (אין deploy ל-Coolify;
דורש git pull בעץ הראשי אחרי מיזוג). leak_guard עובר.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
מפריד בין ריקון-באקלוג המוני לבין חילוץ per-upload, ומסיר את ה"פקק" שגרם
timeout/process_lost ב-heartbeat של ה-CEO.
הבעיה (אבחנה 2026-06-11): לחיצת "חלץ הלכות" על תיק בודד יצרה issue (CMP-165)
שהורה ל-CEO להריץ precedent_process_pending(halacha) — בולען סינכרוני שמרוקן את
כל התור ההיסטורי (147 ממתינים, שעות) בתוך heartbeat שחסום לשעה. תוצאה: timeout
כל שעה → process_lost בפירוק קבוצת-התהליכים → retry → סטורם, והתיק הבודד (FIFO
אחרון) לא טופל. לא OOM, לא קוד שבור — אי-התאמה ארכיטקטונית.
התיקון:
1. per-upload (web/paperclip_client.py, wake_for_precedent_extraction): גוף ה-issue
+ תיאור-הפרויקט מורים כעת להריץ precedent_extract_metadata +
precedent_extract_halachot ל-case_law_id של ה-issue **בלבד** — עם אזהרה
מפורשת לא להריץ process_pending. reextract_halachot כבר מנקה requested_at
ומסמן completed → התיק לא יחזור לתור הלילי.
2. הוראות ה-CEO (.claude/agents/legal-ceo.md): אותו שינוי — חילוץ תיק-בודד, לא
ריקון-תור. (צריך sync_agents_across_companies.py --apply אחרי מיזוג.)
3. ריקון-באקלוג (scripts/drain_halacha_queue.py): שער חלון-לילה 23:00–05:00 שעון
ישראל (zoneinfo, DST-safe — המכונה UTC). מחוץ לחלון ===SKIP===; נעצר ===STOP===
כשהחלון נסגר, השאר ממשיך בלילה הבא (FIFO + per-chunk checkpoint). env:
HALACHA_DRAIN_WINDOW_START/_END/_TZ.
4. cron (scripts/legal-halacha-drain.config.cjs): UTC band 20:00–03:00 שמכסה את
חלון-ישראל בשני מצבי-DST; הסקריפט גוזם לחלון המדויק. ירייה שעתית מחדשת
one-shot שמת (advisory-lock → חפיפה בטוחה).
רשת-ביטחון: request_halacha_extraction עדיין מסמן requested_at, כך שאם wakeup
ל-CEO נכשל — הדריינר הלילי יתפוס את התיק (בלילה, חסום), אך שום נתיב יומי לא
מרוקן את כל התור.
Invariants: מקיים G12/INV-PORT1 (paperclip_client = shell; leak_guard עובר).
נוגע X16 (durability — מתקציב-זמן heartbeat ל-job ייעודי).
בדיקות: py_compile ✓ · window-logic + zoneinfo ✓ (17:00 IDT→False) · leak_guard ✓.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
כל סוכני המערכת טוענים את ה-system prompt מקובץ תחת .claude/agents/ דרך
instructionsFilePath (claude_local + gemini_local), פרט ל-Hermes/curator על
deepseek_local שתמך רק ב-promptTemplate inline ב-DB — מסלול-פרומפט מקביל (הפרת G2),
לא מגורסת ב-git, ושני המקורות (DB ↔ hermes-curator.md) כבר התפצלו בתוכן.
מה השתנה:
- adapters/deepseek-paperclip-adapter: buildPrompt קורא instructionsFilePath אם הוגדר
(resolveTemplate; עדיפות file > promptTemplate > DEFAULT). הקובץ עובר renderTemplate
כך ש-{{wakeReason}}/{{#taskId}}/… ממשיכים לעבוד. כשל-רועש אם הקובץ הוגדר ואינו
קריא — לא fallback שקט (כלל-הנדסה §6, feedback_silent_swallow).
- hermes-curator.md הופך ממסמך-תיעוד למקור-האמת בפועל: מיזוג current-from-both —
ה-runbook התפעולי מה-DB (PIPELINE-WAKE/X16 + §A/§B + interactions) + שער
anti-hallucination (INV-AH) וקריאת-ספ (INV-AG1) שהיו רק ב-md ומעולם לא הגיעו
ל-runtime של הרמס. ה-ingest_final_version/lessons הידני הושמט — ה-pipeline (X16)
כבר מריץ אותו durably; הרצה ידנית הייתה כפילה.
נותר תפעולי (לא ב-git): עדכון 2 רשומות deepseek_local ב-Paperclip DB
(instructionsFilePath=.../hermes-curator.md, ריקון promptTemplate) + git pull בעץ
הראשי + pm2 restart paperclip + sync-agents.
Invariants: מקיים G2 (ביטול מסלול-פרומפט מקביל), G12/X15 (מגע-פלטפורמה רק במעטפת
המוצהרת — adapter), INV-AH + INV-AG1 (מגיעים סוף-סוף ל-Hermes), כלל-הנדסה §6
(כשל-רועש). ללא שינוי התנהגות-runtime פרט להוספת שער-ה-AH (כוונה מפורשת, אישור יו"ר).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
הוחלף ב-legal-analyst-gemini-critique.md (שטן מליץ); 0 סוכנים מצביעים אליו.
שירת רק את ניסוי-ההשוואה החד-פעמי מול Opus (מתועד ב-comparison-opus-vs-gemini.md
ובזיכרון). אין סיבה לשמור קוד מת.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
מחלץ את דיסציפלינת מניעת-ההזיות לבלוק קנוני אחד (docs/anti-hallucination-gate.md)
ומחיל אותו אחיד על כל הסוכנים — במקום שכל סוכן ימציא אותה מחדש ad-hoc (G2: בלי מסלולים מקבילים).
5 טכניקות, כל אחת מעוגנת במקור מקצועי:
- AH-1 עיגון-מקור (אפס ציטוט מהזיכרון) — Stanford RegLab/Magesh JELS 2025 (כלי-RAG משפטיים הוזים 17-33%)
- AH-2 quote-or-retract + AH-3 abstention — Anthropic Reduce-hallucinations
- AH-4 תיוג-ודאות — NIST AI RMF GenAI Profile + RAGAS
- AH-5 Chain-of-Verification — Dhuliawala et al. arXiv:2309.11495
הפצה DRY: הפניה ב-HEARTBEAT.md (נקרא ע"י כל סוכני Paperclip) + שורה אחידה בבלוק
'קרא לפני פעולה' של כל 8 הסוכנים, עם הערת-יישום לכל תפקיד (writer=read-only, qa=אוכף,
proofreader=אל תתקן לכיוון מונח משפטי, exporter=אפס מהות חדשה).
בנוסף: legal-ceo.md מקבל ידע על 'שטן מליץ (Gemini)' עם מדיניות on-demand טהורה —
לא בפייפליין, מופעל רק לבקשת חיים/דפנה, הפלט=לידים ליו"ר (לא לכותב, human-in-the-loop).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
עותק של legal-analyst שרץ תחת gemini_local (Gemini CLI, gemini-3.1-pro-preview)
לצורך השוואת איכות-ניתוח מול Opus. מצב read-only: שלבי extract/aggregate/case_update
מוחלפים בקריאה בלבד, והפלט נכתב ל-analysis-and-research.GEMINI.md בלבד — כדי לא לדרוס
את ניתוח-Opus הקנוני. אכיפת read-only גם ברמת MCP (excludeTools ב-~/.gemini/settings.json).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
סוגר את לולאת-הלמידה (INV-LRN4): כל החלטה נסגרת מול הסופי, וכל סופי
מנותח מול הטיוטה. מזין את הטבלאות ש-T15 כבר קורא מהן.
T5 — פנקס-התאמה:
- SCHEMA_V26: טבלת draft_final_pairs (snapshot draft + final + diff + analysis + status).
- db: create/update/list_draft_final_pairs.
- mark-final (app.py): תופס snapshot של הטיוטה (decision_blocks) ברגע החתימה,
לפני שאפשר לדרוס אותו, ופותח שורת-פנקס (status=final_received).
T4 — דיסטילציה אוטומטית:
- learning_loop.process_final_version: משתמש ב-snapshot (לא בבלוקים שאולי השתנו),
מסווג style_method↔substance, שומר הצעה ב-pair (status=analyzed).
**הוסר ה-auto-upsert של style_patterns** — ביטל את ה-bug שדרס את שער-היו"ר
וזיהם סגנון במהות (INV-LRN1 + INV-LRN5).
- LESSONS_PROMPT: הפרדת style_method↔substance מפורשת + לקח מופשט בלבד.
- curator wake + hermes-curator.md: מריץ ingest_final_version ראשון; מציע רק
style_method שלא תועד; substance→מסלול precedent.
INV-LRN1 (שער-יו"ר, אין auto-commit) · INV-LRN4 (ניגוד-אמת) · INV-LRN5 (טוהר).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
הספ (docs/spec/, G1–G11) חובר לסוכני Paperclip דרך INV-AG1 אבל לא למסלול
שבו רוב הקוד נכתב בפועל — הסשן האינטראקטיבי של Claude Code. סוגר את הפער
לפני מחזור-2 (FU-9..15), שהוא כולו כתיבת-קוד.
שלוש שכבות אכיפה:
1. תיעוד — CLAUDE.md §"פרוטוקול כתיבת-קוד" + docs/spec בטבלת-הייחוס
2. hook — scripts/spec-guard.sh (PreToolUse על Edit/Write/MultiEdit, רשום
ב-.claude/settings.json) מזכיר פעם-בסשן בכל נגיעה בקובץ-קוד; non-blocking
3. PR — .gitea/PULL_REQUEST_TEMPLATE.md עם סעיף-חובה "Invariants"
המקבילה האינטראקטיבית ל-INV-AG1 שכבר אוכף על הסוכנים (HEARTBEAT §"קריאת-ספ").
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
סוגר את לולאת פידבק-יו"ר→ידע-סוכנים. עד כה resolve רק עדכן את ה-DB; עכשיו
לחיצה ב-/feedback מעירה את ה-CEO שמקפל את הלקח לקובץ לפי הקטגוריה.
- paperclip_client.py: wake_ceo_for_feedback_fold() — יוצר issue ב-Paperclip
עם הלקח + rubric ניתוב (style→SKILL.md, wrong_structure→block-schema,
אחר→lessons.md), מעיר CEO. משכפל את דפוס wake_for_precedent_extraction
- db.py: get_chair_feedback(id) — שליפת הערה בודדת עם case_number/appeal_type
- app.py: resolve endpoint מקבל fold (ברירת מחדל true); BackgroundTask
fire-and-forget; guard — רק עם lesson_extracted. מחזיר fold_queued
- legal-ceo.md: dispatch ל-feedback_fold_ + סעיף "קיפול הערת יו"ר" עם rubric
- frontend: useResolveFeedback מקבל fold; /feedback שולח fold=true עם toast;
drafts-panel שולח fold=false (bookkeeping per-case, בלי קיפול כפול)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
חיווט ספ-המערכת לסוכני-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>
Root cause of "agent can't find the Agasi decision in the corpus" (CMPA-55):
the decision was fully ingested, but the retrieval layer failed on the
realistic agent query — searching by case name.
- RC-A (#52): lexical tsvector covered only chunk content + halacha text,
so a bare-name query ("אגסי") matched decisions that *cite* the case, not
the case itself. Add meta_tsv on case_law(case_name, case_number) (SCHEMA
V20) and OR it into the lexical halacha/chunk SQL with a match boost, so a
name/number hit surfaces the case's own rows. Agasi: rank 4 → rank 1.
- RC-B (#53): precedent_library_list hard-defaulted source_kind=external_upload
and never exposed the param, hiding uploaded ערר/בל"מ (internal_committee)
decisions. Thread source_kind through service → tool → MCP tool (supports
'internal_committee' / 'all_committees').
- #54: agent instructions (researcher/analyst/writer) — search-by-name
protocol: add content/case-number, search both corpora, use all_committees
before declaring "not in corpus".
- #55: chunker produced tiny fragment chunks ("דיון", "החלטה") from header
keywords matched mid-sentence. Anchor SECTION_PATTERNS to line start +
merge sub-min sections; exclude <50-char fragments at query time (484
existing fragments hidden; full re-chunk tracked as #57).
Tests: scripts/test_retrieval_by_name.py (name ranks case above citer +
substantive regressions); chunker unit checks (0 tiny chunks). New findings
filed as tasks #56 (halacha source_kind leak) and #57 (re-chunk migration).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Six-phase upgrade of /training from a read-only dashboard into a full
Style Studio for managing Daphna's style corpus.
- Upload Sheet on /training: file → proofread preview → commit (no more
CLI-only `upload-training` skill).
- Rich corpus metadata: GET /api/training/corpus returns summary, outcome,
key_principles, page_count, parties (regex), legal_citation, lessons_count.
PATCH endpoint for chair edits. CorpusDetailDrawer with 4 tabs (details
/content/lessons/patterns) replaces the bare table row.
- LLM metadata enrichment: style_metadata_extractor + MCP tools
(style_corpus_enrich, style_corpus_pending_enrichment) fill summary
/outcome/key_principles via claude_session (free, host-side).
- Per-decision lessons: new decision_lessons table + 4 REST endpoints +
LessonsTab in drawer; hermes-curator now auto-posts findings as
decision_lessons(source=curator).
- Curator Portrait tab: prompt rendered with link to Gitea, recent
curator findings, style_analyzer training prompts, propose-change
form that writes proposals to data/curator-proposals/ for manual
chair review (no auto-mutation of the agent file).
- Style chat tab: SSE-streamed conversations with the style agent.
New host-side pm2 service (legal-chat-service, port 8770) wraps
claude CLI with stream-json + --resume continuation; FastAPI proxies
via host.docker.internal. Zero API cost — uses chaim's claude.ai
subscription. chat_conversations + chat_messages persist history.
Architecture: keeps the existing rule that claude_session only runs
on the host (not the container). The new legal-chat-service is the
canonical bridge between the container and the local CLI for the chat
feature; everything else (upload, metadata, lessons) stays within the
container's existing capabilities.
Audit script (scripts/audit_training_corpus.py) included for verifying
which corpus rows still need enrichment.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Same case_number can exist as both a regular appeal (ערר) and an
extension-of-time request (בל"מ), and we were inferring the difference
from appeal_subtype prefixes — fragile, and case-number lookups
weren't disambiguated. Now stored as a first-class field on both
case_law (corpus) and cases (live cases), with partial unique indexes
on (case_number, proceeding_type).
- SCHEMA_V15: column + CHECK constraints + backfill from
appeal_subtype LIKE 'extension_request_%' + partial unique indexes
replace the old global UNIQUE(case_number).
- derive_proceeding_type() centralizes the inference rule
(extension_request_* → בל"מ; subject regex fallback; default ערר).
- Metadata extractor prompt asks Claude to populate the new field
explicitly; apply_to_record writes it for internal_committee rows.
- internal_decision_upload, case_create, case_update accept an
optional proceeding_type; FastAPI request models expose it.
- Wizard + edit dialog get a sided Select; case header renders the
resolved label (ערר / בל"מ).
- Uploaded the 2 staged בל"מ decisions on betterment levy:
8126/24 (סופר נוח, 13 chunks), 8047/23 (הרנון, 48 chunks).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four parallel sub-agents closed the remaining critical gaps from the
26/05 Stage A/B sprint. Each block independently tested; aggregated here.
## #30/#31 finalizers (sub-agent A)
* Auto-derive practice_area in case_create from case_number prefix
(1xxx→rishuy_uvniya, 8xxx→betterment_levy, 9xxx→compensation_197);
default for CaseCreateRequest is now "" (the DB constraint catches
any stray "appeals_committee").
* practice_area.py: derive_subtype now handles axis-B domain values
(rishuy_uvniya/betterment_levy/compensation_197) without parsing the
case number; new helper derive_domain_practice_area().
* Halacha re-extraction verified unnecessary — all 6 reclassified
records already had is_binding=false and approved halachot.
* Regression tests: 6 cases in tests/test_corpus_constraints.py
covering practice_area enum, internal-committee chair/district,
external-upload arar prefix, MCP guard.
* UI: district input → Select dropdown (7 districts) in
precedent-edit-sheet.tsx, preserving legacy free-text values.
## #37 בל"מ subtypes (sub-agent B)
* 3 new appeal_subtypes: extension_request_{building_permit,
betterment_levy,compensation}. APPEALS_COMMITTEE_SUBTYPES extended,
SUBTYPES_BY_AREA mappings added.
* New helpers: is_blam_subject(), is_blam_subtype(),
derive_subtype_with_blam(case_number, subject, practice_area).
case_create now uses it to auto-detect "בקשה להארכת מועד" subjects.
* 3 methodology templates under docs/methodology/extension-request-*.md.
* paperclip_client.py mapping updated for the 3 new subtypes
(extension_request_building_permit→CMP, the other two→CMPA).
* Frontend: bilingual "בל"מ" badge + filter dropdown on cases list +
detail header; appeal-type-bars collapseBlam() merges בל"מ into its
parent domain for aggregate bars.
* Wizard auto-detects בל"מ from subject during case creation.
* 3 Berlinger cases (1017/1018/1019-03-26) migrated to
appeal_subtype=extension_request_building_permit via psql.
## #35 missing_precedents feature (sub-agent C)
* Schema V13: missing_precedents table (citation, case_id, party,
legal_topic, status, linked_case_law_id, claim_quote, ...) +
FK constraints + 3 indexes. Applied via psql + idempotent migration.
* 6 db.py service functions, 3 MCP tools, 6 FastAPI endpoints
(POST/GET/PATCH/DELETE/upload — upload routes by citation prefix
to ingest_internal_decision or ingest_precedent).
* Next.js page /missing-precedents with 5 status tabs + filters +
sidebar badge counter + detail drawer with metadata edit + smart
upload form that switches fields per committee/court.
* Bootstrap: 7 rows imported from the JSON file
(3 citations × cases, all status=closed with linked_case_law_id).
* legal-researcher.md: new §2ב.5 with missing_precedent_create
usage + dedup semantics + tool grant.
## #36 legal_arguments aggregation (sub-agent D)
* Schema V14: legal_arguments + legal_argument_propositions M:M.
Applied via psql.
* New service argument_aggregator.py with two functions —
aggregate_claims_to_arguments() (Claude CLI / claude_session) and
get_legal_arguments(). Graceful llm_unavailable handling when CLI
is missing (containers).
* 2 MCP tools + 2 API endpoints (POST .../aggregate-arguments as
BackgroundTask, GET .../legal-arguments).
* Frontend: shadcn Accordion + new legal-arguments-panel.tsx with
hierarchical (party → priority badge → arguments) display, "טיעונים"
tab on the case page, "חשב/חשב מחדש" buttons.
* scripts/backfill_legal_arguments.py + SCRIPTS.md entry — dry-run
found 8 candidate cases including 1017/1018/1019.
## Open follow-ups (intentionally deferred)
* npm run api:types in web-ui (CLAUDE.md flow) — recommended before
the next UI commit; not required for backend deployment.
* Run backfill_legal_arguments.py --apply once the container picks up
the new aggregator service.
* webhook on missing-precedents upload-close to Paperclip (optional).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Document new daphna-procedural-patterns.md cataloging the
"appraiser clarification request" interim-decision pattern observed in
8174-24 — structure only, not phrasing (case is an outlier example).
- daphna-decision-tree.md §0.5: gating question before main tree
- legal-ceo.md voice docs table: register procedural patterns doc
- legal-writer.md: mandatory consultation when pattern_tag is set,
with explicit warning against copying 8174-24 wording
Approved via interaction request_confirmation (CMPA-15) 2026-05-17.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The legal-analyst agent was generating a longer placeholder form
[ימולא ע"י יו"ר הוועדה — עמדה/הנחיה לגבי סוגיה זו שתשמש את סוכן הכתיבה]
which _is_placeholder() did not match (substring check fails because ] is
further along in the longer form). Result: UI showed "✓ עמדה נקבעה" (green)
for all 4 issues even though no chair direction had been entered.
Fixes:
1. research_md.py: add regex fallback — any text starting with [ימולא is a placeholder
2. legal-analyst.md: template now emits the standard short placeholder only
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Model drift (instructions → match DB):
- CEO: claude-sonnet-4-6 → claude-opus-4-6 (DB runs opus; CEO needs opus quality)
- מנתח/כותב/מגיה: claude-opus-4-7 → claude-opus-4-6 (DB runs 4-6; no 4-7 in adapter)
legal-proofreader.md:
- {issue-id} placeholder → $PAPERCLIP_TASK_ID בשני המקומות (done + blocked)
legal-researcher.md:
- הוסף reference ל-HEARTBEAT.md בראש הקובץ
legal-qa.md:
- הבהרת שיטת בדיקת corpus_queries_logged: grep ידני בלבד, לא validate_decision
CLAUDE.md (curator):
- הוסף תהליך אישור הצעות curator: comment → חיים מאשר → commits ל-SKILL.md/lessons.md
maxConcurrentRuns CEO: כבר 2 ב-DB — לא נדרש שינוי
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CEO (legal-ceo.md):
- הסרת company UUID ו-project UUID קשוחים בדוגמת יצירת issue
- שימוש ב-$PAPERCLIP_COMPANY_ID לחברה
- project_id נשלף דינמית מה-issue ההורה דרך $PAPERCLIP_TASK_ID
researcher (legal-researcher.md):
- הוסף mcp__legal-ai__search_internal_decisions לרשימת tools
- הוסף סעיף 2ב.2א המסביר את ההבדל: search_decisions = דפנה בלבד;
search_internal_decisions = כל ועדות הערר בכל המחוזות
- הוראות מתי להשתמש + אזהרת היררכיה (ועדת ערר < מחוזי)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CEO wakes for weekly-feedback-job via agents.invoke without issueId,
so $PAPERCLIP_TASK_ID is empty. Removed steps 4-5 (comment + close
issue) from handler — now file-write only with stdout logging.
Also commits pending docs and agent instructions from prior session.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
If pc_wake_ceo fails, the endpoint now raises HTTP 502 and skips the
case_update to processing — preventing cases from silently getting stuck
with no CEO running. Also adds `processing` to CEO routing table and
updates case_list docstring with full status list.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
A/B test (2026-05-05) showed DeepSeek V4-Pro is 2-3x faster and ~20x cheaper
than Sonnet for style/lexicon pattern analysis, with comparable quality.
Adds adapters/deepseek-paperclip-adapter/ package, documents adapter requirements
(env injection, run-id headers), updates CLAUDE.md with adapter integration notes,
and records lessons from ערר 1200-25 (block order for 1xxx, "להלן מתוך" pattern,
expanded factual background, bridge planning analysis, flat heading structure).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The curator's promptTemplate (stored in DB) now teaches Hermes how to
post issue_thread_interactions instead of free-text comments. Three
patterns supported, curator picks per context:
- ask_user_questions for filtering findings (multi-select)
- request_confirmation for accept/reject of a single proposal
- suggest_tasks for proposing follow-up issues
Verified end-to-end on CMP-71: curator hit a real obstacle (couldn't
read the final DOCX from its container) and chose request_confirmation
on its own to ask the user how to proceed — exactly the conversational
behavior we want.
Paperclip auto-wakes the curator with $PAPERCLIP_APPROVAL_ID when the
user responds. The new prompt has a §B branch that handles the second
wake (read response → act → close).
The UI side was already built in d099470 (mirror Paperclip interactions
in case page) — now Hermes-side agents produce interactions too, not
just claude_local agents.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous F2 stage in legal-ceo.md fired after the first DOCX export
— too early, since the user often iterates with עריכה-* uploads after
the first export. The true "this is dafna's chosen final" signal is the
"סמן כסופי" button in the UI, which calls api_mark_final.
This commit moves the curator wakeup from CEO's instructions to a
direct hook in api_mark_final:
- web/paperclip_client.py: add CURATOR_AGENTS dict (CMP + CMPA UUIDs)
and wake_curator_for_final() helper. Looks up main case issue,
creates a child issue assigned to the curator, tags plugin_state for
case visibility, and triggers wakeup via Paperclip API.
- web/app.py: api_mark_final now calls workflow_tools.ingest_final_version
(so case_law table finally gets populated for search_decisions) and
pc_wake_curator_for_final. Both are best-effort — failure does not
block marking final.
- legal-ceo.md: remove F2 stage, leave only the agents-table reference
noting the curator runs from api_mark_final.
- hermes-curator.md: update activation description to reflect the new
flow.
Result: curator runs only when chaim deliberately clicks "סמן כסופי",
on the actual final file, with no risk of analyzing a draft that will
later change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds new sub-agent "מנהל ידע" (hermes_local adapter) that runs after
each successful export to analyze the final decision and suggest updates
to skills/decision/SKILL.md and lessons. Read-only on case data, write
only on a single comment per run.
- legal-ceo.md: new stage F2 after F (export). Looks up curator by name
in current company, creates async sub-issue, no waiting. Falls back to
silent skip if no curator configured.
- legal-ceo.md: agents table updated with both curator UUIDs (CMP + CMPA).
- hermes-curator.md: role instructions documenting CMP/CMPA split and
what the curator does/does not do.
Stage 1 POC. End-to-end validated on CMP-68 (case 1130-25) with two
substantive findings on style patterns. CMPA agent created with separate
~/.hermes/profiles/curator-cmpa profile (own MEMORY.md focused on
היטל השבחה / פיצויים).
Known gaps to follow up: curator does not auto-close its issue, does
not auto-persist findings to MEMORY.md, comment attribution falls back
to chaim's user (install-key) — these are tracked separately and do
not block validation.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings the legal-ai ↔ Paperclip integration in line with the official
Paperclip skill. Net effect: HEARTBEAT.md -47% (370→195 lines), all 14
agents on uniform runtime_config + budget + instructionsBundleMode, and
two cross-company helpers replacing manual SQL.
Highlights:
- HEARTBEAT.md refactor: project-specific only, delegates to the official
paperclipai/paperclip skill (loaded per agent). Adds heartbeat-context
fast-path (§1.7) and PAPERCLIP_WAKE_PAYLOAD_JSON shortcut (§1.5).
- Issue Thread Interactions API: legal-ceo.md now uses
ask_user_questions / request_confirmation / suggest_tasks instead of
free-text comments — gives chair structured UI with idempotency keys.
- pc.sh + paperclip_api.pc_request: every API call goes through helpers
that inject Authorization + X-Paperclip-Run-Id (audit trail).
- sync_agents_across_companies.py: master(CMP)→mirror(CMPA) sync via
Paperclip API, idempotent, with --verify and --apply modes.
- skills/new-company-setup: 11-step blueprint distilling all 11 gaps
into a single onboarding runbook for the next company.
- .taskmaster: 12 tasks covering each gap (one already closed: #29).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>