All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 3m8s
מתקן את הבאג של תיוג שגוי לועדות ערר ומונע חזרתו: **Code changes:** * New MCP tool `internal_decision_upload` (chair_name+district required) — sole supported path for ingesting committee decisions; tags source_kind='internal_committee' automatically. * Citation guard in `precedent_library_upload` rejects citations starting with "ערר" or "בל\"מ" with a directive to use internal_decision_upload. * `practice_area.py` taxonomy unification: PRACTICE_AREAS now accepts both multi-tenant (appeals_committee/national_insurance/labor_law) and domain (rishuy_uvniya/betterment_levy/compensation_197) values. New helper `to_db_practice_area(multi_tenant, subtype) -> domain`. **Agent docs:** * legal-researcher (+5K): upload-tool decision flowchart, code samples per source_kind, district enum (ירושלים/מרכז/תל אביב/צפון/דרום/חיפה/ארצי) * legal-ceo, legal-analyst, legal-writer, legal-qa, HEARTBEAT — taxonomy awareness + source_kind-aware citation patterns + research_complete as valid status. * Fixed two pre-existing wrong practice_area values in examples (histael_hashbacha→betterment_levy, pitsuim_197→compensation_197). Closes TaskMaster #30(parts), #38(parts), #39 (root cause). DB-side backfill + CHECK constraints applied directly via psql: * 11 cases.practice_area corrected (1xxx→rishuy, 8xxx→betterment) * 6 case_law records reclassified external_upload→internal_committee with inferred district * 6 chair_name backfilled from full_text (5 שרית אריאלי + 1 דפנה תמיר) * 88 new halachot extracted for newly-uploaded precedents (אנטרים + ירושלים שקופה 1112/22 + אגא וכט) * CHECK constraints: cases.practice_area enum, case_law internal⇒district Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
226 lines
11 KiB
Markdown
226 lines
11 KiB
Markdown
# HEARTBEAT.md — רשימת ביצוע לכל ריצה (Project-Specific)
|
||
|
||
> **🎯 קובץ זה — Project-specific only.** ה-skill הרשמי `paperclipai/paperclip/paperclip` (טעון אוטומטית בכל heartbeat דרך `paperclipSkillSync`) מכיל את כל ה-API patterns הגנריים: identity (`/api/agents/me`), `PAPERCLIP_WAKE_PAYLOAD_JSON`, `APPROVAL_ID`, inbox, comments, checkout, status updates, וכו'. **קובץ זה מתעד רק התאמות שלנו** — סינון חברה, helpers, workarounds, ו-quirks.
|
||
>
|
||
> **בקונפליקט:** קובץ זה גובר על ה-skill (project-specific מנצח default).
|
||
|
||
---
|
||
|
||
## שפה — כלל עליון
|
||
|
||
**כל הפלט שלך חייב להיות בעברית בלבד.** כולל: comments, סטטוס, שגיאות, סיכומים, ו-thinking פנימי. אין יוצאים מן הכלל. גם שמות tools, פקודות, ונתיבי קבצים — ההסבר סביבם בעברית. ה-skill הרשמי באנגלית — תרגם אם נדרש.
|
||
|
||
---
|
||
|
||
## §0. כל קריאה ל-Paperclip API — דרך `pc.sh` בלבד
|
||
|
||
**ה-skill הרשמי משתמש ב-`curl` ישיר. אצלנו אסור.** משתמשים ב-helper שלנו:
|
||
|
||
```bash
|
||
~/legal-ai/scripts/pc.sh <METHOD> <PATH> [BODY_JSON] [extra curl args...]
|
||
```
|
||
|
||
מוסיף אוטומטית: `Authorization`, `X-Paperclip-Run-Id` (audit), `Content-Type`, base URL.
|
||
|
||
**דוגמאות:**
|
||
```bash
|
||
~/legal-ai/scripts/pc.sh GET "/api/agents/me/inbox-lite"
|
||
~/legal-ai/scripts/pc.sh POST "/api/issues/$ISSUE_ID/checkout"
|
||
~/legal-ai/scripts/pc.sh PATCH "/api/issues/$ISSUE_ID" '{"status":"done"}'
|
||
```
|
||
|
||
**ל-body גדול עם backticks** — `Write` ל-temp file, אז `pc.sh ... "" -H "Content-Type: application/json" -d @/tmp/comment.json`. ראה §דיווח למה.
|
||
|
||
---
|
||
|
||
## §1. זיהוי וסינון חברה — כלל ברזל ⚠️
|
||
|
||
| חברה | COMPANY_ID | סוגי תיקים | טווח מספרים | CEO Agent ID |
|
||
|------|------------|-------------|---------------|---------------|
|
||
| ועדת ערר רישוי ובניה (CMP) | `42a7acd0-30c5-4cbd-ac97-7424f65df294` | רישוי ובניה | **1xxx** | `752cebdd-6748-4a04-aacd-c7ab0294ef33` |
|
||
| ועדת ערר היטלי השבחה (CMPA) | `8639e837-4c9d-47fa-a76b-95788d651896` | היטל השבחה + פיצויים ס' 197 | **8xxx, 9xxx** | `cdbfa8bc-3d61-41a4-a2e7-677ec7d34562` |
|
||
|
||
- אם `$PAPERCLIP_COMPANY_ID` = `42a7acd0...` → רק תיקים ש-**1xxx**
|
||
- אם `$PAPERCLIP_COMPANY_ID` = `8639e837...` → רק תיקים ש-**8xxx/9xxx**
|
||
- **אסור** ליצור פרויקט/issue/תוכן לתיק שלא בטווח שלך
|
||
- אם issue שהוקצה לך מכוון לתיק שלא בטווח — סרב בנימוס ב-comment, והעֵר את ה-CEO של החברה הנכונה
|
||
|
||
---
|
||
|
||
## §1.5. טיפול ב-wake (skill הרשמי + תוספות שלנו)
|
||
|
||
ה-skill מסביר `PAPERCLIP_WAKE_PAYLOAD_JSON`, `APPROVAL_ID`, ו-`heartbeat-context` (Step 6). הוסף עליו:
|
||
|
||
**1.5א. אם `$PAPERCLIP_WAKE_PAYLOAD_JSON` מכיל comment חדש מחיים** — התייחס אליו ב-comment הראשון שלך ("ראיתי שביקשת X — מבצע Y") **לפני** עבודה רחבה. זה מבטיח שחיים יודע שקלטת.
|
||
|
||
**1.5ב. תמיד לקרוא `heartbeat-context`** — לא רק מה ש-skill ממליץ ("Prefer"). אצלנו ה-`attachments` המוחזרים חיוניים (חיים מעלה DOCX/PDF דרך comments). ראה §2.
|
||
|
||
```bash
|
||
CONTEXT=$(~/legal-ai/scripts/pc.sh GET "/api/issues/$ISSUE_ID/heartbeat-context?wakeCommentId=$LATEST_COMMENT_ID")
|
||
ATTACHMENTS=$(echo "$CONTEXT" | jq '.attachments')
|
||
```
|
||
|
||
**1.5ג. APPROVAL_ID flow** — אם חיים ענה על interaction (ראה `legal-ceo.md` §B/§C/§D), קרא תשובה דרך:
|
||
```bash
|
||
~/legal-ai/scripts/pc.sh GET "/api/issues/$PAPERCLIP_TASK_ID/interactions/$PAPERCLIP_APPROVAL_ID" | jq '{status, kind, response}'
|
||
```
|
||
**אסור** לפענח טקסט מ-comment חופשי כשיש APPROVAL_ID — זה הקלט הסטרוקטורלי.
|
||
|
||
---
|
||
|
||
## §2. קבצים מצורפים — דרך `heartbeat-context`, **לא psql**
|
||
|
||
ה-attachments זמינים ב-`$CONTEXT.attachments` (מ-§1.5ב):
|
||
|
||
```bash
|
||
echo "$CONTEXT" | jq '.attachments[] | {filename, contentPath, contentType, byteSize}'
|
||
|
||
# נתיב מלא לקובץ:
|
||
CONTENT_PATH=$(echo "$CONTEXT" | jq -r '.attachments[0].contentPath')
|
||
FULL_PATH="/home/chaim/.paperclip/instances/default/data/storage/$CONTENT_PATH"
|
||
```
|
||
|
||
קבצי DOCX/PDF — קרא עם `Read` tool ב-`$FULL_PATH`.
|
||
|
||
⚠️ **`psql` ישיר ל-`issue_attachments` — אסור.** ה-API הוא ה-source of truth (Gap #21).
|
||
|
||
---
|
||
|
||
## §3. self-recovery — `issue.released` bug
|
||
|
||
⚠️ **Paperclip quirk ידוע**: לאחר ש-issue מסומן `done`, מנגנון `issue.released` עלול להחזיר אותו ל-`todo` תוך ~30s, וגורם ל-wakeup חוזר על משימה שכבר בוצעה (תועד ב-`docs/paperclip-quirks.md §1`).
|
||
|
||
**לפני שמתחילים עבודה — בדוק שלא בוצעה כבר:**
|
||
|
||
1. **תוצרים בדיסק**: `Glob` על תיקיות output הצפויות (`{case_dir}/documents/research/*.md` לחוקר, `analysis-and-research.md` למנתח, וכו')
|
||
2. **תוצרים ב-DB**: דרך MCP — `precedent_list`, `get_claims`, `extract_appraiser_facts` (status=completed)
|
||
3. **comments קודמים** — חפש "הושלם בהצלחה" מסוף-מצב
|
||
|
||
**אם הכל קיים ותקין:** פרסם comment קצר ("אין שינוי — תוצרים קיימים מהריצה הקודמת"), `PATCH status=done`, צא נקי. **לא לעבוד פעמיים.**
|
||
|
||
**אם משהו חסר/שונה:** עבוד רק על מה שחסר.
|
||
|
||
---
|
||
|
||
## §4. דיווח — חובה!
|
||
|
||
**כל heartbeat שמסיים משימה:** comment + status + wake CEO. הסעיף הזה מתעד רק workarounds שלנו לא ב-skill.
|
||
|
||
### §4א. dual-comment workaround ל-`backtick trap`
|
||
|
||
**ל-body קצר (<500 תווים, בלי backticks/קוד/נתיבים)** — pattern רגיל:
|
||
```bash
|
||
~/legal-ai/scripts/pc.sh POST "/api/issues/{issue-id}/comments" '{"body": "סיכום..."}'
|
||
```
|
||
|
||
**ל-body ארוך עם markdown/backticks/נתיבים — חובה שתי פעולות נפרדות:**
|
||
|
||
1. כתוב את ה-JSON לקובץ זמני דרך **Write tool** (לא bash heredoc):
|
||
```
|
||
Write(file_path="/tmp/comment-{issue-id}.json",
|
||
content=json.dumps({"body": markdown_body}, ensure_ascii=False))
|
||
```
|
||
|
||
2. אז `pc.sh` עם `-d @file` שקורא את הקובץ ישירות:
|
||
```bash
|
||
~/legal-ai/scripts/pc.sh POST "/api/issues/{issue-id}/comments" "" \
|
||
-H "Content-Type: application/json" -d @/tmp/comment-{issue-id}.json
|
||
```
|
||
|
||
⚠️ **למה לא bash heredoc / `python3 -c`:** backticks ב-markdown (`` `path/to/file` ``) ייפרשו על-ידי bash כ-command substitution גם בתוך מחרוזת Python. תקבל `Permission denied` מטעה. תועד ב-`docs/paperclip-quirks.md §2`.
|
||
|
||
### §4ב. סטטוס: `done` או `blocked` — לא ביניים
|
||
|
||
```bash
|
||
~/legal-ai/scripts/pc.sh PATCH "/api/issues/{issue-id}" '{"status": "done"}' # הצליח
|
||
~/legal-ai/scripts/pc.sh PATCH "/api/issues/{issue-id}" '{"status": "blocked"}' # נכשל / חסום
|
||
```
|
||
|
||
**אסור** `done` עם כשל שלא טופל. אם משהו נכשל → `blocked` + comment עם פירוט.
|
||
|
||
### §4ג. wake CEO לפי חברה
|
||
|
||
**⚠️ CEO שונה לכל חברה** (ראה §1). UUID hardcoded **אסור** — תמיד דרך `$PAPERCLIP_COMPANY_ID`:
|
||
|
||
```bash
|
||
if [ "$PAPERCLIP_COMPANY_ID" = "8639e837-4c9d-47fa-a76b-95788d651896" ]; then
|
||
CEO_ID="cdbfa8bc-3d61-41a4-a2e7-677ec7d34562" # CMPA
|
||
else
|
||
CEO_ID="752cebdd-6748-4a04-aacd-c7ab0294ef33" # CMP
|
||
fi
|
||
|
||
~/legal-ai/scripts/pc.sh POST "/api/agents/$CEO_ID/wakeup" \
|
||
'{"source":"automation","triggerDetail":"system","reason":"סוכן [שם] סיים [issue-id] בסטטוס [done/blocked]","payload":{"issueId":"[issue-id]","mutation":"agent_completion"}}'
|
||
```
|
||
|
||
⚠️ **חובה `payload.issueId`** — בלי זה הסוכן מתעורר בלי הקשר (בלי תיק, בלי cwd).
|
||
⚠️ **wakeup לחברה אחרת נדחה** — `Agent key cannot access another company`.
|
||
⚠️ **אסור** `INSERT INTO agent_wakeup_requests` ישיר — לא יוצר heartbeat_run, הסוכן לא מתעורר.
|
||
|
||
---
|
||
|
||
## §5. התראת מייל — כשנדרשת תשובה אנושית
|
||
|
||
```bash
|
||
python3 /home/chaim/legal-ai/scripts/notify.py \
|
||
"נדרשת תשובתך — [תיאור קצר]" \
|
||
"תוכן ההודעה עם סיכום מה נדרש"
|
||
```
|
||
|
||
**מתי לשלוח (תמיד):** סיום כל משימה (סיכום קצר), בקשת תוצאה/כיוון, QA fail, החלטה מוכנה לדפנה, מצב שדורש פעולה אנושית, שגיאה לא פתירה.
|
||
|
||
**מתי לא:** עדכוני סטטוס ביניים, שגיאות טכניות שאפשר לפתור לבד.
|
||
|
||
---
|
||
|
||
## §6. Release
|
||
|
||
```bash
|
||
~/legal-ai/scripts/pc.sh POST "/api/issues/{issue-id}/release"
|
||
```
|
||
|
||
---
|
||
|
||
## §7. סטטוסי תיק תקפים (case status flow)
|
||
|
||
הסטטוסים שאתה עשוי לראות ב-`case.status` (לפי `legal-ceo.md` "מפת סטטוסים"):
|
||
|
||
```
|
||
new → proofread → documents_ready → analyst_verified → research_complete*
|
||
→ outcome_set → direction_approved → analysis_enriched → ready_for_writing
|
||
→ drafted → qa_passed / qa_failed → exported
|
||
```
|
||
|
||
`research_complete` — **valid status** (לא legacy מחוסר תוקף). מנותב ע"י `legal-researcher.md` שלב 5 כשמחקר תקדימים רץ בנפרד מהמנתח (תרחיש מתקדם). ה-CEO יודע לטפל בו כאילו זה `analyst_verified` (ראה `legal-ceo.md` "מפת סטטוסים").
|
||
|
||
---
|
||
|
||
## §8. ניתוב upload פסיקה לקורפוס — flowchart מהיר
|
||
|
||
```
|
||
חיים העלה PDF פסיקה לתיק → ה-citation הוא:
|
||
├── "ערר NNNN/YY" או "בל"מ NNNN/YY"
|
||
│ → internal_decision_upload (חובה chair_name + district)
|
||
└── "עע"מ / בר"מ / עמ"נ / בג"ץ / ע"א / ע"פ / רע"א / רע"פ / ת"א / ת"מ"
|
||
→ precedent_library_upload (external_upload)
|
||
```
|
||
|
||
- **`internal_decision_upload`** דורש: `file_path`, `case_number`, `chair_name`, `district`. district מתוך הרשימה: ירושלים / מרכז / תל אביב / צפון / דרום / חיפה / ארצי.
|
||
- **`precedent_library_upload`** לא מקבל chair_name/district. אם תנסה להעלות "ערר ..." דרכו — citation guard ידחה.
|
||
- פירוט מלא: `legal-researcher.md` סעיף "איזה כלי upload להשתמש".
|
||
|
||
---
|
||
|
||
## נתיבי API — הפניה ל-skill הרשמי
|
||
|
||
| פעולה | איפה ב-skill |
|
||
|--------|---------------|
|
||
| Identity, inbox, pick work | Step 1, 3, 4 |
|
||
| Wake payload + APPROVAL handling | Authentication + Step 2 |
|
||
| Heartbeat-context, comments, attachments | Step 6 |
|
||
| Checkout (with the `checkedOutByHarness` skip) | Step 5 |
|
||
| Comment, status update, exit | Step 7-8 |
|
||
| Routines, workflows, references | `references/` ב-skill |
|
||
|
||
**שינויים project-specific מה-skill:** תועדו בקובץ זה (§0 pc.sh, §1 חברה, §2 attachments, §3 quirk, §4 dual-comment + CEO wakeup, §5 notify).
|