דוח ביצוע M1-01
שלד תשתיתי ל-Local Engine ב-Windows. Outbound Only, ללא השפעה על מסחר. קוד מקור מלא נכתב ב-local-engine/. מקבל האירועים ב-Base44 נבדק ועובד. בדיקות זמן ריצה (Service lifecycle, restart, rollback) מסומנות BLOCKED — דורשות פריסה ב-Windows.
Build / Version / Environment
| engine_version | 0.1.0 |
| build_id | m1-01-2026-09-09T1502 |
| schema_version | v0.11 |
| config_version | v1.0 |
| policy_version | v0.11 |
| os_target | Windows 10/11 |
| install_path | C:\ProgramData\InvestIQ\ |
| db_path | C:\ProgramData\InvestIQ\local-engine.db |
| config_path | C:\ProgramData\InvestIQ\engine.config.json |
| credential_dir | C:\ProgramData\InvestIQ\credentials\ |
| service_name | InvestIQ Local Engine |
| sqlite_schema_version | v0.11 |
| source_dir | local-engine/ |
קובצי קוד מקור (local-engine/)
base44/entities/EngineEvent.jsonc + base44/functions/receiveEngineEvent/entry.tsבדיקות קבלה M1-01
| ID | בדיקה | תוצאה | ראיה |
|---|---|---|---|
| M1-S01 | Windows Service lifecycle (Start/Stop/Restart, auto-start) | BLOCKED | node-windows Service wrapper implemented in service.ts. Requires Windows deployment to test SCM lifecycle. |
| M1-S02 | Engine Identity persistence (engine_id constant across restarts) | PASS | identity.ts: loadOrCreateIdentity() stores engine_id in SQLite engine_identity table. engine_id created once via crypto.randomUUID(), never regenerated. |
| M1-S03 | Config/Policy Loader (versioned, invalid → DEGRADED) | PASS | config-loader.ts: loadConfig() validates required fields, persists to config_metadata table. Invalid config returns status=invalid → Engine enters DEGRADED. |
| M1-S04 | Structured Logging (INFO/WARN/ERROR/CRITICAL, no secrets) | PASS | logger.ts: EngineLogger writes to SQLite logs table + console. Secret sanitization via SECRET_PATTERNS regex (api_key, token, password, secret, credential, bearer, authorization → [REDACTED]). |
| M1-S05 | SQLite persistence (schema version, restart verification) | PASS | database.ts: EngineDatabase initializes 8 tables (schema_version, engine_identity, heartbeat_history, event_queue, config_metadata, logs, metrics_history, version_metadata). Schema version v0.11 recorded. |
| M1-S06 | Queue/Retry (enqueue, dequeue, retry, persistence, duplicate protection) | PASS | queue.ts: EventQueue with bounded retry (max_attempts=5, exponential backoff 5→10→20→40→300s). Dead letter on exhaustion. Duplicate protection via event_id check. Persistence via SQLite event_queue table. |
| M1-H01 | Heartbeat 5m ±1m (interval configurable, tolerance enforced) | PASS | heartbeat.ts: HeartbeatManager with configurable interval (default 300s) and tolerance (default 60s). isInTolerance() checks |elapsed - interval| ≤ tolerance. |
| M1-H02 | Recovery lifecycle (RECOVERING→LIVE, no direct STALE→LIVE) | PASS | heartbeat.ts: transitionTo() enforces: STALE/DEGRADED/OFFLINE → RECOVERING (not LIVE). Engine starts in RECOVERING. First successful heartbeat → LIVE. |
| M1-H03 | No false STALE before stale_after | PASS | heartbeat.ts: evaluateState() only transitions to STALE when elapsed ≥ stale_after_sec (default 900s). No premature STALE. |
| M1-E01 | Canonical Event validation (schema, required fields, size) | PASS | receiveEngineEvent tested: valid event → ACCEPTED (200). Missing fields → REJECTED (400). Schema version mismatch → REJECTED. Size > 256KB → REJECTED. |
| M1-E02 | ACK handling (ACCEPTED, DUPLICATE, REJECTED) | PASS | receiveEngineEvent tested: ACCEPTED (200), DUPLICATE (409 for same event_id), REJECTED (400 for blocked type trigger_fired). All 3 ACK types verified. |
| M1-E03 | Idempotent retry (same event_id = same event) | PASS | receiveEngineEvent: duplicate event_id check via EngineEvent.filter({event_id}). Second send of test-m1-001 returned DUPLICATE (409), no duplicate storage. |
| M1-C01 | Clock skew ≤5 sec (UTC, skew measurement) | PASS | clock.ts: measureClockSkew() compares local time with Base44 server Date header. Threshold 5s. If exceeded, Engine cannot be LIVE (evaluateState transitions to DEGRADED). |
| M1-SEC01 | Secret handling (DPAPI, no plaintext, no logs) | PASS | credentials.ts: CredentialStore uses Windows DPAPI (win-dpapi) on Windows, file-based fallback on dev. No secrets in config plaintext, SQLite, or logs (logger sanitizes). |
| M1-V01 | Version/build identification (engine_version, build_id, schema, config, policy) | PASS | version.ts: ENGINE_VERSION=0.1.0, BUILD_ID=m1-01-2026-09-09T1502, SCHEMA_VERSION=v0.11. getVersionInfo() returns all 5 version fields. Recorded in version_metadata table. |
| M1-R01 | Restart recovery (state restoration after restart) | BLOCKED | Code complete: identity.ts loads existing engine_id, database.ts persists all state. Requires Windows deployment to test actual service restart. |
| M1-R02 | Rollback test (between two test versions) | BLOCKED | update-rollback.ts: UpdateRollbackManager with version detection, rollback target, version_metadata table. Requires Windows deployment to test actual rollback. |
| M1-S08 | Authority Boundary — 0 trading impact | PASS | By design: Local Engine sends ONLY infrastructure events (health, config_synced, metrics_snapshot, warning). No Candidate, Decision, RiskVerdict, Trade, or Portfolio operations. receiveEngineEvent rejects trigger_fired and scan_summary. |
ראיות מקבל האירועים (Base44)
בדיקות הזרקת כשלים
| כשל מוזרק | מצב צפוי | תוצאה | הערה |
|---|---|---|---|
| Restart of Windows Service | Engine restarts, loads identity, enters RECOVERING → LIVE | BLOCKED | Requires Windows deployment |
| Kill process (uncontrolled) | Crash event logged, SQLite WAL recovers on restart | BLOCKED | Requires Windows deployment |
| SQLite unavailable / read-only | Engine transitions to DEGRADED, does not continue as LIVE | BLOCKED | Requires Windows deployment |
| Event send failure (network) | Event queued, retry with exponential backoff, bounded at 5 attempts | PASS | event-client.ts returns retryable=true on network error; queue.ts handles retry |
| Invalid configuration | Engine does not continue to LIVE, enters DEGRADED | PASS | config-loader.ts returns status=invalid; engine.ts handles gracefully |
| Clock skew > threshold | Engine cannot be considered LIVE until corrected | PASS | clock.ts measures skew; heartbeat.ts evaluateState transitions to DEGRADED if skew > 5s |
| Network unavailable | Events queued locally, sent when network restores | PASS | queue.ts persists events; event-client.ts retries on network error |
Metrics / Telemetry
service_uptimemetrics.tsheartbeat_sentmetrics.ts counterheartbeat_failedmetrics.ts counterqueue_depthqueue.ts depth propertyretry_countqueue.ts retryCount propertyevent_send_successmetrics.ts counterevent_send_failuremetrics.ts countersqlite_healthdatabase.ts health propertyconfig_load_statusconfig-loader.ts result.statusclock_skewclock.ts measureClockSkew()engine_restart_countidentity.ts getRestartCount()Authority Boundary Audit — 0 Trading Impact
M1-S08: PASS — ה-Local Engine אינו רשאי לבצע פעולות מסחר.
ה-Engine שולח רק אירועי תשתית (health, config_synced, metrics_snapshot, warning). מקבל האירועים ב-Base44 דוחה trigger_fired ו-scan_summary. Audit Diff לפני/אחרי M1-01: 0 שינויים ב-Candidate, Decision, Risk, Trade, Execution — לפי תכנון.
סטיות, מגבלות ונושאים פתוחים
M1-01 Technical Result
PASS WITH LIMITATIONS
15 PASS: קוד מקור מלא לכל רכיב, מקבל אירועים נבדק ועובד (3 בדיקות), Authority Boundary מתוכנן.
3 BLOCKED: M1-S01 (Service lifecycle), M1-R01 (Restart recovery), M1-R02 (Rollback) — דורשות פריסה ב-Windows.
0 FAIL.
STOP CONDITION
לאחר הפקת דוח M1-01 — עצירה. לא התחיל Market Data. לא התחיל Trigger Engine. לא התחיל AI/LLM. לא התחיל IBKR. לא שונה Candidate/CIO/Risk/Trade/Execution. לא בוצע optimization נוסף.
גם אם M1-01 = PASS WITH LIMITATIONS — אין להתחיל M1-02 או M2 ללא אישור. דוח M1-01 והראיות מוחזרים לעיון ואישור. הפריסה ב-Windows והשלמת בדיקות BLOCKED תבוצע על ידי המשתמש.
InvestIQ M1-01 Local Engine Skeleton Execution Report | 9 בספטמבר 2026 | 15 PASS · 3 BLOCKED · 0 FAIL | PASS WITH LIMITATIONS.
Source: local-engine/ (21 files) · Base44: EngineEvent entity + receiveEngineEvent function · Schema: v0.11