Advance simulation parity and 3-axis tutorial coverage

This commit is contained in:
2026-08-23 18:00:56 +08:00
parent 4a11d9692b
commit 938654b19d
107 changed files with 13537 additions and 3565 deletions

View File

@@ -0,0 +1,46 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import createModule from "../../build-wasm/linuxcnc-sim-core.js";
import { compareEndpoints, createEndpoint, endpointHash } from "./endpoint-replay.mjs";
import { loadSimulationCase, toWorkerConfiguration } from "../workspace/sim-case-loader.mjs";
import { SimSession, CONTEXT_ID } from "./sim-session.mjs";
const CASE = "linuxcnc/configs/sim/axis/vismach/3axis-tutorial/3axis-tutorial.ini";
const fetchImpl = async (url) => { try { const body = await readFile(new URL(`../../${String(url).replace(/^\//, "")}`, import.meta.url)); return { ok: true, text: async () => body.toString("utf8") }; } catch { return { ok: false, text: async () => "" }; } };
const bundle = await loadSimulationCase({ path: CASE, fetchImpl });
const wasmBinary = await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url));
async function create(id) {
const core = await createModule({ wasmBinary });
const session = new SimSession(core, { sessionId: id });
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: id };
let seq = 0;
const send = (kind, operationId, payload = {}) => session.accept({ ...base, kind, seq: ++seq, operation_id: operationId, payload });
send("HELLO", "hello"); send("SESSION_ATTACH", "attach");
const loaded = send("LOAD_WORKSPACE", "load", { root_path: "/workspace", configuration: toWorkerConfiguration(bundle) });
assert.equal(loaded.payload.configuration.state, "TASK_READY");
send("PROGRAM_LOAD", "program", { path: "persist.ngc", source: "G21 G90\nG0 X0 Y0 Z0\nG1 X2 Y1 F60\nG1 Z-1\nM2\n" });
send("PROGRAM_RUN", "run");
return { session, send };
}
const continuous = await create("axis3-tutorial-persistence");
const checkpoint = continuous.send("CHECKPOINT", "checkpoint").payload.checkpoint;
continuous.send("SIM_STEP", "step-a", { cycles: 3 });
const continuousEndpoint = createEndpoint({ session: continuous.session });
const recovered = await create("axis3-tutorial-persistence");
const recovery = recovered.session.restoreCheckpoint(checkpoint, continuous.session.timeline.export(), (operation) => operation);
assert.equal(recovery.status, "recovered");
const recoveredEndpoint = createEndpoint({ session: recovered.session });
const parity = compareEndpoints(continuousEndpoint, recoveredEndpoint);
assert.equal(parity.equal, true);
const bad = structuredClone(checkpoint);
bad.state_hash = "fnv1a64:bad";
const blocked = recovered.session.restoreCheckpoint(bad, null, (operation) => operation);
assert.equal(blocked.status, "blocked");
const continuousHash = endpointHash(continuousEndpoint);
const recoveredHash = endpointHash(recoveredEndpoint);
console.log(JSON.stringify({ schema: "axis3-tutorial-persistence.v1", status: "verified", case: CASE, exact_runtime_files: ["3axis-tutorial_mm.var", "tool.tbl", "position_mm.txt"], checkpoint_hash: checkpoint.checkpoint_hash, continuous_hash: continuousHash, recovered_hash: recoveredHash, endpoint_equal: parity.equal, blocked_bad_checkpoint: blocked.status, event_cursor: checkpoint.event_cursor }));