diff --git a/.taskmaster/tasks/tasks.json b/.taskmaster/tasks/tasks.json index cf166bc..47c8bfe 100644 --- a/.taskmaster/tasks/tasks.json +++ b/.taskmaster/tasks/tasks.json @@ -2298,9 +2298,9 @@ }, { "id": "66", - "title": "[FU-8] מחסומי-תהליך → מחסומי-קוד", - "description": "אכיפת sync חוצה-חברות; מחסומי-קוד ל-wakeup/API; חיווט הספ לסוכנים.", - "details": "מכסה GAP-21,22,23. מספק INV-MC1/INT1/INT3/AG1. severity: High. סוג: קוד + החלטת-יו\"ר. GAP-23 prereq לתת-פרויקט 5.", + "title": "[FU-8a] מחסומי-תהליך→קוד: enforce sync + Paperclip-access guard (pure-code)", + "description": "אכיפת cross-company sync (--verify יוצא non-zero על drift; adapter_type mismatch = drift לא silent skip) + fitness-function שחוסם גישת-Paperclip לא-מאושרת (raw http / INSERT agent_wakeup_requests).", + "details": "מכסה GAP-21,22. מספק INV-MC1/INT1/INT3. severity: High. סוג: pure-code. GAP-23 (חיווט ספ→סוכנים) הופרד ל-#69 (משנה התנהגות-ייצור).", "testStrategy": "", "status": "pending", "dependencies": [], @@ -2325,16 +2325,6 @@ "status": "pending", "testStrategy": "", "parentId": "66" - }, - { - "id": 3, - "title": "[GAP-23] חיווט הספ לסוכנים", - "description": "HEARTBEAT/agent docs דורשים קריאת 00-constitution + ספ-תחום (prereq לתת-פרויקט 5).", - "dependencies": [], - "details": "INV-AG1", - "status": "pending", - "testStrategy": "", - "parentId": "66" } ], "updatedAt": "2026-05-30T17:37:34.741136+00:00" @@ -2343,9 +2333,9 @@ "id": "67", "title": "[FU-2b] תיאום מזהים קנוניים + ניקוי ציטוט-כמזהה (data-migration, chair)", "description": "מיגרציה חד-פעמית של ~52+ רשומות case_law עם ציטוט-מלא ב-case_number → מספר-בסיס מנורמל; dedup (למשל 8047-23 כפול); הכרעת צורה קנונית per-record.", - "details": "מכסה GAP-07,08. מספק INV-ID1/ID2/DM2. severity: High. סוג: DATA-MIGRATION + chair-decision (מספר רשמי per-record, with-month canonical). דורש: גיבוי, dry-run, סקירת-יו\"ר, reversibility. תלוי ב-FU-2a (#60, לצורך פונקציית הנרמול). מקור: בדיקת DB 2026-05-30 — internal_committee ~52/56 ציטוט-מלא, ≥1 dup (8047-23), 1 בלתי-פתיר (ערר אדלר/cited_only).", + "details": "מכסה GAP-07,08. מספק INV-ID1/ID2/DM2. severity: High. סוג: DATA-MIGRATION + chair-decision (מספר רשמי per-record, with-month canonical). דורש: גיבוי, dry-run, סקירת-יו\"ר, reversibility. תלוי ב-FU-2a (#60, לצורך פונקציית הנרמול). מקור: בדיקת DB 2026-05-30 — internal_committee ~52/56 ציטוט-מלא, ≥1 dup (8047-23), 1 בלתי-פתיר (ערר אדלר/cited_only). | APPLIED 2026-05-31: 55 internal rows normalized to bare case_number; corrupted 8047 dup (מטודלה) deleted; חלוואני 1028-20 proc→בל\"מ. Backups in data/audit/fu2b-*. external→#68.", "testStrategy": "", - "status": "pending", + "status": "done", "dependencies": [ "60" ], @@ -2357,7 +2347,7 @@ "description": "מיגרציה חד-פעמית; הצורה עם-חודש קנונית (החלטת-יו\"ר).", "dependencies": [], "details": "INV-ID1", - "status": "pending", + "status": "done", "testStrategy": "", "parentId": "67" }, @@ -2367,7 +2357,7 @@ "description": "רשומות עם ציטוט מלא כמזהה (legacy).", "dependencies": [], "details": "INV-DM2/ID2", - "status": "pending", + "status": "done", "testStrategy": "", "parentId": "67" } @@ -2385,6 +2375,30 @@ ], "priority": "medium", "subtasks": [] + }, + { + "id": "69", + "title": "[FU-8b] חיווט הספ לסוכני-Paperclip (GAP-23)", + "description": "HEARTBEAT/agent docs דורשים קריאת 00-constitution + ספ-תחום רלוונטי לפני פעולה. משנה התנהגות-סוכן בייצור; prereq לתת-פרויקט 5.", + "details": "מכסה GAP-23. מספק INV-AG1. severity: High. סוג: docs+chair-decision. דורש ספ יציב (קיים) + החלטה על שילוב בזרימת-הסוכנים. הופרד מ-FU-8a לפי החלטת chaim 2026-05-31 (GAP-21/22 = pure-code עכשיו).", + "testStrategy": "", + "status": "pending", + "dependencies": [ + "66" + ], + "priority": "medium", + "subtasks": [ + { + "id": 1, + "title": "[GAP-23] חיווט הספ לסוכנים", + "description": "HEARTBEAT/agent docs דורשים קריאת 00-constitution + ספ-תחום (prereq לתת-פרויקט 5).", + "dependencies": [], + "details": "INV-AG1", + "status": "pending", + "testStrategy": "", + "parentId": "69" + } + ] } ], "metadata": { diff --git a/docs/superpowers/specs/2026-05-31-fu8a-process-to-code-guards-design.md b/docs/superpowers/specs/2026-05-31-fu8a-process-to-code-guards-design.md new file mode 100644 index 0000000..045369b --- /dev/null +++ b/docs/superpowers/specs/2026-05-31-fu8a-process-to-code-guards-design.md @@ -0,0 +1,78 @@ +# FU-8a — מחסומי-תהליך → מחסומי-קוד (Process Barriers → Code Guards) — עיצוב + +**סטטוס:** מאושר-לעיצוב · **תאריך:** 2026-05-31 · **ענף:** TBD +**מכסה:** GAP-21, GAP-22 · **מספק:** INV-MC1, INV-INT1, INV-INT3 · **משימה:** TaskMaster #66 +**תלוי ב:** — · **סוג:** pure-code · **מחוץ-להיקף:** GAP-23 (חיווט ספ→סוכנים) → #69 / FU-8b. + +--- + +## 1. הבעיה + +שני מחסומים שהיום נשענים על **נוהל אנושי** ולא על **קוד**, ולכן ניתנים להפרה שקטה: + +- **GAP-21 (INV-MC1):** סנכרון-סוכנים חוצה-חברות (`sync_agents_across_companies.py`) ידני ולא-נאכף. + ב-`--verify` (script:397) הוא **יוצא 0 גם כשיש drift**, ו-adapter_type-mismatch (script:388) + מודפס כ-"SKIPPING" ו**נבלע** — אין סיגנל-כשל שניתן לתלות בו gate. +- **GAP-22 (INV-INT1/INT3):** אין מחסום-קוד נגד עקיפת ה-helpers המאושרים של Paperclip — קריאת + `httpx`/`requests` גולמית ל-API של Paperclip (במקום `web/paperclip_api.pc_request`) או `INSERT` + ישיר ל-`agent_wakeup_requests` (במקום ה-wakeup API). היום זה כלל-נוהל ב-CLAUDE.md/HEARTBEAT בלבד. + +## 2. ההכרעה (מאומתת ≥3 מקורות) + +**Architectural fitness functions** — הופכים החלטת-ארכיטקטורה מ"הסכמה חברתית" ל**כלל נאכף שנתפס +ברגע ההפרה**, כ-assertion דמוי-טסט ב-CI. שני המחסומים מיושמים ככאלה: + +| החלטה | נימוק | מקורות | +|-------|--------|--------| +| GAP-21: `--verify` יוצא **non-zero על drift**; adapter_type-mismatch = **drift** (לא silent skip) + דיווח רם | drift-verify הוא gate רק אם הוא יוצא non-zero (Terraform 0/2); "alert, don't skip silently" | InfoQ fitness-functions; Firefly CI-drift; Spacelift drift | +| GAP-22: **fitness-function (pytest שסורק את ה-repo)**, לא import-linter | הכלל הוא דפוס-*שימוש*/מחרוזת (http ל-URL, מחרוזת-SQL), לא גבול-import; fitness-function כ-test-assertion ב-CI הוא הכלי | InfoQ; Lukas Niessen; aipatternbook | +| לרוץ ב-**חבילת-הטסטים הקיימת** (לא CI חדש) | אין CI-lint בפרויקט (רק deploy.yaml); חבילת ה-pytest היא שער-האיכות הקיים | (נגזר מהמצב) | + +## 3. הרכיבים + +- **Modify** `scripts/sync_agents_across_companies.py` (GAP-21): + - `--verify` יחזיר **exit 1** כש-`plan` לא-ריק **או** כשיש adapter_type-mismatch (כיום `return` שקט). + - adapter_type-mismatch: נספר ל-`mismatches` ומדווח רם (`❌`), לא רק "SKIPPING"; נכלל בסיגנל-הכשל + של `--verify`. (ה-skip עצמו ב-`--apply` נשמר — לא מסנכרנים adapter_type אוטומטית — אבל `--verify` + **נכשל** כדי לאלץ טיפול ידני.) +- **Create** `mcp-server/tests/test_paperclip_access_guard.py` (GAP-22) — fitness-function שסורק את + עץ-המקור (`web/`, `mcp-server/src/`, `scripts/`, `plugin-legal-ai/` אם רלוונטי) ו**נכשל** אם נמצא: + 1. קריאת-HTTP גולמית ל-Paperclip — `httpx`/`requests`/`aiohttp` עם `PAPERCLIP_API_URL` או + `localhost:3100`/`pc.nautilus` — **מחוץ** ל-`web/paperclip_api.py` (ה-helper המאושר). + 2. `INSERT INTO agent_wakeup_requests` (כל קובץ) — חייב לעבור דרך wakeup API. + 3. `curl ... $PAPERCLIP_API_URL` ב-shell — מחוץ ל-`scripts/pc.sh`. + - מימוש: סריקת-טקסט ממוקדת (regex) עם **allowlist** מפורש (הקבצים המאושרים) + הודעת-כשל שמסבירה + את ה-helper הנכון. (AST מלא מיותר — הדפוסים הם מחרוזות-URL/SQL, לא מבנה-קוד.) +- **Create** `scripts/check_paperclip_access.py` (GAP-22, אופציונלי-דק) — wrapper הניתן להרצה ידנית/CI + שמריץ את אותה לוגיקת-סריקה (מייבא מהטסט או חולק helper); exit non-zero על הפרה. (אם הטסט מספיק — + לדלג, YAGNI.) + +## 4. שינויי-התנהגות וסיכון + +| שינוי | השפעה | סיכון | +|--------|--------|--------| +| `--verify` יוצא 1 על drift | הופך ל-gate שמיש (אפשר לתלות בו cron/CI) | נמוך — לא משנה `--apply`; משנה רק exit-code של verify | +| adapter_type-mismatch רם + נכלל ב-fail | drift של adapter לא נבלע | נמוך — דיווח; ה-skip ב-apply נשמר | +| fitness-function guard | הפרה עתידית תיכשל בטסטים | נמוך — **ה-repo נסרק 2026-05-31: 0 הפרות קיימות** (אין httpx גולמי ל-Paperclip, אין INSERT ל-agent_wakeup_requests, אין curl גולמי). הגדר הוא גדר-קדימה נקי, אפס תיקוני-קוד קיימים | +| allowlist | קבצים מאושרים (paperclip_api.py, pc.sh) פטורים | נמוך — מפורש ומתועד | + +## 5. אסטרטגיית בדיקה + +- **GAP-22 fitness-function** נבדק על עצמו: הטסט מאתר דפוס-הפרה מוזרק (fixture עם httpx ל-Paperclip) + ומאשר שהוא נתפס; ומאשר שה-helpers המאושרים (paperclip_api.py) **לא** מסומנים. כלומר הטסט בודק + את הסורק על דוגמאות חיוביות+שליליות, ואז מריץ אותו על ה-repo האמיתי (חייב לעבור — אחרת יש הפרה + קיימת לתקן). +- **GAP-21** — בדיקת-יחידה ללוגיקת ה-exit/mismatch: מתוך master/mirror סינתטיים, `--verify` עם drift + מחזיר 1; ללא drift מחזיר 0; adapter_type-mismatch → 1 + הודעה. (refactor של לוגיקת-ההכרעה לפונקציה + טהורה `_verify_exit_code(plan, mismatches)` שניתנת לבדיקה offline בלי DB/Paperclip.) +- חבילה מלאה ירוקה; smoke: `sync...py --verify` מול ה-state הנוכחי (לדווח אם drift קיים). + +## 6. סדר-ביצוע + +1. בדיקות אדומות: `_verify_exit_code` (GAP-21) + סורק ה-guard על fixtures (GAP-22). +2. GAP-21: refactor `--verify` ל-`_verify_exit_code` + ספירת mismatches + exit 1 + דיווח רם. +3. GAP-22: סורק (`tests/test_paperclip_access_guard.py`) + allowlist; **הרצה על ה-repo** וטיפול בהפרות קיימות (תיקון או allowlist מנומק). +4. (אופציונלי) `scripts/check_paperclip_access.py` אם רוצים הרצה עצמאית. +5. חבילה ירוקה + smoke (`--verify`) + SCRIPTS.md (אם נוסף סקריפט) + PR+merge + TaskMaster #66. + +> **GAP-23 (#69)** — חיווט הספ ל-HEARTBEAT/סוכנים — מחוץ-להיקף (משנה התנהגות-ייצור, דורש החלטה).