מפרט טכני CH3 — Implementation Backlog
Version 0.2.2 — Review27.8.2026
סדר פעולה מוסכם
1.✓ להוציא גרסה מתוקנת של המסמך — Version 0.2.
2.✓ לאשר גרסה זו בכתב.
3.✓ מיפוי וניתוח של CH3-001 בלבד — ללא שינוי קוד: רשימת קבצים, סכמה נוכחית, תלויות, ובדיקת Message entity.
4.✓ לקבל רשימת קבצים, סכמה נוכחית, תלויות ותוכנית שינוי מפורטת.
4.1.✓ הכרעות Architect v0.2.2: 4 שאלות פתוחות + 2 הוראות מחייבות + הכרעת חפיפת Cron.
4.2.✓ אישור כתוב של מנגנון מניעת חפיפת Cron — בעל ביצוע יחיד (v0.2.2).
5.✓ ביצוע CH3-001 — מאושר לביצוע (כל התנאים התקבלו).
6.✓ עצור, בדיקה ודוח קבלה לפני CH3-002.
כללי עבודה
- •לא משנים החלטות פרקים 1–2 ללא גרסה חדשה ו-ADR.
- •כל נתיב ביצוע ממשיך לעבור דרך shared executeTrade וההגנות הקיימות (Freeze, pools, commission, tax).
- •כל שינוי נתונים (סכמה/סטטוסים) כולל Migration, שמירת Audit, ותאימות לרשומות קיימות.
- •אין לעבור ל-Live לפני סגירת כל משימות P0 וחסמי Go-Live.
- •כל משימה מסתיימת בבדיקת קבלה מתועדת — לא בהצהרת השלמה.
- •כל שינוי סכמה דורש אישור Architect מראש ובכתב.
- •עצירה לאחר כל בדיקה — אין מעבר למשימה הבאה לפני אישור בכתב.
מחוץ לתחום השינוי
- ✗שינויים ב-UI/UX מעבר לתצוגת הסטטוסים החדשים (CH3-002).
- ✗שינויים בלוגיקת חישוב עמלה, מס, או PnL.
- ✗הוספת ברוקר חי (Live) — כל ה-scope הוא Paper Trading.
- ✗שינויים בישויות Portfolio, Alert, Message מעבר לשדות Audit שיוגדרו (CH3-001).
- ✗שינויים ב-workflow scheduling.
- ✗שינויים בלוגיקת ה-LLM Prompt עצמה.
תוכנית Rollback וגיבוי
- •לפני כל התחלת משימה: snapshot של כל הקבצים המושפעים נשמר ב-Git commit נפרד.
- •ב-Base44: לבקש Diff לפני ואחרי כל שינוי.
- •נקודת שחזור: ה-commit לפני תחילת CH3-001 הוא נקודת החזרה ל-v0.1.
- •Migration: כל סקריפט Migration הוא הפיך — נשמר סקריפט rollback מקביל לפני הרצה.
- •אם בדיקת קבלה נכשלת: rollback מיידי לנקודת השחזור, תיעוד הכשלון, לא ממשיכים.
CH3-001 — הפרדת Orchestrator מה-CIO ומה-LLM
P0Go-Live Blocker
המצב הקיים
refreshPortfolioPrices (entry.ts, ~550 שורות) מבצע הכל בפונקציה אחת: רענון מחירים, אימות תפוגה, ביצוע קניות בהמתנה, מחיקת holdings שנמכרו, migration ILS, stop-loss/take-profit, Portfolio Risk Agent (InvokeLLM), התייעצויות מוגנות, ו-auto-sell. runAgentScan (entry.ts, ~600 שורות) מבצע ניתוח LLM + יצירת עסקאות + ביצוע באותה ריצה.
בדיקת Message entity לפני הכרעת סכמה
| שדה נדרש ל-Audit | קיים? | הערה |
|---|---|---|
| step_name | חסר | שם השלב (PRICE_REFRESH / TRADE_VALIDITY / וכו׳) — ניתן לכלול ב-title |
| step_status | חסר | started / completed / failed — ניתן לכלול ב-summary |
| actor | קיים (source) | source משמש כ-actor — מספיק |
| timestamp | קיים (created_date) | created_date אוטומטי — מספיק |
| correlation_id | חסר | מזהה ריצה לשיוך כל שלבי ריצה אחת — נדרש הכרעה |
הוכרע (מיפוי + אישור Architect, v0.2.2): אפשרי ללא שינוי סכמה — קידוד בשדות קיימים (title/source/severity). ⚠ תיעוד תפעולי זמני בלבד — לא פתרון ה-Audit הסופי של המערכת. שמירת 30 יום מספיקה לבדיקת CH3-001 ותחקור קצר; פתרון שימור קבוע ייסגר לפני Live (ADR נפרד, מחוץ ל-CH3-001).
פעולות
- •פיצול refreshPortfolioPrices לשלבים דטרמיניסטיים נפרדים המפיקים אירוע (step event) לכל שלב.
- •runAgentScan ו-InvokeLLM יקבלו משימה מובנית ויחזירו Structured Output בלבד — ללא החלטות Retry/Timeout/סטטוס.
- •Risk Gate, Approval, Trade Validity ו-Execution יופעלו כשלבים נפרדים ומתועדים.
- •לפני יצירת shared/auditSteps.ts: לבדוק תחילה אם Message entity מסוגל לשמור את כל שדות ה-Audit הנדרשים. רק אם חסרים שדות — לשקול שינוי סכמה.
ארכיטקטורת יעד — 6 שלבים (שלב 3 בלבד = LLM)
| שלב | תיאור | דטרמיניסטי |
|---|---|---|
| 1. PRICE_REFRESH | שירות דטרמיניסטי: fetchQuote לכל symbol → עדכון current_price/value/pnl ב-Portfolio. ללא LLM. | כן |
| 2. TRADE_VALIDITY | בודק pending trades מול מחיר חי: סטייה > threshold → סימון לא-תקף (אין ביצוע/ביטול). | כן |
| 3. CIO_SCAN | runAgentScan: InvokeLLM מחזיר Structured Output בלבד {recommendation, confidence, reasoning}. אין יצירת Trade כאן. | LLM בלבד |
| 4. RISK_GATE | בודק פלט סריקה מול: Freeze, cash pool, max_per_trade, exposure. החלטה דטרמיניסטית: אשר/דחה/המתן. | כן |
| 5. APPROVAL | auto → ממשיך; semi → pending עם approval_expires_at; manual → alert בלבד. | כן |
| 6. EXECUTION | קריאה יחידה ל-shared executeTrade (עם כל ההגנות הקיימות). | כן |
קבצים מושפעים
- ›base44/functions/refreshPortfolioPrices/entry.ts — פיצול לשלבים + הסרת החלטות LLM
- ›base44/functions/runAgentScan/entry.ts — הפיכה ל-CIO טהור: פלט Structured Output בלבד
- ›base44/shared/orchestrator.ts (חדש) — רץ השלבים הדטרמיניסטי + תיעוד step events
- ›base44/shared/auditSteps.ts (חדש) — כתיבת step events — ⚠ תלוי בהכרעת Message entity
Migration
אין שינוי סכמה מתוכנן. ⚠ תלוי בתוצאת בדיקת Message entity (ראה למעלה) — אם יידרש correlation_id תיידרש הכרעה נפרדת.
הכרעות Architect — v0.2.2
| שאלה פתוחה | הכרעה | סטטוס |
|---|---|---|
| evaluateProtectionStatus — היכן ישב? | ניתוח/המלצה בלבד ב-CIO_SCAN (שלב 3). החסימה בפועל דטרמיניסטית ב-RISK_GATE (שלב 4). | הוכרע |
| autoSellHolding / evaluateTakeProfit — מיקום? | עוברים לשלב 6 (EXECUTION). פעולות מכירה, Stop והגנה מקבלות קדימות לפני קניות ופתיחת סיכון חדש בתוך השלב. | הוכרע |
| תיעוד שלב שלא שינה דבר? | כן — יתועד בסטטוס מפורש completed_no_action, כדי להבדיל "בוצע ללא פעולה" מ-"שלב שלא הופעל". | הוכרע |
| השארת לוחות הזמנים הקיימים? | מותנית במנגנון מניעת חפיפה ל-EXECUTION — ראה הכרעת חפיפת Cron למטה. ללא מנגנון: אין לאשר השארה. | הוכרע |
הוראות מחייבות
1.summary יישמר כ-JSON במבנה קבוע וגרסאי (schema_version), לא כטקסט חופשי.
{
"schema_version": "1",
"run_id": "string",
"step": "PRICE_REFRESH|TRADE_VALIDITY|CIO_SCAN|RISK_GATE|APPROVAL|EXECUTION",
"status": "started|completed|completed_no_action|failed",
"actor": "string",
"started_at": "iso",
"ended_at": "iso|null",
"trade_id": "string|null",
"details": "object",
"error": "string|null"
}2.בדיקת קבלה חייבת להוכיח שליפה של כל 6 האירועים לפי runId בסדר הנכון. אם לא ניתן — הכרעת "ללא שינוי סכמה" נפתחת מחדש (יידרש שדה correlation_id ייעודי).
הכרעת חפיפת Cron — interim עד CH3-003
סיכון: שני ה-cron (*/10 סריקה, */15 רענון) נפגשים כל 30 דקות; אם שניהם יקראו ל-executeTrade → כפילות ביצוע ומירוץ על cash pools. נעילה רכה ב-Message ("busy marker") אינה אטומית ועלולה לאפשר לשתי ריצות לעבור יחד — אינה מקובלת.
מנגנון: בעל ביצוע יחיד זמני עד CH3-003 (ללא נעילה, ללא שינוי סכמה):
- •Continuous Agent Scan מבצע ניתוח (CIO_SCAN), Risk Gate ו-Approval בלבד — ואינו קורא ל-executeTrade כלל.
- •Portfolio Price Refresh הוא היחיד שרשאי להפעיל את שלב EXECUTION.
- •סדר פנימי ב-EXECUTION של Portfolio Price Refresh: תחילה מכירות הגנה (Stop / Take Profit / auto-sell), ולאחר מכן עסקאות קנייה מאושרות שעברו Trade Validity.
- •אין להשתמש בנעילה באמצעות Message. אין להסתמך על execution_state (CH3-003) שטרם יושם.
- •קניות שאושרו על-ידי ה-Scan נשמרות כ-approved וממתינות לריצת ה-Refresh הבאה, שתבצע אותן דרך executeTrade.
בדיקת קבלה: בדיקת הקבלה תפעיל את שני ה-Workflows בו-זמנית ותוכיח שלכל Trade קיימת קריאה אחת בלבד ל-executeTrade.
✓ מאושר על-ידי Architect (v0.2.2). לאחר אישור Base44 — CH3-001 מאושר לביצוע.
תנאי קבלה
- ✓ה-LLM אינו מחליט על Retry, Timeout או שינוי סטטוס תפעולי.
- ✓ניתן לזהות ב-Audit את תחילת וסיום כל שלב (step_start / step_end עם timestamp ו-actor).
- ✓שלב שלא שינה דבר מתועד בסטטוס completed_no_action (מבדיל מ"לא הופעל").
- ✓כשל בשלב אחד אינו מפעיל מחדש אוטומטית שלבים שכבר הושלמו.
- ✓summary נשמר כ-JSON גרסאי (schema_version) במבנה קבוע — לא טקסט חופשי.
- ✓בדיקת קבלה מוכיחה שליפה של כל 6 האירועים לפי runId בסדר הנכון. אם לא — "ללא שינוי סכמה" נפתח מחדש.
בדיקת קבלה: הרצת workflow ובדיקה שב-Message entity נכתבים step events לכל 6 השלבים, ה-LLM אינו מופיע בשום trace של החלטת Timeout/Retry, וניתן לקשר את כל האירועים של ריצה אחת.
CH3-002 — מכונת מצבים דטרמיניסטית
P0Go-Live Blocker
הפרדת שלושת המישורים (לפני שינוי סכמה)
| מישור | Scope | ערכים | נשמר ב-DB |
|---|---|---|---|
| מצב מחזור העבודה של ה-Orchestrator | פנימי ל-backend בלבד — לא נשמר ב-DB | INITIALIZING → PRICE_REFRESHED → VALIDITY_CHECKED → CIO_SCANNED → RISK_GATED → APPROVAL_SET → EXECUTION_DONE | לא |
| הסטטוס העסקי של ה-Trade | Trade.status — גלוי למשתמש ולכל הממשקים | pending → approved / rejected / WAIT / EXPIRED / ESCALATED_FOR_REVIEW | כן |
| מצב פקודת הביצוע מול הברוקר | Trade.execution_state — שדה נפרד, לשימוש פנימי + Reconciliation | NOT_SENT → SENT → CONFIRMED / FAILED / RECONCILIATION_REQUIRED | כן |
סטטוסים קנוניים — כולם lowercase
| שם | חדש/קיים | תיאור | טרמינל |
|---|---|---|---|
| pending | קיים | הצעה בהמתנה לאישור | לא |
| approved | קיים | מאושר לביצוע | לא |
| executed | קיים | בוצע | כן |
| rejected | קיים | נדחה ידנית על-ידי משתמש | כן |
| wait | חדש | המתנה לתנאי שוק (buy-limit/stop שלא התמלאו) | לא |
| expired | חדש | תוקף האישור פג — TTL או סטיית מחיר חריגה | כן |
| escalated_for_review | חדש | הועבר לבדיקה אנושית (מניה מוגנת / סכסוך החלטה) | לא |
RECONCILIATION_REQUIRED הועבר ל-CH3-003 (execution_state בלבד — לא Trade.status).
מטריצת מעברים חוקיים
| מ- (from) | אל (to) — מותר |
|---|---|
| pending | approved, rejected, expired, wait, escalated_for_review |
| wait | approved, expired, rejected |
| approved | executed, rejected, expired |
| escalated_for_review | approved, rejected |
| executed / rejected / expired | טרמינל |
מעבר אל escalated_for_review: מגיע מ-pending בלבד (כלול בשורת pending).
פעולות
- •הפרדה מוחלטת בין שלושת המישורים לפני כל שינוי סכמה (ראה טבלת מישורים).
- •קביעת שמות קנוניים — כולם lowercase — לתאימות עם הקוד הקיים (pending, approved, executed, rejected, wait, expired, escalated_for_review).
- •הגדרת מטריצת מעברים חוקיים ב-shared/stateMachine.ts עם assertTransition().
- •חסימת מעבר ישיר pending → executed (חובת approved בינתיים).
- •תפוגה → expired (לא rejected). rejected שמור לדחייה ידנית בלבד.
- •מקור אמת יחיד להיסטוריה: Message Audit בלבד — ללא שדה status_history על Trade.
- •Migration מ-rejected ל-expired: רק כאשר קיימת ראיה ברורה (שדה approval_expires_at עבר). ללא ראיה → Trade נשאר rejected ומסומן לבדיקה ידנית.
שינוי סכמה — Trade ⚠ דורש אישור Architect
status enum מורחב מ-[pending, approved, executed, rejected] ל-[pending, approved, executed, rejected, wait, expired, escalated_for_review]. כולם lowercase.
| שדה חדש | סוג | תיאור |
|---|---|---|
| expiration_stage | string | null | APPROVAL_TTL_EXPIRED | PRICE_DEVIATION_EXCEEDED | MARKET_DATA_STALE — מסביר מדוע הרשומה עברה ל-expired |
| expiration_reason | string | null | טקסט חופשי — נימוק מפורט לתחקור |
Migration
- •Trade עם status=rejected + שדה approval_expires_at שעבר: → status=expired, expiration_stage=APPROVAL_TTL_EXPIRED.
- •Trade עם status=rejected + אין approval_expires_at: → נשאר rejected, מסומן ב-expiration_reason="pending_manual_review".
- •Migration חד-פעמי, הפיך — סקריפט rollback מוכן לפני הרצה.
- •Migration key: trade.id בלבד (לא symbol+created_date — עלול להתנגש).
קבצים מושפעים
- ›base44/entities/Trade.jsonc — הרחבת enum + 2 שדות ⚠ דורש אישור Architect
- ›base44/shared/stateMachine.ts (חדש) — מטריצת מעברים + assertTransition()
- ›base44/shared/tradeExecution.ts — כל שינוי status עובר דרך assertTransition()
- ›base44/functions/refreshPortfolioPrices/entry.ts — תפוגה כותבת expired + expiration_stage
- ›src/pages/Trades.jsx + src/components/invest/Badges.jsx — תצוגת הסטטוסים החדשים
תנאי קבלה
- ✓מעבר לא-חוקי (למשל pending→executed) נדחה ומתועד ב-Message Audit.
- ✓תפוגת TTL → expired (לא rejected). rejected = דחייה ידנית בלבד.
- ✓אישור מחדש של רשומה שפגה (expired) יוצר רשומה חדשה ואינו פותח את הישנה.
- ✓escalated_for_review ניתן להשגה ממצב pending בלבד.
- ✓כל הסטטוסים במאגר הם lowercase — אין ערבוב.
בדיקת קבלה: ניסיון מעבר pending→executed נדחה; תפוגת TTL → expired עם expiration_stage; אישור מחדש של expired יוצר רשומה חדשה; escalated_for_review מגיע מ-pending.
CH3-003 — Idempotency, Retry ו-Reconciliation
P0Go-Live Blocker
המצב הקיים
אין שדה idempotency_key ב-Trade. יש dedup רך לפי חלון 15 דקות (symbol+side) — אינו חסין ל-timeout. executeTrade אינו מסמן מצב "לא ידוע". אין הפרדה בין "טרם נשלח" ל-"לא ידוע".
שלושת השלבים — כולם דטרמיניסטיים
| שלב | תיאור | דטרמיניסטי |
|---|---|---|
| IDEMPOTENCY_GUARD | לפני שליחת פקודה: בדיקת כפילות לפי idempotency_key. אם קיימת רשומה executed עם אותו key — עצור, החזר את הרשומה הקיימת ללא שליחה חוזרת. | כן |
| RECONCILIATION | לפני כל Retry: בדיקת מצב הפקודה מול DB (execution_state). אם execution_state=RECONCILIATION_REQUIRED — עצור ואל תשלח מחדש עד לאישור ידני. | כן |
| CAPITAL_RESERVATION | בעת שליחת פקודה: נעל הון מה-pool (reserved_capital). בעת אישור ביצוע: המר ל-debit. בעת כישלון: שחרר. מונע overdraft ב-timeout. | כן |
ערכי execution_state
| ערך | תיאור |
|---|---|
| NOT_SENT | רשומה נוצרה אך פקודה טרם נשלחה לברוקר (pending שלא הגיע לביצוע) |
| SENT | פקודה נשלחה, ממתינים לאישור |
| CONFIRMED | ברוקר אישר ביצוע |
| FAILED | ברוקר דחה — ניתן לנסות מחדש לאחר Reconciliation |
| RECONCILIATION_REQUIRED | timeout — מצב הפקודה לא ידוע. עצור ואל תשלח מחדש |
UNKNOWN אינו בשימוש — NOT_SENT לטרם-שליחה, RECONCILIATION_REQUIRED לאחר-timeout.
פעולות
- •הקצאת idempotency_key לכל Execution Command (לא לרשומת Trade — לכל פקודת ביצוע שנשלחת).
- •execution_state=NOT_SENT לרשומות שנוצרו ולא נשלחו (pending/wait). UNKNOWN שמור ל-timeout בלבד.
- •אין Retry לפקודת ברוקר לפני בדיקת execution_state — RECONCILIATION_REQUIRED עוצר הכל.
- •שמירת reserved_capital בעת שליחה — משוחרר בהצלחה/כישלון בלבד.
- •Migration key: trade.id (לא symbol+created_date).
שינוי סכמה — Trade ⚠ דורש אישור Architect
| שדה חדש | סוג | תיאור |
|---|---|---|
| idempotency_key | string | null | מזהה ייחודי לפקודת ביצוע — נוצר בעת שליחה לברוקר (לא בעת יצירת Trade). פורמט: legacy:<trade_id> לרשומות קיימות. |
| execution_state | string | NOT_SENT | SENT | CONFIRMED | FAILED | RECONCILIATION_REQUIRED — מצב פקודת ביצוע מול ברוקר, נפרד מ-Trade.status |
| reserved_capital | number | null | הון שננעל לטובת הפקודה עד אישור/כישלון ביצוע |
Migration
- •רשומות Trade עם status=executed: execution_state=CONFIRMED, idempotency_key=legacy:<trade_id>.
- •רשומות Trade עם status=pending/wait/approved: execution_state=NOT_SENT, idempotency_key=null.
- •רשומות Trade עם status=rejected/expired: execution_state=FAILED, idempotency_key=null.
- •Migration key: trade.id בלבד — לא symbol+created_date (מונע התנגשויות).
- •סקריפט rollback מוכן לפני הרצה.
קבצים מושפעים
- ›base44/entities/Trade.jsonc — 3 שדות חדשים ⚠ דורש אישור Architect
- ›base44/shared/idempotency.ts (חדש) — generateKey() + checkDuplicate() + reserveCapital() / releaseCapital()
- ›base44/shared/tradeExecution.ts — עטיפת ביצוע ב-idempotency guard + reconciliation
- ›base44/functions/refreshPortfolioPrices/entry.ts — אין Retry ללא בדיקת execution_state
- ›base44/functions/runAgentScan/entry.ts — הגדרת idempotency_key בעת שליחת פקודה
תנאי קבלה
- ✓אותו idempotency_key אינו יכול ליצור שתי הוראות ביצוע (Double Order מנוע).
- ✓Timeout → execution_state=RECONCILIATION_REQUIRED (לא שליחה חוזרת).
- ✓רשומת pending שלא נשלחה: execution_state=NOT_SENT (לא UNKNOWN).
- ✓בדיקת קצה מוכיחה שאין Double Order בתרחיש timeout מלאכותי.
בדיקת קבלה: הזרקת timeout מלאכותית בביצוע → execution_state=RECONCILIATION_REQUIRED, reserved_capital נשמר, אין פקודה כפולה. בדיקה שרשומת pending חדשה מקבלת NOT_SENT (לא UNKNOWN).
סיכום Migration ואישורים
| משימה | שינוי סכמה | סיכון | אישור נדרש | הערות |
|---|---|---|---|---|
| CH3-001 | תלוי בדיקת Message entity | נמוך | ייתכן שנדרש (להכרעה) | בדיקת entity לפני הכרעה |
| CH3-002 | Trade.status enum + 2 שדות | בינוני | נדרש Architect | Migration מ-rejected ל-expired רק עם ראיה |
| CH3-003 | 3 שדות חדשים ב-Trade | בינוני | נדרש Architect | Migration key: trade.id בלבד |
InvestIQ CH3 Implementation Backlog v0.2.2 — 27.8.2026 | ממתין לאישור בכתב לפני ביצוע