# Paperclip Quirks — מלכודות ידועות

> **הקשר:** מה ש-Paperclip עושה בעצמו, מתחת לרגליהם של הסוכנים שלנו, ושאנחנו צריכים לעקוף אותו או לחיות איתו.
>
> כל מלכודת מתועדת עם:
> 1. מה קורה בפועל
> 2. ראיה אמפירית מתוך לוגים
> 3. ההשפעה על הצינור שלנו
> 4. עקיפה / תיקון / קבלה

---

## 1. `issue.released` הופך `done` ל-`todo`

### מה קורה

לאחר שסוכן מבצע `PATCH /api/issues/{id}` עם `status: done`, **Paperclip מבצע פעולה נוספת בשם `issue.released`** מספר שניות מאוחר יותר. ל-`issue.released` יש side-effect לא-מתועד שמחזיר את ה-status ל-`todo`.

### ראיה אמפירית — תיק 8174-24, CMPA-18 (30/04/26)

מתוך `activity_log`:

```
ts        | action              | actor_type | details
----------+---------------------+------------+----------------------------------------
18:14:49  | issue.comment_added | agent      | comment by researcher
18:14:57  | issue.updated       | agent      | {"status": "done", "_previous": {"status": "in_progress"}}
18:15:35  | issue.released      | agent      |                       ← here
```

מצב מ-`issues` table 38 שניות לאחר ה-`released`:
```
identifier | status | updated_at
CMPA-18    | todo   | 18:15:35
```

ה-status חזר מ-`done` ל-`todo` למרות שאף סוכן או משתמש לא ביקש זאת.

### ההשפעה על הצינור שלנו

Paperclip מזהה issue ב-`todo` כ"יש עבודה לעשות" → מיד מפעיל wakeup לסוכן הרלוונטי → הסוכן רץ שוב עם prompt cache מלא (~$0.10-0.50 פר-ריצה) → מסתכל סביב ומבין שהעבודה כבר נעשתה → סוגר את ה-issue שוב → `issue.released` חוזר על עצמו ⇒ פוטנציאל ללולאה.

### עקיפה — בצד שלנו (ללא תיקון Paperclip)

הסוכן שלנו **עושה זאת כבר היום בהצלחה** במקרה שהוא רואה issue ב-`todo` עם תוצרים קיימים:

