Implement AXIS parity UI and execution baseline

This commit is contained in:
2026-08-23 07:28:37 +08:00
parent 1325504544
commit 06f96f85e5
463 changed files with 84893 additions and 692 deletions

View File

@@ -0,0 +1,74 @@
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 { SimSession, CONTEXT_ID } from "./sim-session.mjs";
const wasmBinary = await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url));
async function runPlan(id, fast) {
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, operation_id, payload = {}) => {
seq += 1;
const response = session.accept({ ...base, kind, seq, operation_id, payload });
assert.notEqual(response.kind, "ERROR", `${id}:${kind}:${response.payload?.code ?? "error"}`);
return response;
};
send("HELLO", "hello");
send("SESSION_ATTACH", "attach");
send("LOAD_WORKSPACE", "workspace", { root_path: "/workspace" });
send("HAL_COMMAND", "thread", { action: "thread", name: "servo-thread", period_ticks: 1 });
send("HAL_COMMAND", "constant", { action: "component", instance: "constant", type: "constant", thread: "servo-thread" });
send("HAL_SET", "constant-value", { target: "param", name: "constant.value", value: 2.5 });
send("ENCODER_SET", "encoder", { channel: 0, speed_rps: 1, ppr: 10, scale: 4, index_enable: true });
send("PROGRAM_LOAD", "program", { source: "G0 X1\nG1 X2\nM2\n", path: "authoritative.ngc" });
send("PROGRAM_RUN", "run");
const steps = [];
if (fast) {
const response = send("SIM_STEP", "fast-step", { cycles: 8 });
steps.push(response);
} else {
for (let index = 0; index < 8; index += 1) steps.push(send("SIM_STEP", `step-${index}`, { cycles: 1 }));
}
const last = steps.at(-1);
assert.equal(last.payload.authoritative.kinematics.type, "trivkins");
assert.equal(last.payload.authoritative.tick, last.payload.task.simulation_tick);
assert.equal(last.payload.authoritative.kinematics.joint_count, 3);
assert.equal(last.payload.scheduler.phase_trace.join(","), "reconcile,task,tp,kinematics,motion,hal_io,callbacks,publish");
assert.equal(last.payload.hal_runtime.components[0].calls, 8);
assert.equal(last.payload.device_io.encoders[0].tick, 8);
assert.equal(last.payload.authoritative.kinematics.pose.x, 2);
const endpoint = createEndpoint({ session });
const checkpoint = session.createCheckpoint();
send("SIM_STEP", "post-checkpoint", { cycles: 1 });
const continuous = createEndpoint({ session });
const recovered = session.restoreCheckpoint(checkpoint, session.timeline.export(), (operation) => operation);
assert.equal(recovered.status, "recovered");
const restored = createEndpoint({ session });
const recoveryParity = compareEndpoints(continuous, restored);
assert.equal(recoveryParity.equal, true, JSON.stringify(recoveryParity));
return { endpoint, checkpoint, recoveryParity, authoritative: last.payload.authoritative, task: last.payload.task, scheduler: last.payload.scheduler };
}
const oneX = await runPlan("authoritative-1x", false);
const fast = await runPlan("authoritative-fast", true);
const modeParity = compareEndpoints(oneX.endpoint, fast.endpoint);
assert.equal(modeParity.equal, true);
assert.equal(oneX.recoveryParity.equal, true);
assert.equal(fast.recoveryParity.equal, true);
console.log(JSON.stringify({
schema: "authoritative-sim-task-s6-sample.v1",
status: "verified",
context_id: CONTEXT_ID,
supported: { kinematics: "trivkins", axes: ["x", "y", "z"], fixed_tick_phases: oneX.scheduler.phase_trace },
parity: { mode: modeParity, one_x_recovery: oneX.recoveryParity, fast_recovery: fast.recoveryParity },
endpoint_hash: endpointHash(oneX.endpoint),
authoritative_hash: oneX.authoritative.state_hash,
task_hash: oneX.task.state_hash,
checkpoint_hash: oneX.checkpoint.checkpoint_hash,
boundaries: ["non-trivkins kinematics remain S6-03+", "full LinuxCNC canonical/native oracle remains explicitly blocked"],
}));