feat(halacha): drain לילי (23:00–05:00) + per-upload חילוץ תיק-בודד דרך ה-CEO (#120)
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 6s
All checks were successful
G12 Leak-Guard / leak-guard (pull_request) Successful in 6s
מפריד בין ריקון-באקלוג המוני לבין חילוץ per-upload, ומסיר את ה"פקק" שגרם timeout/process_lost ב-heartbeat של ה-CEO. הבעיה (אבחנה 2026-06-11): לחיצת "חלץ הלכות" על תיק בודד יצרה issue (CMP-165) שהורה ל-CEO להריץ precedent_process_pending(halacha) — בולען סינכרוני שמרוקן את כל התור ההיסטורי (147 ממתינים, שעות) בתוך heartbeat שחסום לשעה. תוצאה: timeout כל שעה → process_lost בפירוק קבוצת-התהליכים → retry → סטורם, והתיק הבודד (FIFO אחרון) לא טופל. לא OOM, לא קוד שבור — אי-התאמה ארכיטקטונית. התיקון: 1. per-upload (web/paperclip_client.py, wake_for_precedent_extraction): גוף ה-issue + תיאור-הפרויקט מורים כעת להריץ precedent_extract_metadata + precedent_extract_halachot ל-case_law_id של ה-issue **בלבד** — עם אזהרה מפורשת לא להריץ process_pending. reextract_halachot כבר מנקה requested_at ומסמן completed → התיק לא יחזור לתור הלילי. 2. הוראות ה-CEO (.claude/agents/legal-ceo.md): אותו שינוי — חילוץ תיק-בודד, לא ריקון-תור. (צריך sync_agents_across_companies.py --apply אחרי מיזוג.) 3. ריקון-באקלוג (scripts/drain_halacha_queue.py): שער חלון-לילה 23:00–05:00 שעון ישראל (zoneinfo, DST-safe — המכונה UTC). מחוץ לחלון ===SKIP===; נעצר ===STOP=== כשהחלון נסגר, השאר ממשיך בלילה הבא (FIFO + per-chunk checkpoint). env: HALACHA_DRAIN_WINDOW_START/_END/_TZ. 4. cron (scripts/legal-halacha-drain.config.cjs): UTC band 20:00–03:00 שמכסה את חלון-ישראל בשני מצבי-DST; הסקריפט גוזם לחלון המדויק. ירייה שעתית מחדשת one-shot שמת (advisory-lock → חפיפה בטוחה). רשת-ביטחון: request_halacha_extraction עדיין מסמן requested_at, כך שאם wakeup ל-CEO נכשל — הדריינר הלילי יתפוס את התיק (בלילה, חסום), אך שום נתיב יומי לא מרוקן את כל התור. Invariants: מקיים G12/INV-PORT1 (paperclip_client = shell; leak_guard עובר). נוגע X16 (durability — מתקציב-זמן heartbeat ל-job ייעודי). בדיקות: py_compile ✓ · window-logic + zoneinfo ✓ (17:00 IDT→False) · leak_guard ✓. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -856,9 +856,10 @@ async def _get_or_create_library_project(
|
||||
"""INSERT INTO projects (id, company_id, name, description, status, color)
|
||||
VALUES ($1, $2::uuid, $3, $4, 'backlog', $5)""",
|
||||
project_id, company_id, _LIBRARY_PROJECT_NAME,
|
||||
"תור אוטומטי לחילוץ הלכות ומטא-דאטה מפסיקה שהועלתה לספריה. "
|
||||
"כל issue כאן מייצג פסק דין שצריך לעבד — להריץ "
|
||||
"mcp__legal-ai__precedent_process_pending.",
|
||||
"תור אוטומטי לחילוץ הלכות ומטא-דאטה מפסיקה שהועלתה לספריה. כל issue "
|
||||
"כאן מייצג פסק דין יחיד שצריך לעבד — להריץ "
|
||||
"precedent_extract_metadata + precedent_extract_halachot עבור ה-case_law_id "
|
||||
"של ה-issue בלבד (לא precedent_process_pending, שמרוקן את כל התור).",
|
||||
"#a17a3a", # gold-ish
|
||||
)
|
||||
await _ensure_default_workspace(conn, project_id, company_id)
|
||||
@@ -876,12 +877,17 @@ async def wake_for_precedent_extraction(
|
||||
|
||||
Creates a Paperclip issue under the per-company "ספריית פסיקה" project,
|
||||
assigns it to the company CEO, links the case_law_id via plugin_state,
|
||||
and wakes the CEO via the Board API. The CEO instructions tell it to
|
||||
run `mcp__legal-ai__precedent_process_pending` and close the issue.
|
||||
and wakes the CEO via the Board API. The issue tells the CEO to extract
|
||||
THIS case only — ``precedent_extract_metadata`` + ``precedent_extract_halachot``
|
||||
for the linked ``case_law_id`` — NOT ``precedent_process_pending``, which
|
||||
drains the whole historical backlog (hours) and blows the heartbeat's
|
||||
time budget (→ timeout/process_lost). The backlog is drained separately by
|
||||
the nightly ``legal-halacha-drain`` service (23:00–05:00).
|
||||
|
||||
Best-effort: any failure is logged and swallowed so a partial Paperclip
|
||||
outage doesn't block the upload itself. The user can always invoke
|
||||
`precedent_process_pending` manually.
|
||||
outage doesn't block the upload itself. ``request_halacha_extraction`` still
|
||||
stamps ``halacha_extraction_requested_at`` as a safety net, so the nightly
|
||||
drain picks the case up even if this wakeup fails.
|
||||
"""
|
||||
if not PAPERCLIP_BOARD_API_KEY:
|
||||
logger.warning(
|
||||
@@ -914,10 +920,13 @@ async def wake_for_precedent_extraction(
|
||||
f"**case_law_id:** `{case_law_id}`\n"
|
||||
f"**citation:** {citation}\n\n"
|
||||
f"---\n\n"
|
||||
f"**משימה:** הרץ את הכלי `mcp__legal-ai__precedent_process_pending` "
|
||||
f"פעמיים — פעם עם `kind='metadata'` ופעם עם `kind='halacha'`. "
|
||||
f"הכלי יעבד את כל הפסיקות בתור (כולל זו), כך שגם אם הופעל מאוחר "
|
||||
f"יותר עבור פסיקות אחרות — אין בעיה.\n\n"
|
||||
f"**משימה — חלץ את הפסיקה הזו בלבד** (לא את התור):\n"
|
||||
f"1. `mcp__legal-ai__precedent_extract_metadata(case_law_id=\"{case_law_id}\")`\n"
|
||||
f"2. `mcp__legal-ai__precedent_extract_halachot(case_law_id=\"{case_law_id}\")`\n\n"
|
||||
f"⚠️ **אל תריץ** `precedent_process_pending` — הוא מרוקן את **כל** התור "
|
||||
f"ההיסטורי (מאות פסיקות, שעות) וחורג מתקציב-הזמן של ה-heartbeat → "
|
||||
f"timeout/process_lost. ריקון-הבאקלוג רץ בנפרד כשירות-לילה ייעודי "
|
||||
f"(`legal-halacha-drain`, 23:00–05:00). כאן — רק התיק הזה.\n\n"
|
||||
f"לאחר ריצה: סמן את ה-issue כ-done ופתח comment קצר עם מספר ההלכות "
|
||||
f"שחולצו ושדות המטא-דאטה שהושלמו."
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user