| 1 | ישות Decision נוצרת עם כל שדות החובה — validateDecision מחזיר valid=true. | PASS | createDecision מאמת base required + action-dependent. |
| 2 | שדות חובה תלויי פעולה: BUY דורש quantity, reference_price, stop_loss, take_profit, max_entry_price, risk_reward_ratio, max_loss_usd, exit_rules. | PASS | ACTION_REQUIRED_FIELDS[BUY] נבדק ב-validateDecision. |
| 3 | decision_context (ENTRY/POSITION/EXIT) מוגדר לכל Decision ותואם ל-action. | PASS | CONTEXT_ACTIONS מאמת שילוב. runAgentScan מעביר ENTRY/EXIT. |
| 4 | decision_family_id יציב: זהה לכל גרסאות אותה החלטה. decision_id ייחודי לכל גרסה. | PASS | createDecision מייצר family_id. supersedeDecision שומר family_id. |
| 5 | מעבר DRAFT→ACTIVE מקפיא Snapshot: snapshot_frozen, snapshot_id, snapshot_hash, input_refs, snapshot_data מאוכלסים. | PASS | publishDecision מייצר snapshot_id, snapshot_hash (SHA-256), input_refs. |
| 6 | snapshot_data מסונן: אין Secrets, API keys. "פלט LLM מלא" אינו נשמר. | PASS | filterSecrets מסיר מפתחות רגישים. llm_output הוסר — filtered_agent_output בלבד. |
| 7 | snapshot_hash הוא SHA-256 של JSON קנוני (sorted keys, no whitespace). | PASS | canonicalStringify + sha256 ב-publishDecision. |
| 8 | גרסה חדשה מעלה decision_version, מקשר parent_decision_id, ומסמן ישן כ-SUPERSEDED עם superseded_by. | PASS | supersedeDecision מבצע הכל. |
| 9 | החלפת גרסה אטומית: CAS (version_cas) + idempotency_key מונעים שתי גרסאות ACTIVE. | PASS | חדש נוצר ראשון (אם נכשל — ישן נשאר ACTIVE). updateMany אטומי מסמן ישן SUPERSEDED. מפסיד מוחק יתום. 7/7 בדיקות: old SUPERSEDED+superseded_by→new, 1 ACTIVE, call-2 נחסם. |
| 10 | getActiveDecision מחזיר רק את הגרסה ה-ACTIVE האחרונה לפי family_id. | PASS | עוקב שרשרת SUPERSEDED + בודק family Actives. |
| 11 | expires_at נאכף: Decision שפג תוקפו מסומן EXPIRED. TTL תלוי הקשר (ttl_context). | PASS | checkDecisionExpiry + assertDecisionActive. ttl_context נשמר. |
| 12 | EXPIRED/SUPERSEDED/CANCELLED אינם יכולים ליצור Trade. | PASS | assertDecisionActive זורק על מצב לא-ACTIVE. |
| 13 | Trade כולל decision_id, decision_version, decision_family_id המפנים ל-Decision. | PASS | runAgentScan מעביר את שלושתם ל-createTradeWithAudit. |
| 14 | assertDecisionActive נאכף בגבול הביצוע המשותף: tradeExecution.ts + executeTrade + refreshPortfolioPrices. | PASS | יבוא + קריאה ב-3 קבצים. פרצת Legacy נסגרה: null decision_id עובר רק עם legacy=true. Enforced: זורק על Trade חדש ללא Decision. |
| 15 | try/catch לפי מצב: Enforced — כשל חוסם עסקה. Shadow — נפילה + לוג. Disabled — ישיר. | PASS | getFeatureFlagMode() מחזיר enforced/shadow/disabled. runAgentScan: continue ב-Enforced. assertDecisionActive: זורק ב-Enforced על Trade ללא Decision. |
| 16 | cancelDecision דורש cancel_reason_code קנוני. טקסט חופשי משלים בלבד. | PASS | VALID_REASON_CODES נבדק. cancel_reason_text אופציונלי. |
| 17 | approval_required נקבע לפי automation_mode + confidence. Risk Gate ו-Approval ברשומות נפרדות — שערי בקרה לפני ביצוע. | PASS | RiskVerdict(PASS) ב-TRADE_VALIDITY (else branch). checkRiskGatePassed+checkApprovalValid לפני executeTrade. 8/8 בדיקות: בלי PASS נחסם, בלי Approval נחסם, רק שניהם מותרים. |
| 18 | שדות עקיבות: schema/policy/model/prompt/agent_profile version, correlation_id נשמרים בעת יצירה. | PASS | createDecision שומר את כולם. runAgentScan מעביר correlation_id + model_version. |
| 19 | created_at ו-published_at נפרדים. | PASS | createDecision: created_at. publishDecision: published_at. |
| 20 | hard_semi בכל ה-entities: Trade, Portfolio, Decision. פרופיל משנה של semi. | PASS | enum בכל הישויות. poolField כולל hard_semi + backward compat. |
| 21 | correlation_id זורם מ-Decision דרך Risk Gate → Approval → Trade → Audit. | PASS | createDecision שומר correlation_id=runId. RiskVerdict/ApprovalRecord כוללים correlation_id. |
| 22 | CH3-007: Risk Gate משווה מחיר ביצוע מול Decision.reference_price. | PASS | TRADE_VALIDITY ב-refreshPortfolioPrices: fetch Decision → reference_price. |
| 23 | CH3-013: Decision.reasoning נפרד משדות מובנים. validateDecision אוכף Schema. | PASS | reasoning שדה נפרד. validateDecision אוכף action-dependent. |
| 24 | CH3-014: correlation_id + decision_id/version בנתיב ה-Audit המלא. Snapshot קפוא לשחזור. | PASS | Trade.decision_id + correlation_id. snapshot_hash לשחזור. |
| 25 | decision_context מתואם לפרק 2: ENTRY=BUY,WAIT,REJECT · POSITION=HOLD,REDUCE,INCREASE,WAIT,EXIT_REVIEW · EXIT=SELL,WAIT,REJECT_EXIT. | PASS | CONTEXT_ACTIONS תואם לפרק 2. |
| 26 | DRAFT→ACTIVE אינו דורש Risk Gate. הסדר: ACTIVE → Risk Gate → Approval → Execution. | PASS | publishDecision אינו בודק Risk Gate. RiskVerdict נפרד. |
| 27 | Decision אינה מכילה risk_gate_passed, approval_id — אלו ב-RiskVerdict/ApprovalRecord. | PASS | ישויות נפרדות נוצרו. Decision אינה מכילה שדות אלו. |
| 28 | supersedeDecision אטומי: גם בשתי קריאות מקבילות נשארת גרסה ACTIVE אחת. | PASS | DRAFT-first: new נוצר כ-DRAFT (לא ACTIVE). CAS אטומי = מעבר יחיד (old.superseded_by = Family Active Pointer). רק אחרי זכייה — קידום ל-ACTIVE. crash test: 13/13 — crash אחרי CAS משאיר 0 ACTIVE, getActiveDecision משחזר בדיוק 1. 🔒 PROVEN. |
| 29 | Trade חדש ב-Enforced דורש Decision תקף. Trade היסטורי ממשיך בדגל legacy. | PASS | Enforced: continue על כשל יצירת Decision. legacy field ב-Trade. assertDecisionActive(b, id, isLegacy): null עובר רק עם legacy=true. Enforced: זורק על null+legacy=false. |
| 30 | cancel_reason_code אינו כולל TIMEOUT/SUPERSEDED — אלו מעברי מצב נפרדים. | PASS | VALID_REASON_CODES: USER_CANCELLED, POLICY_CHANGE, MARKET_CLOSED, DATA_STALE, RISK_BREACH, MANUAL_OVERRIDE. |
| 31 | אין מיגרציית נתונים semi_hard→hard_semi. שם קנוני hard_semi ב-enum. | PASS | enum: hard_semi. poolField: hard_semi + semi_hard backward compat. ללא מיגרציה. |