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>
102 lines
10 KiB
Markdown
102 lines
10 KiB
Markdown
# X9 — חוזה כלי-ה-MCP (Agent MCP Tool Contract)
|
||
|
||
קובץ-תחום זה כפוף ל-[חוקת המערכת](00-constitution.md) והוא ה-deep-dive על **משטח כלי-ה-MCP** —
|
||
71 הכלים ש-[mcp-server](../../mcp-server/) חושף לסוכני Paperclip (CEO/analyst/researcher/writer/qa/…).
|
||
עד כה הספ תיאר *מה הסוכנים עושים* ([X4-agents.md](X4-agents.md)) אך לא **חוזה-הכלים** עצמו: envelope,
|
||
שמות, idempotency, סימטריית extract/get, ומפת-הרשאות. הקובץ מגדיר את הכללים; הממצאים → [gap-audit.md](gap-audit.md).
|
||
|
||
> **מודלי-סמכות מעורבים.** TOOL1/TOOL2/TOOL3/TOOL5 הם **הנדסיים** (עיצוב-API/כלים — ≥3 מקורות).
|
||
> TOOL4 ו-TOOL6 הם **פרויקטלי-תפעוליים**, הנקשרים ל-[G2](00-constitution.md#inv-g2-מקור-אמת-יחיד--אין-מסלולים-מקבילים-מתפצלים)
|
||
> ו-[G10](00-constitution.md#inv-g10-המערכת-מסייעת--שערים-אנושיים-הם-invariant).
|
||
|
||
---
|
||
|
||
## 1. אינוונטר (71 כלים, [server.py](../../mcp-server/src/legal_mcp/server.py))
|
||
|
||
| דומיין | כלים (מייצג) |
|
||
|--------|--------------|
|
||
| ניהול-תיק | case_create/list/get/update/delete, case_get_final_text |
|
||
| מסמכים | document_upload, document_upload_training, document_list/get_text/update, extract_references |
|
||
| טענות+טיעונים | extract_claims, get_claims, aggregate_claims_to_arguments, get_legal_arguments |
|
||
| **חיפוש (6 — חופפים)** | search_decisions, search_case_documents, find_similar_cases, search_internal_decisions, search_precedent_library, precedent_search_library |
|
||
| **כתיבת-בלוק (6 — חופפים)** | draft_section, get_block_context, write_block, write_all_blocks, write_interim_draft, save_block_content |
|
||
| ייצוא/QA | export_docx, export_interim_draft, validate_decision, revise_draft, list_bookmarks, apply_user_edit |
|
||
| פסיקה (3 תת-מערכות) | case-attached (precedent_attach/list/remove/search_library) · library (precedent_library_*) · internal (internal_decision_*) |
|
||
| הלכות | halacha_review, halachot_pending, precedent_extract_halachot/metadata, precedent_process_pending |
|
||
| ציטוטים | extract_internal_citations, list_internal_citations, list_incoming_citations |
|
||
| missing-precedents | missing_precedent_create/list/close |
|
||
| workflow/feedback | workflow_status, get_metrics, processing_status, set_outcome, brainstorm_directions, approve_direction, ingest_final_version, record/list_chair_feedback |
|
||
| appraiser/style | extract_appraiser_facts, style_corpus_enrich, style_corpus_pending_enrichment |
|
||
|
||
---
|
||
|
||
## 2. Invariants של התחום
|
||
|
||
### INV-TOOL1: envelope-תשובה עקבי לכל הכלים
|
||
**כלל:** כל כלי מחזיר **מבנה אחיד** (למשל `{status, data, message}`) — לא string-לפעמים-JSON-לפעמים-`{error}`.
|
||
שגיאה מובחנת ממצב-ריק ממצב-הצלחה באופן עקבי. מופע של [G2](00-constitution.md#inv-g2-מקור-אמת-יחיד--אין-מסלולים-מקבילים-מתפצלים);
|
||
מקביל ל-[X6 INV-UI3](X6-ui-api-contract.md). **הנדסי.**
|
||
**מקורות:** Anthropic — *MCP / tool result conventions* (https://modelcontextprotocol.io/) ·
|
||
JSON-RPC 2.0 (result/error envelope) (https://www.jsonrpc.org/specification) · RFC 9457 (Problem Details) | סטטוס: verified
|
||
**אכיפה:** wrapper-תשובה משותף בכל הכלים. **כיום אין** — מעורב.
|
||
**הפרה ידועה:** `search_*` מחזיר `"לא נמצאו תוצאות."` או JSON; חלק `{error}`, חלק raise ([gap-audit GAP-48](gap-audit.md)).
|
||
|
||
### INV-TOOL2: שמות עקביים + חיפוש לפי-קורפוס
|
||
**כלל:** שמות-הכלים עוקבים אחר convention אחיד, ושם משקף התנהגות. כלי-חיפוש מובחנים **לפי הקורפוס**
|
||
(style / internal / external / case-attached), לא ב-6 שמות חופפים; כלי-כתיבת-בלוק אינם חופפים (context מול write).
|
||
מופע של [G2](00-constitution.md#inv-g2-מקור-אמת-יחיד--אין-מסלולים-מקבילים-מתפצלים) ("סימטריה", [§6](00-constitution.md#6-כללי-הנדסה-מונעים-הישנות)). **הנדסי.**
|
||
**מקורות:** Anthropic — *Writing effective tools / clear names* (https://www.anthropic.com/engineering/writing-tools-for-agents) ·
|
||
Google *API Design Guide* (naming) (https://cloud.google.com/apis/design/naming_convention) ·
|
||
Zalando *RESTful API Guidelines* | סטטוס: verified
|
||
**אכיפה:** איחוד/מיזוג כלי-חיפוש + כלי-בלוק; rename של שמות-מטעים. **כיום אין.**
|
||
**הפרה ידועה:** `precedent_search_library` מחפש למעשה quotes מצורפים-לתיק (שם מטעה); 6 כלי-חיפוש + 6 כלי-בלוק חופפים ([gap-audit GAP-49/50](gap-audit.md)).
|
||
|
||
### INV-TOOL3: idempotency בכל כלי-מוטציה
|
||
**כלל:** כלי שמשנה-מצב הוא **idempotent על מפתח דטרמיניסטי** — קריאה חוזרת אינה יוצרת כפילות. מופע של
|
||
[G3](00-constitution.md#inv-g3-ingest-אחיד-ו-idempotent). **הנדסי.**
|
||
**מקורות:** Stripe — *Idempotent requests* (https://docs.stripe.com/api/idempotent_requests) ·
|
||
Kleppmann *DDIA* (idempotence) · IETF — *Idempotency-Key header* draft (https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/) | סטטוס: verified
|
||
**אכיפה:** upsert/ON CONFLICT (או בדיקת-מפתח ברמת-אפליקציה) בכלי-מוטציה. **GAP-52 ✅ נסגר (2026-06-06):** `case_create` (מפתח case_number, UNIQUE), `precedent_attach` (מפתח case_id+section_id+citation+quote), `document_upload` (מפתח case_id+SHA-256 של הקובץ — מדלג על OCR/embed כפול) — כולם מחזירים את הקיים במקום כפילות. נבחרה בדיקת-מפתח ברמת-אפליקציה (לא UNIQUE-constraint) כדי לא לשבור startup על נתונים-קיימים כפולים. קודמים: `missing_precedent_create`/`precedent_link_cases`/`extract_internal_citations`.
|
||
**הפרה ידועה:** —
|
||
|
||
### INV-TOOL4: סימטריית extract/get + persistence
|
||
**כלל:** לכל כלי-חילוץ שכותב ל-DB יש **כלי-קריאה (get) מקביל**, והפלט **נשמר durably** (לא מוחזר-ונאבד).
|
||
מופע של [G2](00-constitution.md#inv-g2-מקור-אמת-יחיד--אין-מסלולים-מקבילים-מתפצלים) (מקור-אמת נגיש). **פרויקטלי-תפעולי.**
|
||
**מקור-סמכות:** דפוס `extract_claims`↔`get_claims`, `aggregate`↔`get_legal_arguments` ב-[server.py](../../mcp-server/src/legal_mcp/server.py).
|
||
**אכיפה:** לכל extract — get מקביל. **GAP-44 ✅ + GAP-45 ✅ נסגרו (2026-06-06):** נוסף `get_appraiser_facts` (קורא `list_appraiser_facts`+`detect_appraiser_conflicts`, ללא חילוץ-מחדש); נוסף `extraction_status` שחושף את עומק תור-החילוץ (metadata/halacha) + גיל הבקשה הוותיקה — read-only.
|
||
**הפרה ידועה:** —
|
||
|
||
### INV-TOOL5: limit-caps על כל כלי-רשימה/חיפוש
|
||
**כלל:** לכל כלי שמחזיר רשימה יש **תקרת-limit נאכפת** (הגנה מפני עומס/DoS); pagination היכן שרלוונטי. **הנדסי.**
|
||
**מקורות:** OWASP API Security Top 10 — *API4:2023 Unrestricted Resource Consumption* (https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/) ·
|
||
Microsoft *REST API Guidelines* (pagination) · Stripe API (limit caps) | סטטוס: verified
|
||
**אכיפה:** clamp ל-max בכל כלי-רשימה. **GAP-53 ✅ נסגר (2026-06-06):** `_clamp_limit` (תקרה 200) על ~13 כלי list/search ב-[server.py](../../mcp-server/src/legal_mcp/server.py); `list_chair_feedback` קיבל param `limit` (server→workflow→db עם `LIMIT`).
|
||
**הפרה ידועה:** —
|
||
|
||
### INV-TOOL6: שלמות-הרשאות — כל כלי שהוראות-הסוכן דורשות מוענק
|
||
**כלל:** מפת-ההרשאות (אילו כלים מוענקים לכל סוכן) **תואמת** את מה שהוראות-הסוכן מצריכות — לא חסר ולא עודף.
|
||
מופע של [G10](00-constitution.md#inv-g10-המערכת-מסייעת--שערים-אנושיים-הם-invariant) (שערים מוגדרים); מפורט ב-[X4-agents.md](X4-agents.md). **פרויקטלי-תפעולי.**
|
||
**מקור-סמכות:** frontmatter `tools:` ב-[.claude/agents/](../../.claude/agents/) מול הוראות-הסוכן.
|
||
**אכיפה:** בדיקת-עקביות tools↔instructions (יעד FU-13).
|
||
**הפרה ידועה:** legal-analyst חסר `aggregate_claims_to_arguments`/`extract_references`/`extract_internal_citations`; researcher חסר טריגרי-חילוץ ([gap-audit GAP-46](gap-audit.md)).
|
||
|
||
---
|
||
|
||
## 3. הערות-עיצוב
|
||
- **set_outcome** — אי-התאמת enum: `block_writer.py:442` משתמש ב-`rejected/accepted/partial`, בעוד
|
||
`lessons.py:11` מגדיר `rejection/partial_acceptance/full_acceptance/betterment_levy`. שתי אוצרות-מילים →
|
||
SSoT יחיד נדרש ([gap-audit GAP-51](gap-audit.md); תואם [X6 INV-UI1](X6-ui-api-contract.md) על enum-סטטוס).
|
||
- **3 מסלולי-קליטת-פסיקה** (library / internal / training) עם ולידציה א-סימטרית — נקשר ל-[01-ingest.md](01-ingest.md) / GAP-01/05.
|
||
|
||
הממצאים המלאים + התיקון → **FU-14** ([gap-audit.md](gap-audit.md)).
|
||
|
||
---
|
||
|
||
## 4. הפניות-אחיות
|
||
- [X4-agents.md](X4-agents.md) — מפת-הסוכנים + ההרשאות (INV-TOOL6).
|
||
- [X8-field-provenance.md](X8-field-provenance.md) — כלי-החילוץ ומה שהם שומרים.
|
||
- [X6-ui-api-contract.md](X6-ui-api-contract.md) — envelope מקביל בצד-ה-API.
|
||
- [01-ingest.md](01-ingest.md), [03-retrieval.md](03-retrieval.md) — מסלולי-קליטה/חיפוש שהכלים עוטפים.
|
||
- [00-constitution.md](00-constitution.md) — [G2](00-constitution.md#inv-g2-מקור-אמת-יחיד--אין-מסלולים-מקבילים-מתפצלים), [G3](00-constitution.md#inv-g3-ingest-אחיד-ו-idempotent), [G10](00-constitution.md#inv-g10-המערכת-מסייעת--שערים-אנושיים-הם-invariant).
|
||
- [mcp-server/src/legal_mcp/server.py](../../mcp-server/src/legal_mcp/server.py), [tools/](../../mcp-server/src/legal_mcp/tools/).
|