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>
13 KiB
X7 — לקוח-Paperclip ופרמטרי-חיבור (Paperclip Client & Connection Parameters)
קובץ-תחום זה כפוף ל-חוקת המערכת ומשלים את X3:
בעוד X3 מתאר את זרימות-האינטגרציה (wakeup, ניתוב comments, webhook), קובץ זה הוא ה-deep-dive
על שכבת-הלקוח והפרמטרים — איך legal-ai מדבר עם Paperclip בקוד (אילו לקוחות, אילו מסלולים),
ועל כל הפרמטרים המחברים (מזהי-חברה/סוכן, env, מפתחות, plugin_state, גזירת company_id).
invariant פרויקטלי-תפעולי. ה-invariants כאן הם עובדות על איך מערכת זו בנויה — אין להן סמכות חיצונית; מקור-הסמכות = ה-runbooks והקוד (root CLAUDE.md, legal-ai/CLAUDE.md, web/paperclip_api.py, web/paperclip_client.py). כל invariant נקשר ל-G גלובלי שהוא משרת — כאן בעיקר G2 (מסלול קנוני יחיד) ו-G9 (עקיבוּת/audit), וכלל-ההנדסה "סימטריה" (חוקה §6).
1. מצב קיים — שני לקוחות מקבילים
ל-legal-ai יש שני לקוחות Paperclip שונים שחיים בו-זמנית, וזהו מקור-השורש לרוב הפערים כאן:
| לקוח | קובץ | אופי | מה מנהל |
|---|---|---|---|
| "current" (API) | web/paperclip_api.py | HTTP דרך pc_request + board API key |
webhooks יוצאים, wakeup חלקי |
| "legacy" (DB-ישיר) | web/paperclip_client.py | חיבור psql ישיר ל-DB של Paperclip + API | projects, issues, comments, wakeup, queries |
legal-ai/CLAUDE.md מתעד ש-paperclip_client.py הוא "legacy — השתמש ב-paperclip_api.py",
אך בפועל ה-legacy עדיין מבצע את רוב העבודה הכבדה (יצירת תיקים/issues, comments, wakeup-ים),
וחלקו דרך INSERT/SELECT ישיר ל-DB של Paperclip — מסלול-מקביל לעוקף את ה-API.
זוהי בדיוק התבנית ש-G2 אוסר: שני מסלולי-קוד מקבילים ליכולת אחת (גישה ל-Paperclip), שמתפצלים ועלולים לסטות.
2. הפרמטרים המחברים (Connection Parameters)
2א. משתני-סביבה
| Var | קורא | ברירת-מחדל | סוד? |
|---|---|---|---|
PAPERCLIP_API_URL |
paperclip_api.py | http://localhost:3100 |
לא |
PAPERCLIP_BOARD_API_KEY |
paperclip_api.py / paperclip_client.py | "" |
כן (board key long-lived, לא JWT) |
PAPERCLIP_DB_URL |
paperclip_client.py:21, app.py:3789 | postgresql://paperclip:paperclip@127.0.0.1:54329/paperclip |
כן — creds בתוך ברירת-המחדל |
PAPERCLIP_COMPANY_ID |
app.py:3976 | 42a7acd0-... (CMP, hardcoded) |
לא |
legalApiBaseUrl |
plugin (instance config) | http://localhost:8085 |
לא |
ראה גם X10-deploy-env-secrets.md — חוזה-ה-env המלא וטיפול-הסודות.
2ב. מזהים קשיחים בקוד (hardcoded) — סתירה ל-X3
paperclip_client.py:36-62 מכיל מזהי-חברה וסוכן קשיחים:
COMPANIES["licensing"] = "42a7acd0-..."(CMP),COMPANIES["betterment"] = "8639e837-..."(CMPA)- CEO/curator/analyst UUIDs לכל חברה (CMP CEO
752cebdd-..., וכו'). - ה-plugin (worker.ts) מכיל CEO IDs קשיחים משלו.
זו סתירה ישירה ל-X3 §1א הקובע "מזהה-ה-CEO נגזר מ-$PAPERCLIP_COMPANY_ID,
לעולם לא UUID hardcoded". הסתירה מתועדת כממצא (gap-audit GAP-26, וכן GAP-56 ב-X10).
2ג. plugin_state keys (חוזה הקישור Paperclip↔legal-ai)
scope_kind |
state_key |
ערך | משמעות |
|---|---|---|---|
issue |
legal-case-number |
מספר-תיק | קישור issue→תיק |
issue |
precedent-case-law-id |
case_law_id | קישור issue→פסיקה לחילוץ |
instance |
webhook-idem-{requestId} |
timestamp | guard idempotency 5 דק' (inbound) |
2ד. גזירת company_id — שתי דרכים שונות
- app.py: נגזר מ-prefix מספר-התיק (
1→licensing,8/9→betterment) (X3 §1ג). - paperclip_client.py: מ-
_FALLBACK_APPEAL_TYPE_TO_COMPANY(מיפוי tag→company) + lookup ב-DB.
שתי דרכי-גזירה לאותו ערך = drift פוטנציאלי (gap-audit GAP-27).
3. צד נכנס (Inbound) — הפלאגין
plugin-legal-ai/src/worker.ts (לא בריפו זה) קורא ל-legal-ai דרך
legalApiBaseUrl. שלושה סוגי-משטח, שכולם חוזה-API שאינו מתועד היום ב-X6:
- 16 כלי
legal_*— עוטפים endpoints של/api/cases/...,/api/search, וכו'. onWebhook— מקבל את ה-webhook היוצא (ראה X3 §1ג ו-INV-INT8 להלן).- 3 cron jobs —
sync-case-status(כל 15 דק'),stale-case-reminder(יומי),weekly-feedback-analysis(שבועי).
4. Invariants של התחום
INV-INT4: לקוח-Paperclip קנוני יחיד — אין לקוח-מקביל ואין גישת-DB ישירה
כלל: כל גישה ל-Paperclip עוברת דרך לקוח-API קנוני יחיד (pc_request/pc.sh). אסור מסלול-מקביל —
לא לקוח שני, ולא INSERT/SELECT/UPDATE ישיר ל-DB של Paperclip. נתונים נקראים/נכתבים דרך ה-API
הרשמי בלבד; ה-DB של Paperclip הוא מקור-האמת של Paperclip, ו-legal-ai אינו מסלול-כתיבה מקביל אליו.
מופע של G2 וכלל "סימטריה" (חוקה §6).
מקור-סמכות: legal-ai/CLAUDE.md ("paperclip_client.py legacy — השתמש ב-paperclip_api.py";
"קריאות API — תמיד דרך helper"); X3 INV-INT3. (פרויקטלי-תפעולי — משרת G2.)
אכיפה: איחוד שני הלקוחות ללקוח-API אחד; הסרת PAPERCLIP_DB_URL כמסלול-כתיבה. כיום אין אכיפה —
שני הלקוחות דו-קיימים (יעד FU-9).
הפרה ידועה: paperclip_client.py — create_project/post_comment-fallback
עושים INSERT ישיר ל-projects/issues/comments/plugin_state (gap-audit GAP-24, GAP-25).
INV-INT5: מזהי-חברה/סוכן מ-config — לא hardcoded בקוד
כלל: מזהי-החברה (CMP/CMPA) ומזהי-הסוכנים (CEO/curator/analyst) נגזרים מ-config (env/טבלת-מיפוי), לא קבועים בקוד. הוספת חברה/החלפת instance אינה דורשת שינוי-קוד. מופע של G2 (SSoT למיפוי) — מקור-אמת יחיד למיפוי. מקור-סמכות: X3 §1א ("לעולם לא UUID hardcoded"); X2-multi-company.md. (פרויקטלי-תפעולי — משרת G2.) אכיפה: טבלת-מיפוי/env יחידה; code-review. כיום אין אכיפה — UUIDs קשיחים. הפרה ידועה: paperclip_client.py:36-62 + app.py:3976 + plugin worker.ts — IDs קשיחים. סותר את X3 §1א (gap-audit GAP-26).
INV-INT6: גזירת company_id קנונית יחידה
כלל: ל-company_id יש מסלול-גזירה אחד מתוך מספר-התיק/סוג-הערר, במקום יחיד. אסור שתי לוגיקות-גזירה
מקבילות (prefix מול fallback-map) שעלולות לסטות. מופע של G2.
מקור-סמכות: X3 §1ג; X2-multi-company.md. (פרויקטלי-תפעולי.)
אכיפה: פונקציית-גזירה יחידה משותפת ל-app.py ול-client.py (יעד FU-9). כיום אין.
הפרה ידועה: prefix ב-app.py מול _FALLBACK_APPEAL_TYPE_TO_COMPANY ב-paperclip_client.py (gap-audit GAP-27).
INV-INT7: webhook יוצא — at-least-once + idempotency + ללא בליעה שקטה
כלל: ה-webhook היוצא (legal-ai→plugin) מספק at-least-once עם מפתח-idempotency יציב (event id),
כך שמסירה-כפולה בטוחה בצד-המקבל; וכישלון-מסירה נרשם ומדווח (telemetry/health), לא נבלע בשקט.
זהו invariant הנדסי (סמנטיקת-מסירה כללית), הקשור ל-G9
(עקיבוּת) ולכלל "אין בליעה שקטה" (חוקה §6).
מקורות: Stripe — Webhooks / at-least-once delivery & idempotency
(https://docs.stripe.com/webhooks) · Hookdeck — At-Least-Once vs Exactly-Once Webhook Delivery
(https://hookdeck.com/webhooks/guides/webhook-delivery-guarantees) · Martin Kleppmann, DDIA
(O'Reilly 2017, idempotence & exactly-once semantics) | סטטוס: verified
אכיפה: event-id יציב + UNIQUE-dedup בצד-המקבל; ה-emitter רושם כישלון ל-telemetry (יעד). כיום:
inbound יש guard 5 דק' (X3 §1ג); outbound אין idempotency, וה-emitter בולע
שגיאות ב-logger.warning בלבד.
הפרה ידועה: emit_*_webhook ב-paperclip_api.py — fire-and-forget, try/except
שמתעד warning ולעולם לא raise, ללא event-id/dedup (gap-audit GAP-28).
INV-INT8: חוזה-אירועי-webhook מתוקען ומגורס
כלל: ל-webhook חוזה-אירוע מפורש ומגורס — eventType מתוך קבוצה סגורה, סכמת-payload מתועדת לכל
סוג, וגרסה. אין eventType חופשי ואין "ברירת-מחדל שקטה". מופע של
G2/G9.
מקור-סמכות: X3 §1ג (3 סוגי-האירוע: status_change, missing_precedent_created,
export_complete); קוד ה-emitter (paperclip_api.py:87+). (פרויקטלי-תפעולי — משרת G2/G9.)
אכיפה: enum + סכמה משותפים emitter↔handler. כיום: eventType נופל ל-status_change כברירת-מחדל
אם חסר/לא-מוכר (gap-audit GAP-29).
5. מצב קיים מול יעד — פער אכיפה
האינטגרציה נשענת על נוהל + שני לקוחות, לא על מסלול-קוד קנוני אחד:
- לקוח (INV-INT4): יעד — לקוח-API יחיד; הסרת מסלול-ה-DB הישיר.
- מזהים (INV-INT5/INT6): יעד — טבלת-מיפוי/env יחידה; פונקציית-גזירה אחת.
- webhook (INV-INT7/INT8): יעד — event-id + dedup + enum-אירוע מגורס + רישום-כישלון.
כל אלה מקובצים ל-FU-9 (gap-audit.md).
6. הפניות-אחיות
- X3-integration-deploy.md — זרימות (wakeup, comments, webhook) + INV-INT1/2/3.
- X10-deploy-env-secrets.md — חוזה-env מלא, סודות, hardcoded IDs/creds.
- X2-multi-company.md — CMP/CMPA, sync, company filtering.
- X6-ui-api-contract.md — חוזה ה-API שהפלאגין (inbound) צורך.
- 00-constitution.md — G2, G9, כלל "סימטריה" (§6).
- web/paperclip_api.py, web/paperclip_client.py, scripts/pc.sh.