# X16 — עמידות-פייפליין (Durable Pipeline Execution) > כפוף ל-[00-constitution.md](00-constitution.md). מחזק את **INV-G3** (idempotency) > ב-checkpointing+replay לפייפליינים הדטרמיניסטיים המקומיים. נושק ל-[07-learning.md](07-learning.md) > ו-[X11-citation-corroboration.md](X11-citation-corroboration.md). ## 0. הבעיה שני הפייפליינים המקומיים החד-פעמיים — [final_halacha_pipeline.py](../../scripts/final_halacha_pipeline.py) (כפתור run-halacha, אימות-הלכות, X11) ו-[final_learning_pipeline.py](../../scripts/final_learning_pipeline.py) (כפתור run-learning, למידת-סגנון, 07-learning) — חולקים **צורה זהה**: סקריפט מקומי, 3–4 שלבים בטור, idempotent, פאנל-LLM ארוך בסוף (CSV-gated, "can take minutes"). היום הם **ליניאריים וחסרי-זיכרון**: קריסה באמצע (ניתוק ל-DeepSeek/Gemini, restart של קונטיינר, OOM) → הרצה-מחדש מ-שלב 0. השלבים idempotent ולכן זה **בטוח**, אבל **משלמים שוב**: מחלצים, בונים corroboration על כל הקורפוס, ושופטים מחדש הלכות שכבר נשפטו — דקות וקריאות-LLM לפח. **הקשר-סיכון אמיתי:** דליפת task-master (יתומים ppid=1, ~3GB) מסכנת OOM ל-Postgres ([project_taskmaster_mcp_memory_leak]). אם OOM הורג ריצת-פאנל ארוכה — היום מתחילים מאפס. **הבחנה מ-idempotency:** idempotency = "בטוח להריץ שוב". durable execution = "בטוח להריץ שוב **בלי לשלם שוב**". זה שכלול, לא תחליף. ## 1. ההכרעה להטמיע **LangGraph כספרייה בתוך הסקריפט** (לא כפלטפורמה מחליפה ל-Paperclip): מנוע-העמידות היחיד שהוא state-of-the-art ב-checkpointing+replay+time-travel, בשימוש כ-`import` בתוך הסקריפט המקומי. Paperclip לא מושפע — הכפתור עדיין מעיר את Hermes שמריץ את אותו ה-CLI. > **גבול-תחום מפורש (מתחבר ל-G12/X15):** LangGraph נכנס **רק** כמנוע-פנימי של הסקריפטים > המקומיים. אסור להשתמש בו כתחליף-פלטפורמה או כ-orchestrator של הסוכנים — זה ייצור מסלול > מקביל ל-Paperclip (הפרת G2) ויערבב עמידות עם פלטפורמה. HITL/ניתוב-יו"ר נשאר מאחורי > ה-Port (ראו §4 Phase 3). **מקורות:** Temporal — *Durable Execution* · Saga / workflow-checkpointing pattern · Martin Kleppmann, *DDIA* (idempotence & exactly-once) · LangGraph checkpointer/replay docs. ## 2. ה-invariant ### INV-DUR1 — עמידות לפייפליינים דטרמיניסטיים **כלל:** פייפליין דטרמיניסטי רב-שלבי משמר את התקדמותו ב-checkpoint מתמיד אחרי כל שלב שהושלם; הרצה-חוזרת של אותה יחידת-עבודה **מדלגת** על שלבים שכבר הושלמו ומתחילה מנקודת-הכשל המדויקת. מימוש-העמידות הוא **משותף** לכל הפייפליינים (`scripts/_pipeline_runtime.py`) — לא מימוש-לכל-סקריפט (G2). חוזה-הכניסה (ה-CLI) נשמר ללא-שינוי. **מקורות:** Temporal (Durable Execution) · Kleppmann *DDIA* (exactly-once) · Saga pattern (workflow checkpointing) | סטטוס: verified **אכיפה:** `_pipeline_runtime.py` עם LangGraph + checkpointer; thread_id דטרמיניסטי לכל יחידת-עבודה (תיק); בדיקת kill-and-resume שמאמתת ששלבים שהושלמו אינם רצים-מחדש. **הפרה ידועה:** היום `final_halacha_pipeline.py` / `final_learning_pipeline.py` ליניאריים — קריסה = הרצה-מחדש מלאה (חוזרים על extract/corroboration/panel). ## 3. ארכיטקטורה ``` scripts/_pipeline_runtime.py ← מודול-עמידות משותף יחיד (G2) • build_graph(steps) StateGraph: node לכל שלב • SqliteSaver data/checkpoints/.sqlite (לא Postgres המשותף) • run(thread_id, resume) מדלג-אוטומטית על nodes ב-checkpoint ``` **הכרעות-תכנון:** 1. **Checkpointer = SQLite (`langgraph-checkpoint-sqlite`), לא Postgres.** קובץ תחת `data/checkpoints/`: מקומי (תואם "local-only"), פשוט, ו**נמנע מהאזהרה** ב-CLAUDE.md נגד migrations מ-2 worktrees על Postgres המשותף (`localhost:5433`). PostgresSaver = אופציה עתידית אם נדרש ריכוז/observability. 2. **`thread_id = f":{case_number}"`.** הרצה-חוזרת של אותו תיק מזהה checkpoint לא-גמור וממשיכה אוטומטית; תיק שהושלם = no-op. idempotency + דילוג-checkpoint מתחברים. 3. **גרעיניות (מדורגת):** - **גס (P0/P1):** כל שלב = node. קריסה בין-שלבים → המשך מהשלב שנפל. הפאנל node יחיד שרץ-מחדש — אך הוא כבר CSV-backed + idempotent (מדלג פנימית על מה שנשפט). - **עדין (P2, אופציונלי):** פירוק הפאנל ל-map מעל ההלכות/הלקחים (LangGraph `Send`), כל פריט = יחידת-checkpoint → resume תוך-פאנל בלי לשפוט מחדש ברמת-LLM. נשען על ה-CSV הקיים כמקור "כבר-נשפט". 4. **סמנטיקת-כשל מפורשת.** היום הכל "non-fatal, continue". עם LangGraph: nodes "מייעצים" (extract, corroboration) — catch+record-status וממשיכים; node "קריטי" (panel) — raise בכשל-קשה → עצירה ב-checkpoint → resume. 5. **שימור-חוזה-הכניסה.** ה-CLI (`--case`/`--limit`/`--dry-run`) זהה; run-halacha/run-learning → Hermes → אותו `python ...pipeline.py --case X` לא משתנה. מוסיפים `--fresh` (ברירת-מחדל: auto-resume אם יש checkpoint לא-גמור לתיק). ## 4. גלגול מדורג | Phase | תחום | מאמץ | |-------|------|------| | **P0** | deps ל-`mcp-server/pyproject` (`langgraph` + `langgraph-checkpoint-sqlite`, venv מקומי בלבד → אפס השפעת-קונטיינר). `_pipeline_runtime.py` עם SqliteSaver. עטיפת 4 שלבי-halacha כ-nodes (גס). CLI זהה. test: kill אחרי [1] → resume → assert [0],[1] לא רצו שוב | ~1 יום | | **P1** | אותו runtime על `final_learning_pipeline` (3 שלבים) — מימוש-עמידות אחד לשניהם (G2) | חצי יום | | **P2** | (אופציונלי) פירוק-פאנל ל-map per-item — resume תוך-פאנל | 1–2 ימים | | **P3** | (עתידי) LangGraph `interrupt()` ל-HITL של היו"ר (split→chair, INV-G10) — **רק מאחורי ה-Port** (X15/G12) | — | ## 5. ראו גם - [07-learning.md](07-learning.md) · [X11-citation-corroboration.md](X11-citation-corroboration.md) - [X15-agent-platform-port.md](X15-agent-platform-port.md) — הגבול מול הפלטפורמה (G12). - [scripts/SCRIPTS.md](../../scripts/SCRIPTS.md) — הסקריפטים המושפעים.