import { ReplayTimeline, fnv1a64 } from "./replay.mjs"; import { capabilities, validateLimit } from "./capabilities.mjs"; import { mapCoreError } from "./error-map.mjs"; import { createCheckpoint, recoverSimulation } from "../workspace/recovery.mjs"; import { preflightConfiguration } from "../workspace/configuration.mjs"; import { ConfigurationStartupStateMachine } from "../workspace/configuration.mjs"; import { preflightHalConfiguration } from "../workspace/hal-configuration.mjs"; import { DEVICE_COMMANDS, VirtualDevices } from "./virtual-devices.mjs"; import { PythonBridge } from "./python-bridge.mjs"; import { ProgramRunner } from "./program-runner.mjs"; import { SimTask } from "./sim-task.mjs"; import { SimScheduler, SCHEDULER_PHASES } from "./sim-scheduler.mjs"; import { OperationLedger } from "./operation-ledger.mjs"; import { MotionState } from "./motion-state.mjs"; import { PlcRuntime } from "./plc-runtime.mjs"; import { HalRuntime } from "./hal-runtime.mjs"; import { DeviceIoRuntime } from "./device-io.mjs"; import { IoAckTracker } from "./io-ack.mjs"; import { PythonCallbacks } from "./python-callbacks.mjs"; import { createTrace, validateTrace } from "./trace-export.mjs"; import { ConfigurationBatchRuntime } from "../workspace/configuration-batch.mjs"; import { AuthoritativeRuntime } from "./authoritative-runtime.mjs"; const PROTOCOL_SCHEMA = 1; const CONTEXT_ID = "linuxcnc-2.10.0-pre0-wasm-m1-py-c1"; const OPERATION_KINDS = new Set([ "SESSION_ATTACH", "LOAD_WORKSPACE", "SIM_STEP", "DESTROY", "CHECKPOINT", "RECOVER", "ABORT", "COMMAND", "START", "STOP", "RESET", "PROGRAM_LOAD", "PROGRAM_RUN", "PROGRAM_PAUSE", "PROGRAM_RESUME", "PROGRAM_ABORT", "PROGRAM_RESTART", "JOG_START", "JOG_STOP", "HOME", "SET_MODE", "SET_OVERRIDE", "SPINDLE_COMMAND", "TOOL_PREPARE", "TOOL_CHANGED", "TOOL_PREPARED", "TOOL_CHANGE", "TOOL_ABORT", "TOOL_FAULT", "TOOL_CLEAR_FAULT", "SPINDLE_FAULT", "SPINDLE_INHIBIT", "SPINDLE_ORIENT", "SPINDLE_ORIENTED", "IO_STEP", "IO_RECOVER", "PROBE_CONFIG", "LIMIT_SET", "ESTOP", "HAL_COMMAND", "HAL_SET", "ENCODER_SET", "COOLANT_COMMAND", "COOLANT_FAULT", "DOOR_SET", "INTERLOCK_SET", "INTERLOCK_RESET", "DEVICE_ESTOP", "DEVICE_ACK_ISSUE", "DEVICE_ACK", "DEVICE_ACK_ABORT", "CONFIGURATION_BATCH", "PYTHON_IMPORT", "PYTHON_CALL", "PYTHON_CAPABILITY", "PROGRAM_STEP", "PROGRAM_SEEK", "MDI_EXECUTE", "PLC_CONFIG", "PLC_SET", "PLC_TRIGGER", "FOLLOWING_ERROR", "IO_COMMAND", "IO_ACK", "IO_TIMEOUT", "REMAP_REGISTER", "REMAP_CALL", "VCP_REGISTER", "VCP_UPDATE", "FILTER_EXEC", ]); function text(value) { return typeof value === "string" && value.length > 0 ? value : null; } function call(core, name, ...args) { if (args.some((value) => typeof value === "string") && typeof core.ccall === "function") { return core.ccall(name, "number", args.map((value) => typeof value === "string" ? "string" : "number"), args); } const direct = core[`_${name}`] ?? core[name]; if (typeof direct === "function") return direct(...args); if (typeof core.cwrap === "function") { const wrapped = core.cwrap(name, "number", args.map((value) => typeof value === "string" ? "string" : "number")); return wrapped(...args); } throw new Error(`missing core export: ${name}`); } function appendCoreEvent(core, seq, tick, kind, payload) { if (typeof core.ccall !== "function") return 0; const bytes = new TextEncoder().encode(canonicalPayload(payload)); return core.ccall("sim_event_append", "number", ["number", "number", "string", "array", "number"], [seq, tick, kind, bytes, bytes.length]); } function canonicalPayload(value) { if (value === null || typeof value !== "object") return JSON.stringify(value); if (Array.isArray(value)) return `[${value.map(canonicalPayload).join(",")}]`; return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalPayload(value[key])}`).join(",")}}`; } export class SimSession { constructor(core, { contextId = CONTEXT_ID, sessionId = "" } = {}) { this.core = core; this.contextId = contextId; this.sessionId = sessionId; this.tick = 0; this.created = false; this.timeline = new ReplayTimeline(); this.operations = new Map(); this.ledger = new OperationLedger(); this.devices = new VirtualDevices(); this.motion = new MotionState(); this.plc = new PlcRuntime(); this.hal = new HalRuntime(); this.deviceIo = new DeviceIoRuntime(); this.configurationBatch = new ConfigurationBatchRuntime({ context_id: contextId }); this.ioAck = new IoAckTracker(); this.callbacks = new PythonCallbacks(); this.python = new PythonBridge(); this.program = new ProgramRunner(core); this.authoritative = new AuthoritativeRuntime(); this.task = new SimTask(core, { contextId, sessionId: sessionId || null }); this.scheduler = new SimScheduler(core); this.configurationState = null; this.halState = null; call(core, "sim_protocol_reset"); if (typeof core.ccall === "function") core.ccall("sim_event_reset", null, [], []); } envelope(kind, input, payload, tick = this.tick) { return { schema_version: PROTOCOL_SCHEMA, kind, context_id: this.contextId, session_id: this.sessionId, seq: input.seq, ...(text(input.operation_id) ? { operation_id: input.operation_id } : {}), simulation_tick: tick, payload, }; } error(input, code, messageKey, retryable = false) { return this.envelope("ERROR", input, { status: "error", code, message_key: messageKey, retryable, operation_id: input.operation_id ?? null, simulation_tick: this.tick, }); } coreError(input, result, source) { const mapped = mapCoreError(result, { operation_id: input.operation_id, simulation_tick: this.tick, source }); return this.envelope("ERROR", input, mapped); } operationState(input) { if (!text(input.operation_id) || !OPERATION_KINDS.has(input.kind)) return null; return this.operations.get(input.operation_id) ?? null; } stateForCheckpoint() { const state = { context_id: this.contextId, session_id: this.sessionId, tick: this.tick, created: this.created, protocol_seq: this.timeline.events.cursor, devices: this.devices.export(), motion: this.motion.export(), plc: this.plc.export(), hal_runtime: this.hal.export(), device_io: this.deviceIo.export(), configuration_batch: this.configurationBatch.export(), io_ack: this.ioAck.export(), callbacks: this.callbacks.export(), configuration: this.configurationState, hal: this.halState, python: this.python.exportState(), task: this.task.export(), scheduler: this.scheduler.export(), authoritative: this.authoritative.export(), ledger: this.ledger.export(), }; if (this.program.loaded) state.program = this.program.exportState(); return state; } workspacePackageState() { const value = { context_id: this.contextId, session_id: this.sessionId, configuration: this.configurationState, hal: this.halState, devices: this.devices.export(), motion: this.motion.export(), plc: this.plc.export(), hal_runtime: this.hal.export(), device_io: this.deviceIo.export(), configuration_batch: this.configurationBatch.export(), io_ack: this.ioAck.export(), callbacks: this.callbacks.export(), python: this.python.exportState(), tick: this.tick, event_cursor: this.timeline.events.cursor, task: this.task.export(), scheduler: this.scheduler.export(), authoritative: this.authoritative.export(), }; if (this.program.loaded) value.program = this.program.exportState(); return { ...value, state_hash: fnv1a64(value) }; } createCheckpoint() { const latest = this.timeline.snapshots.latest(); if (!latest || latest.seq !== this.timeline.events.cursor || latest.tick !== this.timeline.events.tick) { this.timeline.checkpoint( this.timeline.events.cursor, this.timeline.events.tick, this.stateForCheckpoint(), latest?.snapshot_id ?? null, ); } return createCheckpoint({ contextId: this.contextId, timeline: this.timeline, state: this.stateForCheckpoint(), operations: [...this.operations.values()], }); } exportTrace() { const latest = this.timeline.snapshots.latest(); if (!latest || latest.seq !== this.timeline.events.cursor || latest.tick !== this.timeline.events.tick) { this.timeline.checkpoint(this.timeline.events.cursor, this.timeline.events.tick, this.stateForCheckpoint(), latest?.snapshot_id ?? null); } return createTrace({ contextId: this.contextId, timeline: this.timeline, state: this.stateForCheckpoint(), task: this.task.export(), tick: this.tick }); } importTrace(trace) { const validated = validateTrace(trace, { contextId: this.contextId }); this.timeline = validated.timeline; this.created = Boolean(trace.state?.created); if (trace.state?.ledger?.entries) this.ledger = new OperationLedger(trace.state.ledger.entries); if (trace.state?.task) this.task.restore(trace.state.task); if (trace.state?.scheduler) this.scheduler.restore(trace.state.scheduler); if (trace.state?.authoritative) this.authoritative.restore(trace.state.authoritative); if (trace.state?.motion) this.motion.restore(trace.state.motion); if (trace.state?.plc) this.plc.restore(trace.state.plc); if (trace.state?.hal_runtime) this.hal.restore(trace.state.hal_runtime); if (trace.state?.device_io) this.deviceIo.restore(trace.state.device_io); if (trace.state?.configuration_batch) this.configurationBatch.restore(trace.state.configuration_batch); if (trace.state?.io_ack) this.ioAck.restore(trace.state.io_ack); if (trace.state?.callbacks) this.callbacks.restore(trace.state.callbacks); if (trace.state?.python) this.python.restoreState(trace.state.python); if (trace.state?.devices) this.devices = new VirtualDevices({ state: trace.state.devices }); this.tick = trace.tick; return { status: "verified", trace_hash: trace.trace_hash, state_hash: fnv1a64(trace.state), seq: trace.seq, tick: trace.tick }; } restoreCheckpoint(checkpoint, events = null, reconcile = undefined) { const replayDevices = new VirtualDevices({ state: checkpoint?.state?.devices }); const replayMotion = new MotionState(); if (checkpoint?.state?.motion) replayMotion.restore(checkpoint.state.motion); const replayPlc = new PlcRuntime(); if (checkpoint?.state?.plc) replayPlc.restore(checkpoint.state.plc); const replayHal = new HalRuntime(); if (checkpoint?.state?.hal_runtime) replayHal.restore(checkpoint.state.hal_runtime); const replayDeviceIo = new DeviceIoRuntime(); if (checkpoint?.state?.device_io) replayDeviceIo.restore(checkpoint.state.device_io); const replayConfigurationBatch = new ConfigurationBatchRuntime({ context_id: this.contextId }); if (checkpoint?.state?.configuration_batch) replayConfigurationBatch.restore(checkpoint.state.configuration_batch); const replayIoAck = new IoAckTracker(); if (checkpoint?.state?.io_ack) replayIoAck.restore(checkpoint.state.io_ack); const replayCallbacks = new PythonCallbacks(); if (checkpoint?.state?.callbacks) replayCallbacks.restore(checkpoint.state.callbacks); const replayProgram = new ProgramRunner(this.core); if (checkpoint?.state?.program) replayProgram.restoreState(checkpoint.state.program); const replayPython = new PythonBridge(); if (checkpoint?.state?.python) replayPython.restoreState(checkpoint.state.python); const replayAuthoritative = new AuthoritativeRuntime(); if (checkpoint?.state?.authoritative) replayAuthoritative.restore(checkpoint.state.authoritative); const result = recoverSimulation({ checkpoint, contextId: this.contextId, events, reconcile, apply: (state, event) => { if (DEVICE_COMMANDS.has(event.kind)) replayDevices.applyEvent(event.kind, event.payload); if (event.kind === "HOME") replayMotion.home(event.payload?.axis ?? null); if (event.kind === "JOG_START") replayMotion.startJog(event.payload); if (event.kind === "JOG_STOP") replayMotion.stopJog(); if (event.kind === "SET_OVERRIDE") replayMotion.setOverride(event.payload?.feed ?? event.payload?.feed_override, event.payload?.spindle ?? event.payload?.spindle_override); if (event.kind === "LIMIT_SET") replayMotion.setLimit(event.payload?.axis, event.payload?.active === true); if (event.kind === "ESTOP") replayMotion.estop(event.payload?.active === true); if (event.kind === "ESTOP") replayDeviceIo.estop(event.payload?.active === true); if (event.kind === "IO_RECOVER") replayDeviceIo.interlockReset(); if (event.kind === "SIM_STEP") replayMotion.step(event.tick); if (event.kind === "SIM_STEP") replayAuthoritative.step(event.tick); if (event.kind === "PROGRAM_LOAD") replayProgram.load(event.payload?.source ?? event.payload?.text ?? event.payload?.program_source, event.payload?.path ?? null); if (event.kind === "PROGRAM_RUN") replayProgram.start(); if (event.kind === "PROGRAM_PAUSE") replayProgram.pause(); if (event.kind === "PROGRAM_RESUME") replayProgram.resume(); if (event.kind === "PROGRAM_ABORT") replayProgram.abort(); if (event.kind === "PROGRAM_RESTART") replayProgram.restart(); if (event.kind === "SIM_STEP" && replayProgram.loaded) { if (replayProgram.status === "paused" && state.task?.program_status === "running") replayProgram.resume(); replayProgram.tick(Number.isSafeInteger(event.payload?.cycles) ? event.payload.cycles : 1); replayAuthoritative.syncProgram(replayProgram.snapshot()); } if (event.kind === "PLC_CONFIG") replayPlc.configure(event.payload); if (event.kind === "PLC_SET") replayPlc.setRegister(event.payload?.register, event.payload?.value); if (event.kind === "PLC_TRIGGER") replayPlc.trigger(); if (event.kind === "SIM_STEP") for (let replayTick = replayPlc.state.tick + 1; replayTick <= event.tick; replayTick += 1) replayPlc.scan(replayTick); if (event.kind === "HAL_COMMAND" && event.payload?.action === "configure") replayHal.configure(event.payload); if (event.kind === "HAL_COMMAND" && event.payload?.action === "thread") replayHal.registerThread(event.payload?.name, event.payload?.period_ticks); if (event.kind === "HAL_COMMAND" && event.payload?.action === "component") replayHal.registerComponent(event.payload?.instance, event.payload?.type, event.payload?.thread); if (event.kind === "HAL_COMMAND" && event.payload?.action === "connect") replayHal.connect(event.payload?.source, event.payload?.target); if (event.kind === "HAL_COMMAND" && event.payload?.action === "failure") replayHal.setFailure(event.payload?.instance, event.payload?.failed === true); if (event.kind === "HAL_SET" && event.payload?.target === "pin") replayHal.setPin(event.payload?.name, event.payload?.value, event.payload?.type); if (event.kind === "HAL_SET" && event.payload?.target === "param") replayHal.setParam(event.payload?.name, event.payload?.value, event.payload?.type); if (event.kind === "SIM_STEP") replayHal.step(event.tick); if (event.kind === "ENCODER_SET") replayDeviceIo.encoderSet(event.payload?.channel, event.payload); if (event.kind === "COOLANT_COMMAND") replayDeviceIo.coolantCommand(event.payload); if (event.kind === "COOLANT_FAULT") replayDeviceIo.coolantFault(event.payload?.fault === true); if (event.kind === "DOOR_SET") replayDeviceIo.doorSet(event.payload?.open === true); if (event.kind === "INTERLOCK_SET") replayDeviceIo.interlockSet(event.payload?.input_ok === true); if (event.kind === "INTERLOCK_RESET") replayDeviceIo.interlockReset(); if (event.kind === "DEVICE_ESTOP") replayDeviceIo.estop(event.payload?.active === true); if (event.kind === "DEVICE_ACK_ISSUE") replayDeviceIo.issueAck(event.operation_id ?? event.payload?.operation_id, event.payload?.timeout_ticks ?? 10); if (event.kind === "DEVICE_ACK") replayDeviceIo.ack(event.payload?.operation_id); if (event.kind === "DEVICE_ACK_ABORT") replayDeviceIo.abortAck(event.payload?.operation_id); if (event.kind === "SIM_STEP") replayDeviceIo.step(event.tick); if (event.kind === "CONFIGURATION_BATCH") replayConfigurationBatch.load(event.payload?.entries ?? [], { context_id: this.contextId }); if (event.kind === "IO_COMMAND") replayIoAck.issue(event.payload?.operation_id ?? event.payload?.command_id, event.payload?.kind ?? "IO", event.tick, event.payload?.timeout_ticks ?? 10); if (event.kind === "IO_COMMAND") replayDeviceIo.issueAck(event.payload?.operation_id ?? event.payload?.command_id, event.payload?.timeout_ticks ?? 10); if (event.kind === "IO_ACK") replayIoAck.ack(event.payload?.operation_id, event.tick); if (event.kind === "IO_ACK") replayDeviceIo.ack(event.payload?.operation_id); if (event.kind === "IO_TIMEOUT") replayIoAck.step(event.tick); if (event.kind === "SIM_STEP") replayIoAck.step(event.tick); if (event.kind === "IO_TIMEOUT") replayDeviceIo.ackStep(event.tick); if (event.kind === "REMAP_REGISTER") replayCallbacks.registerRemap(event.payload?.name, event.payload); if (event.kind === "VCP_REGISTER") replayCallbacks.registerVcp(event.payload?.name, event.payload?.pins ?? []); if (event.kind === "FILTER_EXEC") replayCallbacks.filter(event.payload?.name, event.payload?.source ?? "", event.payload?.args ?? []); if (event.kind === "REMAP_CALL") replayCallbacks.invoke("remap", event.payload?.name, event.payload?.phase ?? "prolog", event.payload?.args ?? []); if (event.kind === "VCP_UPDATE") replayCallbacks.updateVcp(event.payload?.name, event.payload?.pin, event.payload?.value); if (event.kind === "PYTHON_IMPORT") replayPython.importModule(event.payload?.module); if (event.kind === "PYTHON_CALL") replayPython.invoke(event.payload?.module, event.payload?.symbol, event.payload?.args ?? []); if (event.kind === "PYTHON_CAPABILITY") replayPython.checkCapability(event.payload?.capability); if (event.kind === "SIM_STEP") replayCallbacks.setTick(event.tick); if (event.kind === "SIM_STEP") replayPython.setTick(event.tick); const task = { ...(state.task ?? this.task.export()), seq: event.seq, simulation_tick: event.tick }; delete task.state_hash; if (event.kind === "ESTOP" && event.payload?.active === true) { task.state = "ESTOP"; } else if (event.kind === "IO_RECOVER") { task.state = "READY"; } else if (event.kind === "PROGRAM_PAUSE") { task.state = "PAUSED"; task.program_status = "paused"; } else if (event.kind === "PROGRAM_RESUME" || event.kind === "PROGRAM_RUN") { task.state = "RUNNING"; task.program_status = "running"; } else if (event.kind === "PROGRAM_ABORT" || event.kind === "ABORT") { task.state = "STOPPED"; task.program_status = "aborted"; } if (replayProgram.loaded) { const programStatus = replayProgram.status === "completed" ? "completed" : replayProgram.status === "running" ? "running" : replayProgram.status === "paused" ? "paused" : replayProgram.status === "aborted" ? "aborted" : "loaded"; task.current_line = replayProgram.currentLine; task.program_status = programStatus; if (programStatus === "completed" && task.state === "RUNNING") task.state = "STOPPED"; } const schedulerUnsigned = { schema: "sim_scheduler.v1", budget: state.scheduler?.budget ?? 1000000, phase_trace: [...SCHEDULER_PHASES], tick: event.tick, }; const scheduler = { ...schedulerUnsigned, last_cycles: event.kind === "SIM_STEP" && Number.isSafeInteger(event.payload?.cycles) ? event.payload.cycles : (state.scheduler?.last_cycles ?? 0), state_hash: fnv1a64(schedulerUnsigned), }; return { ...state, tick: event.tick, task: { ...task, state_hash: fnv1a64(task) }, scheduler, devices: replayDevices.export(), motion: replayMotion.export(), authoritative: replayAuthoritative.export(), plc: replayPlc.export(), hal_runtime: replayHal.export(), device_io: replayDeviceIo.export(), configuration_batch: replayConfigurationBatch.export(), io_ack: replayIoAck.export(), callbacks: replayCallbacks.export(), python: replayPython.exportState(), ...(replayProgram.loaded ? { program: replayProgram.exportState() } : {}) }; }, }); if (result.status === "recovered" || result.status === "aborted") { this.tick = result.simulation_tick; if (result.state?.task) this.task.restore(result.state.task); if (result.state?.scheduler) this.scheduler.restore(result.state.scheduler); this.authoritative = new AuthoritativeRuntime(); if (result.state?.authoritative) this.authoritative.restore(result.state.authoritative); this.devices = new VirtualDevices({ state: result.state?.devices ?? checkpoint?.state?.devices }); this.motion = new MotionState(); if (result.state?.motion) this.motion.restore(result.state.motion); this.authoritative.applyMotion(this.motion); this.plc = new PlcRuntime(); if (result.state?.plc) this.plc.restore(result.state.plc); this.hal = new HalRuntime(); if (result.state?.hal_runtime) this.hal.restore(result.state.hal_runtime); this.deviceIo = new DeviceIoRuntime(); if (result.state?.device_io) this.deviceIo.restore(result.state.device_io); this.configurationBatch = new ConfigurationBatchRuntime({ context_id: this.contextId }); if (result.state?.configuration_batch) this.configurationBatch.restore(result.state.configuration_batch); this.ioAck = new IoAckTracker(); if (result.state?.io_ack) this.ioAck.restore(result.state.io_ack); this.callbacks = new PythonCallbacks(); if (result.state?.callbacks) this.callbacks.restore(result.state.callbacks); this.configurationState = result.state?.configuration ?? checkpoint?.state?.configuration ?? null; this.halState = result.state?.hal ?? checkpoint?.state?.hal ?? null; this.python = new PythonBridge(); if (result.state?.python) this.python.restoreState(result.state.python); this.program = new ProgramRunner(this.core); if (result.state?.program) this.program.restoreState(result.state.program); this.timeline = new ReplayTimeline(checkpoint.timeline); if (events?.schema === "replay-timeline.v1") { for (const event of events.events.events.slice(this.timeline.events.cursor)) this.timeline.appendEvent(event.seq, event.tick, event.kind, event.payload, event.payload_hash); } else if (Array.isArray(events)) { for (const event of events) this.timeline.appendEvent(event.seq, event.tick, event.kind, event.payload, event.payload_hash); } this.operations = new Map(result.operations.map((operation) => [operation.operation_id, operation])); this.ledger = new OperationLedger(); for (const operation of result.operations) { const entry = { ...operation, phase: operation.phase ?? (operation.status === "verified" ? "committed" : operation.status), side_effect_count: operation.side_effect_count ?? (operation.status === "verified" ? 1 : 0) }; try { this.ledger.importEntry(entry); } catch { /* legacy checkpoint entries remain in operations */ } } } return result; } validateEnvelope(input) { if (!input || typeof input !== "object") return ["protocol_argument", "invalid_envelope"]; if (input.schema_version !== PROTOCOL_SCHEMA) return ["protocol_schema", "unsupported_schema"]; if (input.context_id !== this.contextId) return ["protocol_context", "context_mismatch"]; if (!text(input.kind) || !Number.isSafeInteger(input.seq) || input.seq <= 0) return ["protocol_argument", "invalid_sequence_or_kind"]; if (this.sessionId && input.session_id !== this.sessionId) return ["protocol_session", "session_mismatch"]; if (!this.sessionId && text(input.session_id)) { this.sessionId = input.session_id; this.task.bindSession(this.sessionId); } return null; } accept(input) { const invalid = this.validateEnvelope(input); if (invalid) return this.error(input ?? {}, invalid[0], invalid[1]); const result = call(this.core, "sim_protocol_accept", input.schema_version, input.seq, input.kind, input.operation_id ?? "", input.simulation_tick ?? this.tick); if (result !== 0) return this.coreError(input, result, "sim_protocol_accept"); let ledgerPreparation; try { ledgerPreparation = this.ledger.prepare(input); if (ledgerPreparation.replay && ledgerPreparation.entry?.response) { const replayTick = Number.isSafeInteger(input.simulation_tick) && input.simulation_tick >= this.tick ? input.simulation_tick : this.tick; this.timeline.appendEvent(input.seq, replayTick, "OPERATION_REPLAY", { operation_id: input.operation_id, original_seq: ledgerPreparation.entry.seq }); const replayEventResult = appendCoreEvent(this.core, input.seq, replayTick, "OPERATION_REPLAY", { operation_id: input.operation_id, original_seq: ledgerPreparation.entry.seq }); if (replayEventResult !== 0) return this.error(input, "event_log", "core_event_append_failed"); this.tick = replayTick; try { this.task.setCommand(input.seq, replayTick); } catch (error) { return this.error(input, "task_state", String(error?.message ?? error)); } return { ...ledgerPreparation.entry.response, replayed: true, seq: input.seq, ledger: this.ledger.reconcile(input.operation_id) }; } if (ledgerPreparation.entry) this.ledger.execute(input.operation_id); } catch (error) { const ledgerCode = String(error?.message ?? error); try { this.task.setCommand(input.seq, input.simulation_tick ?? this.tick); this.tick = this.task.state.simulation_tick; } catch { /* protocol has already accepted the command; retain ledger error */ } try { this.timeline.appendEvent(input.seq, this.tick, "COMMAND_REJECTED", { code: ledgerCode, operation_id: input.operation_id ?? null }); appendCoreEvent(this.core, input.seq, this.tick, "COMMAND_REJECTED", { code: ledgerCode, operation_id: input.operation_id ?? null }); } catch { /* preserve the original ledger diagnostic */ } return this.error(input, ledgerCode.startsWith("ledger_") ? ledgerCode : "ledger", ledgerCode); } try { this.task.setCommand(input.seq, input.simulation_tick ?? this.tick); this.tick = this.task.state.simulation_tick; } catch (error) { return this.error(input, "task_state", String(error?.message ?? error)); } const existingOperation = this.operationState(input); if (existingOperation?.response) { if (existingOperation.kind !== input.kind) return this.error(input, "recovery_operation_conflict", "operation_id_conflict"); try { const replayTick = Number.isSafeInteger(input.simulation_tick) && input.simulation_tick >= this.tick ? input.simulation_tick : this.tick; this.timeline.appendEvent(input.seq, replayTick, "OPERATION_REPLAY", { operation_id: input.operation_id, original_seq: existingOperation.seq }); const replayEventResult = appendCoreEvent(this.core, input.seq, replayTick, "OPERATION_REPLAY", { operation_id: input.operation_id, original_seq: existingOperation.seq }); if (replayEventResult !== 0) return this.error(input, "event_log", "core_event_append_failed"); this.tick = replayTick; return { ...existingOperation.response, replayed: true, seq: input.seq }; } catch (error) { return this.error(input, "event_log", String(error?.message ?? error)); } } if (text(input.operation_id) && OPERATION_KINDS.has(input.kind)) { this.operations.set(input.operation_id, { operation_id: input.operation_id, status: "executing", seq: input.seq, kind: input.kind, result_hash: null }); } if (Number.isSafeInteger(input.simulation_tick) && input.simulation_tick >= this.tick) this.tick = input.simulation_tick; const eventTick = input.kind === "SIM_STEP" && Number.isSafeInteger(input.payload?.cycles) ? this.tick + input.payload.cycles : this.tick; try { this.timeline.appendEvent(input.seq, eventTick, input.kind, input.payload ?? {}); } catch (error) { if (text(input.operation_id)) this.operations.delete(input.operation_id); return this.error(input, "event_log", String(error?.message ?? error)); } const coreEventResult = appendCoreEvent(this.core, input.seq, eventTick, input.kind, input.payload ?? {}); if (coreEventResult !== 0) { if (text(input.operation_id)) this.operations.delete(input.operation_id); return this.error(input, "event_log", "core_event_append_failed"); } const finish = (response, status = "verified") => { if (text(input.operation_id) && OPERATION_KINDS.has(input.kind)) { const operation = this.operations.get(input.operation_id); if (operation) { operation.status = status; operation.result_hash = fnv1a64(response.payload ?? {}); operation.response = response; } try { this.ledger.verify(input.operation_id, response); this.ledger.commit(input.operation_id, input.seq); } catch (error) { const ledgerCode = String(error?.message ?? error); return this.error(input, ledgerCode.startsWith("ledger_") ? ledgerCode : "ledger", ledgerCode); } } return response; }; const deviceResponse = (kind, payload) => { const result = this.devices.command(kind, payload ?? {}); try { if (kind === "ESTOP" && payload?.active === true) this.task.estop(-904); else if (kind === "IO_RECOVER" && result.status === "verified") this.task.recover(); else if (kind === "TOOL_FAULT" && payload?.fault === true) this.task.fault(-905); } catch (error) { return finish(this.error(input, "task_state", String(error?.message ?? error)), "failed"); } if (kind === "ESTOP") this.deviceIo.estop(payload?.active === true); if (kind === "IO_RECOVER" && result.status === "verified") this.deviceIo.interlockReset(); const responseKind = result.status === "verified" ? "COMMAND_RESULT" : "ERROR"; return finish(this.envelope(responseKind, input, { ...result, command: kind, task: this.task.export(), device_io: this.deviceIo.export(), motion: this.motion.export(), operation_id: input.operation_id ?? null, simulation_tick: this.tick, }), result.status === "verified" ? "verified" : "failed"); }; const deviceIoResponse = (kind, payload = {}) => { let result; if (kind === "ENCODER_SET") result = this.deviceIo.encoderSet(payload.channel, payload); else if (kind === "COOLANT_COMMAND") result = this.deviceIo.coolantCommand(payload); else if (kind === "COOLANT_FAULT") result = this.deviceIo.coolantFault(payload.fault === true); else if (kind === "DOOR_SET") result = this.deviceIo.doorSet(payload.open === true); else if (kind === "INTERLOCK_SET") result = this.deviceIo.interlockSet(payload.input_ok === true); else if (kind === "INTERLOCK_RESET") result = this.deviceIo.interlockReset(); else if (kind === "DEVICE_ESTOP") result = this.deviceIo.estop(payload.active === true); else if (kind === "DEVICE_ACK_ISSUE") result = this.deviceIo.issueAck(input.operation_id ?? payload.operation_id, payload.timeout_ticks ?? 10); else if (kind === "DEVICE_ACK_ABORT") result = this.deviceIo.abortAck(payload.operation_id); else if (kind === "DEVICE_ACK") result = this.deviceIo.ack(payload.operation_id); else result = this.deviceIo.fail("device_io_command_unsupported"); const responseKind = result.status === "verified" ? "COMMAND_RESULT" : "ERROR"; return finish(this.envelope(responseKind, input, { ...result, command: kind, device_io: this.deviceIo.export(), task: this.task.export(), operation_id: input.operation_id ?? null }), result.status === "verified" ? "verified" : "failed"); }; switch (input.kind) { case "HELLO": return finish(this.envelope("CAPABILITIES", input, capabilities(this.contextId)), "verified"); case "SESSION_ATTACH": if (!this.created) { const createResult = call(this.core, "sim_create", 0, 0); if (createResult !== 0) return finish(this.coreError(input, createResult, "sim_create"), "failed"); this.created = true; } try { this.task.transition("READY"); } catch (error) { return finish(this.error(input, "task_state", String(error?.message ?? error)), "failed"); } return finish(this.envelope("SESSION_READY", input, { state_hash: this.task.hash(), task: this.task.export(), subscriptions: [] }), "verified"); case "LOAD_WORKSPACE": { const rootPath = input.payload?.root_path; if (!text(rootPath) || !rootPath.startsWith("/") || rootPath.includes("..")) return finish(this.error(input, "workspace_path", "invalid_workspace_path"), "failed"); let startupLoaded = false; const configuration = input.payload?.configuration ?? null; if (configuration) { const startupWorkspace = configuration.workspace ?? configuration.files ?? configuration.workspace_files; if (startupWorkspace) { const startup = new ConfigurationStartupStateMachine({ workspace: startupWorkspace, entrypoint: configuration.entrypoint, variables: configuration.variables ?? {}, maxDepth: configuration.maxDepth ?? 32, core: this.core, coreCreated: this.created, task: this.task, halManifest: configuration.halManifest ?? configuration.hal_manifest ?? configuration.manifest ?? [], }); const startupReport = startup.run(); if (startupReport.status !== "ready") { return finish(this.envelope("ERROR", input, { status: "blocked", code: "configuration_startup", message_key: "configuration.startup_blocked", retryable: false, startup: startupReport, }), "failed"); } this.configurationState = startupReport; this.created = true; startupLoaded = true; } else { const preflight = preflightConfiguration(input.payload.configuration); if (preflight.status !== "ready") { return finish(this.envelope("ERROR", input, { status: "blocked", code: "configuration_preflight", message_key: "configuration.preflight_blocked", retryable: false, preflight, }), "failed"); } this.configurationState = { entrypoint: input.payload.configuration.entrypoint ?? null, status: preflight.status, resource_count: preflight.resource_count, state_hash: fnv1a64(preflight), }; } } if (input.payload?.hal) { const preflight = preflightHalConfiguration(input.payload.hal); if (preflight.status !== "ready") { return finish(this.envelope("ERROR", input, { status: "blocked", code: "hal_preflight", message_key: "hal.preflight_blocked", retryable: false, preflight, }), "failed"); } this.halState = { status: preflight.status, record_count: preflight.record_count, state_hash: fnv1a64(preflight), }; } const configuredKinematics = input.payload?.kinematics ?? configuration?.kinematics?.type ?? null; if (configuredKinematics) { const kinematics = this.authoritative.setKinematics(configuredKinematics); if (kinematics.status === "blocked") return finish(this.envelope("ERROR", input, { status: "blocked", code: kinematics.code, kinematics: this.authoritative.export() }), "failed"); } const loadResult = startupLoaded ? 0 : call(this.core, "sim_load_workspace", rootPath); return loadResult === 0 ? finish(this.envelope("COMMAND_RESULT", input, { status: "verified", command: input.kind, state_hash: this.task.hash(), task: this.task.export(), ...(this.configurationState?.schema === "configuration-startup-runtime.v1" ? { configuration: this.configurationState } : {}), })) : finish(this.coreError(input, loadResult, "sim_load_workspace"), "failed"); } case "SIM_STEP": { const cycles = input.payload?.cycles; const limit = validateLimit("max_tick_step", cycles); if (limit.status !== "accepted") return finish(this.envelope("ERROR", input, { ...limit, operation_id: input.operation_id ?? null, simulation_tick: this.tick, retryable: false }), "failed"); let program_steps = []; try { this.scheduler.step(cycles, { task: () => { program_steps.push(...this.program.tick(1)); }, tp: (nextTick) => { if (this.program.loaded) { const sync = this.authoritative.syncProgram(this.program.snapshot()); if (sync.status === "blocked") throw new Error(sync.code); } const planner = this.authoritative.step(nextTick); if (planner.status === "error") throw new Error(planner.code); }, kinematics: () => { if (!["trivkins", "corexy", "tripod", "lineardelta", "rotarydelta"].includes(this.authoritative.state.kinematics.type)) throw new Error("authoritative_kinematics_unsupported"); }, motion: (nextTick) => { const stepResult = call(this.core, "sim_step", 1); if (stepResult !== 0) throw new Error(`core_sim_step_${stepResult}`); this.tick = nextTick; this.task.setTick(nextTick); const motionState = this.motion.step(nextTick); if (motionState.fault && this.task.state.state === "RUNNING") this.task.fault(-1205); if (this.program.loaded) this.authoritative.applyMotion(this.motion); const halState = this.hal.step(nextTick); if (halState.status === "error") throw new Error(halState.code); const deviceIoState = this.deviceIo.step(nextTick); if (deviceIoState.status === "blocked") throw new Error(deviceIoState.code); const plcState = this.plc.scan(nextTick); if (plcState.status === "error") throw new Error(plcState.code); const ackState = this.ioAck.step(nextTick); if (ackState.status === "error") throw new Error(ackState.code); const callbackClock = this.callbacks.setTick(nextTick); if (callbackClock.status === "blocked") throw new Error(callbackClock.code); this.python.setTick(nextTick); const protocolTick = call(this.core, "sim_protocol_set_tick", nextTick); if (protocolTick !== 0) throw new Error(`protocol_tick_${protocolTick}`); }, }); } catch (error) { return finish(this.error(input, "scheduler", String(error?.message ?? error)), "failed"); } const program = this.program.loaded ? this.program.snapshot() : null; if (program) { const status = program.program_status === "completed" ? "completed" : program.program_status === "running" ? "running" : program.program_status; this.task.setProgram(status, program.line); if (status === "completed" && this.task.state.state === "RUNNING") this.task.transition("STOPPED"); } const snapshotState = { tick: this.tick, cycles, task: this.task.export(), scheduler: this.scheduler.export(), authoritative: this.authoritative.export(), motion: this.motion.export(), plc: this.plc.export(), hal_runtime: this.hal.export(), device_io: this.deviceIo.export(), configuration_batch: this.configurationBatch.export(), io_ack: this.ioAck.export(), callbacks: this.callbacks.export() }; if (program) snapshotState.program = program; const snapshot = this.timeline.checkpoint(input.seq, this.tick, snapshotState, this.timeline.snapshots.latest()?.snapshot_id ?? null); return finish(this.envelope("COMMAND_RESULT", input, { status: "verified", cycles, program_steps, task: this.task.export(), scheduler: this.scheduler.export(), authoritative: this.authoritative.export(), motion: this.motion.export(), plc: this.plc.export(), hal_runtime: this.hal.export(), device_io: this.deviceIo.export(), configuration_batch: this.configurationBatch.export(), io_ack: this.ioAck.export(), callbacks: this.callbacks.export(), ...(program ? { program } : {}), state_hash: snapshot.state_hash, snapshot })); } case "PROGRAM_LOAD": { if (["RUNNING", "PAUSED"].includes(this.task.state.state)) return finish(this.error(input, "task_state", "program_load_while_active"), "failed"); const source = input.payload?.source ?? input.payload?.text ?? input.payload?.program_source; const result = this.program.load(source, input.payload?.path ?? null); if (result.status === "verified") { this.authoritative.reset(); this.task.setProgram("loaded", 0); } return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null, }), result.status === "verified" ? "verified" : "failed"); } case "PROGRAM_RUN": { const result = this.program.start(); if (result.status === "verified") { this.task.setMode("AUTO"); if (this.task.state.state === "STOPPED") this.task.recover(); this.task.transition("RUNNING"); this.task.setProgram("running", this.program.currentLine); } return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null, }), result.status === "verified" ? "verified" : "failed"); } case "PROGRAM_PAUSE": case "PROGRAM_RESUME": case "PROGRAM_ABORT": { const action = input.kind === "PROGRAM_PAUSE" ? "pause" : input.kind === "PROGRAM_RESUME" ? "resume" : "abort"; const result = this.program[action](); if (result.status === "verified") { if (action === "pause") this.task.transition("PAUSED"); else if (action === "resume") this.task.transition("RUNNING"); else { this.authoritative.abort(); this.task.transition("STOPPED"); this.task.setProgram("aborted", this.program.currentLine); } } return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null, }), result.status === "verified" ? "verified" : "failed"); } case "PROGRAM_RESTART": { const result = this.program.restart(); if (result.status === "verified") { if (["ESTOP", "FAULT"].includes(this.task.state.state)) return finish(this.error(input, "task_state", "program_restart_faulted"), "failed"); if (this.task.state.state === "STOPPED") this.task.recover(); this.task.setMode("AUTO"); this.authoritative.reset(); this.task.setProgram("loaded", 0); } return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null, }), result.status === "verified" ? "verified" : "failed"); } case "PROGRAM_STEP": { if (this.task.state.state === "READY") { this.task.setMode("AUTO"); this.task.transition("RUNNING"); } const result = this.program.step(); if (result.status === "verified") { this.task.setProgram(result.program_status === "completed" ? "completed" : "paused", result.line); if (result.program_status === "completed") { if (this.task.state.state === "RUNNING") this.task.transition("STOPPED"); } else if (this.task.state.state === "RUNNING") this.task.transition("PAUSED"); } return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null, }), result.status === "verified" ? "verified" : "failed"); } case "PROGRAM_SEEK": { const result = this.program.seek(input.payload?.line); if (result.status === "verified") this.task.setProgram("paused", result.line); return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null, }), result.status === "verified" ? "verified" : "failed"); } case "MDI_EXECUTE": { if (["RUNNING", "PAUSED"].includes(this.task.state.state)) return finish(this.error(input, "task_state", "mdi_while_program_active"), "failed"); if (this.task.state.state === "STOPPED") this.task.recover(); const result = this.program.executeBlock(input.payload?.block ?? input.payload?.command); if (result.status === "verified") { this.task.setMode("MDI"); this.task.setProgram("loaded", this.program.currentLine); } return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null, }), result.status === "verified" ? "verified" : "failed"); } case "HOME": { const result = this.motion.home(input.payload?.axis ?? null); return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null }), result.status === "verified" ? "verified" : "failed"); } case "JOG_START": case "JOG_STOP": case "SET_OVERRIDE": case "FOLLOWING_ERROR": { let result; if (input.kind === "JOG_START") result = this.motion.startJog(input.payload); else if (input.kind === "JOG_STOP") result = this.motion.stopJog(); else if (input.kind === "SET_OVERRIDE") result = this.motion.setOverride(input.payload?.feed ?? input.payload?.feed_override, input.payload?.spindle ?? input.payload?.spindle_override); else result = this.motion.setFollowingError(input.payload?.value ?? input.payload?.following_error); if (result.status === "error" && result.state?.fault && this.task.state.state === "RUNNING") this.task.fault(-1205); return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null }), result.status === "verified" ? "verified" : "failed"); } case "SPINDLE_COMMAND": case "SPINDLE_FAULT": case "SPINDLE_INHIBIT": case "SPINDLE_ORIENT": case "SPINDLE_ORIENTED": case "IO_STEP": case "TOOL_PREPARE": case "TOOL_PREPARED": case "TOOL_CHANGE": case "TOOL_CHANGED": case "TOOL_ABORT": case "TOOL_FAULT": case "TOOL_CLEAR_FAULT": case "PROBE_CONFIG": case "IO_RECOVER": return deviceResponse(input.kind, input.payload); case "LIMIT_SET": { const result = this.motion.setLimit(input.payload?.axis, input.payload?.active === true); return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null }), result.status === "verified" ? "verified" : "failed"); } case "PLC_CONFIG": case "PLC_SET": case "PLC_TRIGGER": { const result = input.kind === "PLC_CONFIG" ? this.plc.configure(input.payload) : input.kind === "PLC_SET" ? this.plc.setRegister(input.payload?.register, input.payload?.value) : this.plc.trigger(); return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), plc: this.plc.export(), command: input.kind, operation_id: input.operation_id ?? null }), result.status === "verified" ? "verified" : "failed"); } case "CONFIGURATION_BATCH": { const result = this.configurationBatch.load(input.payload?.entries, { context_id: this.contextId }); return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, configuration_batch: this.configurationBatch.export(), task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null }), result.status === "verified" ? "verified" : "failed"); } case "HAL_COMMAND": case "HAL_SET": { const payload = input.payload ?? {}; let result; if (input.kind === "HAL_SET") { result = payload.target === "param" ? this.hal.setParam(payload.name, payload.value, payload.type) : this.hal.setPin(payload.name, payload.value, payload.type); } else if (payload.action === "configure") { result = this.hal.configure(payload); } else if (payload.action === "thread") { result = this.hal.registerThread(payload.name, payload.period_ticks); } else if (payload.action === "component") { result = this.hal.registerComponent(payload.instance ?? payload.name, payload.type, payload.thread ?? "servo-thread"); } else if (payload.action === "connect") { result = this.hal.connect(payload.source, payload.target); } else if (payload.action === "failure") { result = this.hal.setFailure(payload.instance, payload.failed === true); } else if (payload.action === "step") { result = this.hal.step(payload.tick ?? this.tick); } else { result = this.hal.fail("hal_command_unsupported"); } return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, task: this.task.export(), hal_runtime: this.hal.export(), command: input.kind, operation_id: input.operation_id ?? null }), result.status === "verified" ? "verified" : "failed"); } case "ENCODER_SET": case "COOLANT_COMMAND": case "COOLANT_FAULT": case "DOOR_SET": case "INTERLOCK_SET": case "INTERLOCK_RESET": case "DEVICE_ESTOP": case "DEVICE_ACK_ISSUE": case "DEVICE_ACK": case "DEVICE_ACK_ABORT": return deviceIoResponse(input.kind, input.payload); case "IO_COMMAND": case "IO_ACK": case "IO_TIMEOUT": { let result; if (input.kind === "IO_COMMAND") { result = this.ioAck.issue(input.operation_id, input.payload?.kind ?? "IO", this.tick, input.payload?.timeout_ticks ?? 10); if (result.status === "verified") this.deviceIo.issueAck(input.operation_id, input.payload?.timeout_ticks ?? 10); } else if (input.kind === "IO_ACK") { result = this.ioAck.ack(input.payload?.operation_id, this.tick); this.deviceIo.ack(input.payload?.operation_id); } else { const targetTick = this.tick + (input.payload?.ticks ?? 0); result = this.ioAck.step(targetTick); this.deviceIo.ackStep(targetTick); } return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, io_ack: this.ioAck.export(), device_io: this.deviceIo.export(), task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null }), result.status === "verified" ? "verified" : "failed"); } case "REMAP_REGISTER": case "REMAP_CALL": case "VCP_REGISTER": case "VCP_UPDATE": case "FILTER_EXEC": { const result = input.kind === "REMAP_REGISTER" ? this.callbacks.registerRemap(input.payload?.name, input.payload) : input.kind === "REMAP_CALL" ? this.callbacks.invoke("remap", input.payload?.name, input.payload?.phase ?? "prolog", input.payload?.args ?? []) : input.kind === "VCP_REGISTER" ? this.callbacks.registerVcp(input.payload?.name, input.payload?.pins ?? []) : input.kind === "VCP_UPDATE" ? this.callbacks.updateVcp(input.payload?.name, input.payload?.pin, input.payload?.value) : this.callbacks.filter(input.payload?.name, input.payload?.source ?? "", input.payload?.args ?? []); return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, { ...result, callbacks: this.callbacks.export(), task: this.task.export(), command: input.kind, operation_id: input.operation_id ?? null }), result.status === "verified" ? "verified" : "failed"); } case "ESTOP": { const motionResult = this.motion.estop(input.payload?.active === true); const deviceResult = deviceResponse(input.kind, input.payload); if (motionResult.status === "error") return finish(this.envelope("ERROR", input, { ...motionResult, task: this.task.export() }), "failed"); return deviceResult; } case "PYTHON_IMPORT": { const result = this.python.importModule(input.payload?.module); return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, result), result.status === "verified" ? "verified" : "failed"); } case "PYTHON_CALL": { const result = this.python.invoke(input.payload?.module, input.payload?.symbol, input.payload?.args ?? []); return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, result), result.status === "verified" ? "verified" : "failed"); } case "PYTHON_CAPABILITY": { const result = this.python.checkCapability(input.payload?.capability); return finish(this.envelope(result.status === "verified" ? "COMMAND_RESULT" : "ERROR", input, result), result.status === "verified" ? "verified" : "failed"); } case "SNAPSHOT_REQUEST": return finish(this.envelope("STATE_SNAPSHOT", input, { snapshot_schema: 1, tick: this.tick, task: this.task.export(), state_hash: this.task.hash(), snapshot: this.timeline.snapshots.latest() })); case "CHECKPOINT": { try { const operation = text(input.operation_id) ? this.operations.get(input.operation_id) : null; if (operation) operation.status = "verified"; const checkpoint = this.createCheckpoint(); return finish(this.envelope("CHECKPOINT_READY", input, { status: "verified", checkpoint, state_hash: checkpoint.checkpoint_hash })); } catch (error) { return finish(this.error(input, "recovery_checkpoint", String(error?.message ?? error)), "failed"); } } case "RECOVER": { const result = this.restoreCheckpoint(input.payload?.checkpoint, input.payload?.events, input.payload?.reconcile); return finish(this.envelope("RECOVERY_STATUS", input, result), result.status === "blocked" ? "failed" : "verified"); } case "ABORT": { const target = input.payload?.operation_id; const operation = text(target) ? this.operations.get(target) : null; if (operation && operation.status !== "verified") operation.status = "aborted"; let ledgerResult = null; if (text(target)) { try { ledgerResult = this.ledger.abort(target); } catch (error) { ledgerResult = { status: "missing", error: String(error?.message ?? error) }; } } if (this.task.state.state !== "DESTROYED") { try { this.task.transition("STOPPED"); } catch { /* target abort can be bookkeeping-only */ } } return finish(this.envelope("COMMAND_RESULT", input, { status: ledgerResult?.status === "too_late" ? "too_late" : operation ? "aborted" : "verified", operation_id: target ?? null, ledger: ledgerResult })); } case "DESTROY": this.program.destroy(); this.task.destroy(); this.scheduler.destroy(); call(this.core, "sim_destroy"); this.created = false; return finish(this.envelope("COMMAND_RESULT", input, { status: "verified", destroyed: true, replay: this.timeline.export() })); default: return finish(this.envelope("COMMAND_RESULT", input, { status: "verified", command: input.kind })); } } } export { CONTEXT_ID, PROTOCOL_SCHEMA };