Version: 1.0 LOCKED Scope: Cloud/server-authoritative
This file is the single source of truth for EngineCore rules. If any other document conflicts, this one wins.
Server-authoritative:
- Server is the single source of truth
- Engine + Features execute on the server
- Clients are render + dispatch only
- No client-side domain authority
Lock 1: Engine + Features MUST be pure
- No IO
- No async/await
- No time access
- No randomness
- No logging
- No framework dependencies
Lock 2: Effects MUST be data-only
- Serializable JSON data only
- No callbacks, no closures
- No runtime handles
Lock 3: Runtime owns ALL IO
- Database, HTTP, WebSocket, queues
- Retry logic
- Correlation IDs
- Idempotency enforcement
Lock 4: Composition MUST be registry-based
- No hardcoded feature routing in engine
- Features added via registry only
Lock 5: Features return FeatureResult only
- { ok: true, effects: Effect[] } — success path
- { ok: false, code, message, type } — failure path
- No thrown exceptions from features
- No plain Effect[] returned directly
- Runtime emits completion event after successful durable commit only
Lock 6: UI is dumb
- Render + dispatch only
- UI-local ephemeral state allowed
- No domain logic in UI
Lock 7: Concurrency handled in Runtime only
- Optimistic version check
- Idempotency required for write operations
- Engine unaware of concurrency mechanics
Lock 8: State MUST be serializable (JSON-safe) State MUST NOT contain:
- Map, Set
- Date objects
- functions
- class instances
- runtime handles State MUST use:
- Record<string, T>
- arrays
- primitives All timestamps are ISO strings.
Lock 9: Engine MUST remain domain-agnostic
- Engine has no knowledge of specific domain models
- Domain logic lives only in Features
- No engine/dealEngine.ts, engine/crmEngine.ts or similar
- Engine operates on generic State + Command + Effect types only
Lock 10: Features MUST be isolated
- A Feature reads only state it owns
- A Feature MUST NOT write another Feature's slice directly
- Cross-feature relationships use ID references only
- Cross-feature side effects are expressed as Effects only
- Exceptions to read isolation MUST be explicitly documented in ARCHITECTURE.md
- Shared/reference data access rules are defined per project in ARCHITECTURE.md
Runtime validates command envelope before Feature execution. Feature validates business rules only.
Validation split:
- Runtime: command shape, required fields, idempotency key, schema
- Feature: business rules, domain constraints, state consistency
Feature MUST assume command envelope is already valid when it executes.
type Command = {
type: string;
idempotencyKey: string;
occurredAtIso: string;
actorId: string; // required — use 'system' for automated/scheduled commands
correlationId?: string;
payload: unknown;
};
type Effect =
| { type: 'SET_STATE'; slice: string; id: string; value: unknown }
| { type: 'APPEND_ACTIVITY'; value: unknown } // payload schema is project-defined in ARCHITECTURE.md
| { type: 'EMIT_EVENT'; eventType: string; payload: unknown }
| { type: 'SCHEDULE_TASK'; taskType: string; payload: unknown };
type EngineOk = { ok: true; effects: Effect[] };
type EngineErr = { ok: false; code: string; message: string; type: 'VALIDATION' | 'BUSINESS'; field?: string };
type FeatureResult = EngineOk | EngineErr;
type FeatureHandler = (state: State, command: Command) => FeatureResult;Runtime interprets FeatureResult:
- ok: true → execute effects, commit durable changes, emit completion event
- ok: false → reject command, return error to caller, no state change
Runtime MUST commit durable effects atomically: all durable effects commit, or none commit.
Runtime MUST enrich emitted events with occurredAtIso and correlationId before passing to event bus or external consumers.
Scheduled tasks MUST resolve back into Commands through Runtime. SCHEDULE_TASK does not execute logic directly — Runtime converts it to a Command at the scheduled time.
Engine/Features MUST NOT generate:
- occurredAtIso
- persistent IDs (entity IDs, event IDs, task IDs)
- correlationId Runtime MUST generate them, unless explicitly provided by command as part of the command contract.
Every write command MUST include:
- idempotencyKey: string Runtime MUST:
- reject duplicates
- enforce optimistic concurrency via version Engine MUST be unaware.
If a change:
- modifies engine core loop
- introduces IO/time/random/async into engine/features
- changes composition model
- violates any lock Then STOP and PROPOSE only. Do not implement.
GATE 1 - Purity Feature layer contains none of: Date, Math.random, crypto, uuid, async, await, setTimeout
GATE 2 - Serialization State contains none of: Map, Set, Date, Function, class instances State uses Record<string, T>
GATE 3 - Runtime ownership Persistent IDs and occurredAtIso/correlationId generated only in Runtime (unless explicitly provided by command as part of the command contract) All IO only in Runtime
GATE 4 - Write commands Every write command includes: idempotencyKey + occurredAtIso + actorId
GATE 5 - FeatureResult Every Feature function returns FeatureResult No Feature throws exceptions No Feature returns plain Effect[] directly
GATE 6 - Feature isolation No Feature reads or writes another Feature's slice directly Any read isolation exception is documented in ARCHITECTURE.md Cross-feature side effects expressed as Effects only
If any gate fails: do not return code. Fix first.