1. בודק שהקבצים הצפויים קיימים (`Glob /documents/research/*.md`)
2. בודק שה-DB מאוכלס (`mcp__legal-ai__precedent_list`, `get_claims`, וכו')
3. אם הכל קיים → לא מבצע עבודה כפולה → כותב comment "אין שינוי" → `PATCH issue → done`

**הראיה:** בריצה החוזרת (PID 309786 ב-30/04/26 18:15:54), המנתח של החוקר זיהה תוך 90 שניות שכל 9 התקדימים והקובץ קיימים, וסגר את ה-issue ב-`PATCH → done` שוב. הריצה הזאת עלתה כ-$0.20 — לא חינם, אבל לא לולאה.

### אם תרצה לחקור פנימה

ה-`issue.released` נרשם ב-`activity_log` עם `actor_type=agent` אבל בלי `agent_id` שמסביר מי. הוא לא נכתב על ידי הסקריפטים שלנו (אנחנו לא קוראים endpoint כזה). מקור אפשרי:
- מנגנון `executionLockedAt` / `executionWorkspaceId` של Paperclip שמשחרר משאבים אחרי שריצה מסתיימת ובמקביל מאפס status

האפשרות הנכונה לסגור את הבאג היא **ב-Paperclip עצמו** — לתקן את `issue.released` שלא ידרוס status מסוף-מצב כמו `done`. עד שזה נסגר אצלם, אנחנו חיים עם self-recovery.

### סטטוס

- **לא נסגר ב-Paperclip** (ידוע לפי 30/04/26)
- **טופל בצד שלנו** דרך self-recovery בסקייל של הסוכן (HEARTBEAT.md §4-recovery)
- **לתעד עלות**: כל ריצת self-recovery מוסיפה ~$0.20 לתיק

---

## 2. Bash backtick trap בעת בניית comment body דרך curl

### מה קורה

הסוכן בונה pipeline מורכב כדי לפרסם comment עם markdown ארוך:

```bash
curl ... -d "$(python3 -c "
body = '''## כותרת
📁 קובץ: \`/path/to/file.md\`
'''
print(json.dumps({'body': body}))")"
```

ה-`bash` שמריץ את ה-`$(...)` הראשון רואה את ה-backticks (` ` ` ) בתוך המחרוזת של Python ומפרש אותם **כ-command substitution של bash**. הוא מנסה להריץ את `/path/to/file.md` כפקודה, ומכיוון שהקובץ לא executable — מחזיר:

```
/bin/bash: line 56: /path/to/file.md: Permission denied
```

### ההטעיה

ההודעה `Permission denied` היא **לא** באמת בעיית הרשאות:
- `ls -la` מראה שהקובץ הוא `chaim:chaim` עם `-rw-r--r--`
- `touch` ידני באותו נתיב מצליח
- ה-Write tool כבר כתב את הקובץ הזה בהצלחה דקה קודם

### למה זה קורה דווקא בנתיבי מסמכים

Backticks הם תחביר markdown נפוץ לציטוט נתיבים: `` `/home/chaim/...` ``. בפלט markdown זה נכון, אבל כשהסוכן מטמיע את ה-markdown בתוך bash heredoc / command substitution, ה-backticks מפעילים את עצמם.

### תיקון — דפוס "כתוב לקובץ זמני אז curl -d @file"

במקום:
```bash
curl ... -d "$(python3 -c "...long body with backticks...")"
```

עשה:
```python
# 1. כתוב את ה-body לקובץ זמני דרך Write tool (בלי שום bash quoting)
Write("/tmp/comment.json", json.dumps({"body": markdown_body}))
```
```bash
# 2. אז curl קורא מהקובץ — אין shell expansion על התוכן
curl -s -X POST -H "Authorization: Bearer $PAPERCLIP_API_KEY" \
  -H "Content-Type: application/json" \
  "$PAPERCLIP_API_URL/api/issues/{issue-id}/comments" \
  -d @/tmp/comment.json
```

הנתיב `-d @file` קורא את התוכן של הקובץ **בלי שום ניתוח** — אין shell, אין quoting, אין backticks-as-commands. זה גם מאפשר body של 10K+ תווים ללא הגבלת ARG_MAX.

### סטטוס

- **תיעוד ב-HEARTBEAT.md** עם הוראה מפורשת להשתמש ב-Write+`-d @file` ל-bodies מעל 500 תווים
- **השפעה היסטורית**: לפני התיקון, הריצה ב-CMPA-18 (30/04/26) הצליחה (curl באמת רץ) — אבל ה-`Permission denied` בלוג היה מבלבל וגרם לחקירה. עתה שהסיבה ידועה, אפשר להתעלם.

---

## 3. CEO main issue auto-block ב-`in_progress`

### מה קורה

CEO שמסיים turn (פרסם comment "ממתין לסיום של סוכן Y") ומשאיר את ה-issue ב-`in_progress` יקבל auto-block תוך דקה אחת מ-Paperclip ("live execution disappeared"). הסטטוס יקפוץ ל-`blocked` ויידרש wakeup ידני להמשיך.

### עקיפה

CEO צריך להעביר את ה-issue ל-`in_review` (לא `in_progress`) כשהוא ממתין למשאב חיצוני (סוכן אחר, יו"ר). זה מתועד ב-CLAUDE.md זיכרון: `feedback_paperclip_enums.md`.

### סטטוס

- **תיקון ב-`legal-ceo.md`** (commit a1969dd)
- נצפה עובד ב-CMPA-15 ב-30/04/26 — ה-CEO עבר ל-`in_review` נכון

---

## 4. Wakeup דרך DB ישיר ≠ wakeup דרך API

### מה קורה

`INSERT INTO agent_wakeup_requests` ידני בלי לעבור דרך `POST /api/agents/{id}/wakeup` יוצר רשומת wakeup אבל **לא יוצר `heartbeat_run`**. בלי `heartbeat_run`, ה-runtime של Paperclip לא מזהה שיש משהו להריץ → הסוכן לעולם לא מתעורר.

### עקיפה

תמיד להשתמש ב-API. כל הסקייל שלנו תועדו עם האזהרה הזאת.

### סטטוס

- **תיקון בכל הסקייל** (CLAUDE.md זיכרון: `reference_paperclip_wakeup.md`)
