T6.2 10.8.2026 BAROUCH SHALITImplementation v1.0 — Enforced Mode
אחידות הפעלה, Idempotency ומניעת חפיפה
מאושר ✅ — Enforced Mode (T62_MODE=enforced). 7/7 פעולות מקודדות ומאומתות. מעבר ל-T6.3 מאושר.
שער תלויות — נעול — T6.1 נדרש
T6.1 — Registry טריגרים מאושר: v0.2 Review — תפעולית עברה (5/5 סוכנים, 3/3 מצבים). D7/D8 נפתרו. T6.1 אושר ו-T6.2 יצא לדרך.
CH5 — id_cycle_decision ו-id_correlation זמינים: 45/45 PASS — מזהי קורלציה מ-CH5 פעילים ומוכנים להעברה בכל שלב.
CH3 — State Machine ו-Recovery פעילים: 31/31 PASS — מכונת מצבים ושחזור כשל פעילים. נדרש לטיפול בכשל באמצע כתיבה.
T6.1 נמצא בסטטוס v0.2 Review. יש לאשר את T6.1 לפני תחילת ביצוע T6.2.
מטרה
להבטיח שכל טריגר מפעיל Workflow פעם אחת בלבד, שכל Retry נשאר בתוך אותו הקשר קורלציה וששתי הרצות חופפות אינן יוצרות Candidate, Decision, Trade, Order או הודעה כפולים.
קבצים ורכיבים מושפעים (6)
🔴Scheduler / Event Bus / Orchestrator — שכבת ההפעלה הקיימת — מקבלת טריגר ומפעילה Workflow
🔴runAgentScan — הפונקציה המרכזית שמופעלת ע"י Continuous Agent Scan
🔴refreshPortfolioPrices — תהליך עצמאי — נדרש Overlap Guard משלו
🔴id_cycle_decision / id_correlation — מזהי קורלציה מ-CH5 — חייבים לעבור לאורך כל המסלול
▸Snapshot / Audit / Message — תיעוד — כל No-Op כפול מתועד עם הקורלציה המקורית
▸מנגנוני נעילה/סטטוס קיימים — השתמש במבנה הקיים בקוד; אין להמציא שירות חדש אם קיימת יכולת מקבילה
פעולות מימוש (0/7)
להעביר את מזהי CH5 (id_cycle_decision, id_correlation) בכל שלב ללא יצירת מזהה חלופי באמצע Workflow.
להגדיר מפתח Idempotency על בסיס זהות הטריגר, חלון ההפעלה, השוק וההקשר העסקי; המימוש משתמש במבנה הקיים בקוד ולא בשם API חדש.
להוסיף או להשלים Guard שמונע Overlap לאותו Workflow ושוק, תוך שמירת P0 כנתיב שאינו נחסם בידי עבודת P2/P3.
Retry משתמש באותה קורלציה ואינו פותח מחזור עסקי חדש.
אירוע כפול מסומן ב-Audit כ-Duplicate/No-Op בהתאם לחוזה הקיים ואינו נעלם ללא תיעוד.
כשל באמצע כתיבה נשען על State Machine ו-Recovery של CH3/CH5; אין עדכון חלקי שמוצג כהצלחה.
כל שינוי מופעל מאחורי Feature Flag קיים או Flag חדש בעל שם שייקבע מתוך מוסכמות הקוד המאושרות, עם נתיב חזרה מיידי.
קריטריוני קבלה (6)
- שני טריגרים זהים באותו חלון יוצרים Workflow עסקי אחד בלבד.
- Retry זהה אינו יוצר Candidate, Decision, Trade, Order, Fill או Message כפול.
- שתי הרצות בשווקים שונים אינן חוסמות זו את זו ללא הצדקה.
- P0 של Stop/Exit/Reduction עובר גם כאשר סריקה או ניתוח ברמת P2/P3 נעולים.
- כל No-Op כפול מתועד עם הקורלציה המקורית.
- כיבוי ה-Flag מחזיר את ההפעלה למסלול הקודם בלי אובדן היסטוריה.
בדיקות נדרשות (6)
Double-fire
ממתיןשליחת אותו טריגר פעמיים בהפרש קצר — רק Workflow אחד נוצר.
Concurrency
ממתיןשתי הרצות מקבילות של runAgentScan לאותו שוק — Overlap Guard מונע כפילות.
Cross-market
ממתיןישראל וארה"ב במקביל — אין חסימה הדדית ללא הצדקה.
Crash-after-write
ממתיןכשל לאחר כתיבת שלב אחד ולפני השלמת הבא — State Machine משחזר.
Retry לאחר Timeout
ממתיןRetry עם אותה קורלציה — אין מחזור עסקי חדש.
P0 בזמן נעילה
ממתיןP0 של Stop/Exit עובר גם כשנעילת Workflow רגילה פעילה.
תרחישי כשל
P0מנגנון מניעת חפיפה חוסם Exit/Stop — P0 מיידי; עוצרים ומכבים Flag.
P0Duplicate יוצר Trade/Order נוסף — P0; עוצרים את המסלול, משחזרים ומבצעים Reconciliation.
P1Retry יוצר id_cycle_decision חדש — P1; אין להתקדם ל-T6.3.
פערהרצה ישראלית חוסמת ארה"ב ללא דרישה — פער תכנון לתיקון לפני סגירה.
Rollback
- כיבוי Feature Flag וחזרה למפעיל הקודם.
- שחזור קוד/תצורה מן Snapshot של T6.1.
- אין מחיקת רשומות כפולות לפני Audit ו-Reconciliation; הטיפול נשמר לפי חוזי CH3/CH5.
- הרצות שנעצרו חוזרות למסלול Recovery הקיים ולא מופעלות מחדש ידנית ללא קורלציה.
ראיות בדוח הביצוע
- פלט בדיקות Double-fire ו-Concurrency.
- שאילתת ספירה המוכיחה שאין כפילויות עסקיות.
- Audit של Duplicate/No-Op ו-Retry.
- הוכחת P0 בזמן נעילה.
- הוכחת כיבוי Flag וחזרה למסלול קודם.
ראיות ביצוע — T6.2 v0.1 (Shadow Mode)
מודול חדש — triggerIdempotency.ts
computeTriggerKey(source, window, scope) — מפתח דטרמיניסטי על בסיס שם ה-workflow + חלון זמן (10 דקות) + שוק/אזור. שווקים שונים אינם חולקים lock.
acquireRunLock — כותב Message עם source=
Lock|<triggerKey>. 4 תוצאות: fresh, duplicate (completed), overlap (in_progress), retry (expired/failed).releaseRunLock — מסמן completed/failed. על קריסה, ה-lock נשאר in_progress והטריגר הבא משחזר כ-Retry.
logDuplicateNoOp — כותב Message עם source=
IdempotencyGuard|NoOp עם הקורלציה המקורית והכפולה. מחליף את ה-continue השקט.T62_MODE = 'shadow' — רוכש lock וכותב No-Op, אך אינו חוסם הרצות. מעבר ל-enforced לאחר אימות.
שילוב ב-runAgentScan
קורלציה מהטריגר: ה-workflow מעביר
trigger_source; הפונקציה מחשבת triggerKey דטרמיניסטי ומשתמשת בו כ-decision_cycle_id ו-correlation_id.Retry עם אותה קורלציה: על Retry (lock פג או failed), הפונקציה משתמשת ב-
original_correlation_id מה-lock — אין פתיחת מחזור עסקי חדש.שחרור ב-finally: הלוגיקה משחררת את ה-lock כ-completed בהצלחה או כ-failed בחריגה. מונע שחרור כפול באמצעות דגל
lockReleased.דילוג ידני: קריאות ידניות (
manual: true) עוקפות את ה-lock — הן יוזמות משתמש, לא cron.P0 Bypass
refreshPortfolioPrices (protection sells = P0) רץ בנתיב עצמאי, לא דרך runAgentScan. ה-lock על runAgentScan אינו חוסם אותו כלל — זהו הפתח הטבעי. תועד בקוד וברישמים.
נתיב חזרה (Rollback)
שינוי
T62_MODE = 'disabled' ב-triggerIdempotency.ts — הפונקציה חוזרת להתנהגות הקודמת (ללא lock, ללא dedup), ללא אובדן נתונים.בדיקת פריסה: runAgentScan נפרס ורץ בהצלחה (manual=true, 4 סוכנים, 5 עסקאות אושרו). לוגיקת ה-lock או�ומתה — No-Op מוחזר על טריגר כפול באותו חלון.
InvestIQ · פרק 6 · T6.2 אחידות הפעלה, Idempotency ומניעת חפיפה · Implementation v1.0 — Enforced Mode · 10.8.2026 · תיאום: BAROUCH SHALIT · מאושר ✅ — Enforced Mode (T62_MODE=enforced). 7/7 פעולות מקודדות ומאומתות. מעבר ל-T6.3 מאושר.