chore: close wasm status contract work

This commit is contained in:
wangdequan
2026-07-08 09:20:47 -04:00
parent 97732ceb0b
commit e69333972c
69 changed files with 20435 additions and 495 deletions

View File

@@ -21,6 +21,13 @@ const lineExecutionComparison = compareLineExecutionTrace(nativeEvidence, webEvi
const axisValuesByLineComparison = compareAxisValuesByLine(nativeEvidence, webEvidence);
const gcodeExecutionProcessComparison = compareGcodeExecutionProcess(nativeEvidence, webEvidence);
const strictComparison = compareStrictEvidence(nativeEvidence, webEvidence);
const functionalChecks = compareFunctionalEvidence(nativeEvidence, webEvidence, {
pathComparison,
lineExecutionComparison,
axisValuesByLineComparison,
gcodeExecutionProcessComparison,
strictComparison,
});
const checks = [
check("profile", "native axis mask is XYZBC", nativeEvidence.coverage?.axisProfile === true, {
@@ -204,26 +211,44 @@ const checks = [
];
const failed = checks.filter((item) => item.status !== "pass");
const functionalFailed = functionalChecks.filter((item) => item.status !== "pass");
const blockers = [
...(nativeEvidence.status === "blocked" ? nativeEvidence.blocker ? [nativeEvidence.blocker] : ["native-blocked"] : []),
...(webEvidence.blockers || []).map((blocker) => blocker.id),
];
const surfaceSummary = {
checkCount: checks.length,
passCount: checks.length - failed.length,
failCount: failed.length,
legacyComparePassCount: checks.length - failed.length,
legacyCompareFailCount: failed.length,
blockers,
nativeStatus: nativeEvidence.status,
webStatus: webEvidence.status,
};
const functionalSummary = {
status: functionalFailed.length === 0 ? "pass" : "fail",
checkCount: functionalChecks.length,
passCount: functionalChecks.length - functionalFailed.length,
failCount: functionalFailed.length,
requiredImprovements: functionalFailed.map((item) => ({
category: item.category,
requirement: item.requirement,
evidence: item.evidence,
})),
};
const report = {
apiName: "xyzbc-trt-native-web-evidence-comparison",
status: failed.length === 0 ? "pass" : "fail",
status: failed.length === 0 && functionalFailed.length === 0 ? "pass" : "fail",
comparedAt: new Date().toISOString(),
nativePath,
webPath,
summary: {
checkCount: checks.length,
passCount: checks.length - failed.length,
failCount: failed.length,
blockers,
nativeStatus: nativeEvidence.status,
webStatus: webEvidence.status,
},
summary: surfaceSummary,
surfaceSummary,
functionalSummary,
checks,
functionalChecks,
pathComparison,
lineExecutionComparison,
axisValuesByLineComparison,
@@ -236,11 +261,14 @@ const report = {
uiBehaviorComparison: strictComparison.axisUiBehaviorComparison,
visualComparison: strictComparison.visualComparison,
strictComparison,
requiredImprovements: failed.map((item) => ({
category: item.category,
requirement: item.requirement,
evidence: item.evidence,
})),
requiredImprovements: [
...failed.map((item) => ({
category: item.category,
requirement: item.requirement,
evidence: item.evidence,
})),
...functionalSummary.requiredImprovements,
],
semanticBoundary: "native_linuxcnc_vs_web_opfs_wasm_xyzbc_trt_evidence_comparison",
};
@@ -445,6 +473,152 @@ function statusObject(passed, evidence = {}) {
};
}
function compareFunctionalEvidence(nativeEvidence, webEvidence, {
pathComparison,
lineExecutionComparison,
axisValuesByLineComparison,
gcodeExecutionProcessComparison,
strictComparison,
}) {
const nativeErrors = errorPathIds(nativeEvidence);
const webErrors = errorPathIds(webEvidence);
const requiredIllegalPaths = [
"run-while-estop",
"run-before-homed",
"wrong-mode",
"missing-file",
"bad-switchkins-type",
"remap-stop",
];
const taskPolicy = webEvidence.taskHalEquivalence?.taskPolicy
|| webEvidence.nativeStateFlowReview?.buttonInterlocks
|| {};
const webExecution = webEvidence.taskHalEquivalence?.taskHal || {};
const webBasicSim = webEvidence.basicSimEquivalent || webEvidence.taskHalEquivalence?.basicSimEquivalent || {};
const semanticPath = pathComparison.semanticExecutionVsSemanticExecution || {};
const runtimeReady = strictComparison.runtimeExecutionComparison?.status === "pass";
const taskHalReady = strictComparison.taskHalFullStateComparison?.status === "pass";
const sourceUiReady = strictComparison.axisUiBehaviorComparison?.status === "pass";
const errorReady = strictComparison.errorPathComparison?.status === "pass";
return [
check("functional", "cppTaskStateMachineParity", taskHalReady
&& webEvidence.taskHalEquivalence?.ready === true
&& webEvidence.nativeStateFlowReview?.ready === true
&& ["estop", "estop-reset", "on"].includes(String(taskPolicy.taskState || ""))
&& ["manual", "auto", "mdi"].includes(String(taskPolicy.taskMode || ""))
&& ["idle", "reading", "paused", "waiting"].includes(String(taskPolicy.interpState || "")), {
linuxCncRules: ["emcTaskSetState", "determineState", "EMC_STAT.task"],
nativeReady: nativeEvidence.taskHalFullState?.ready,
webReady: webEvidence.taskHalFullState?.ready,
taskPolicy,
}),
check("functional", "cppModeGateParity", sourceUiReady
&& errorReady
&& nativeErrors.has("wrong-mode")
&& webErrors.has("wrong-mode")
&& taskPolicy.canExecuteMdi === false
&& taskPolicy.canRunAuto === false, {
linuxCncRules: ["emcTaskSetMode", "AUTO non-idle/manual gate", "AXIS manual_ok/mdi gate"],
nativeWrongModeRepresented: nativeErrors.has("wrong-mode"),
webWrongModeRepresented: webErrors.has("wrong-mode"),
taskPolicy,
}),
check("functional", "cppHomingParity", taskHalReady
&& webBasicSim.ready === true
&& webBasicSim.homing?.allConfiguredAxesHomed === true
&& Array.isArray(nativeEvidence.taskStateFlow?.states)
&& nativeEvidence.taskStateFlow.states.some((state) => Array.isArray(state.homed)), {
linuxCncRules: ["EMC_JOINT_HOME", "EMCMOT_JOINT_HOME", "homing.c HOME_START/HOME_FINISHED"],
nativeTaskStateFlowReady: nativeEvidence.taskStateFlow?.ready,
webHoming: webBasicSim.homing,
}),
check("functional", "cppRunGateParity", taskHalReady
&& errorReady
&& nativeErrors.has("run-while-estop")
&& webErrors.has("run-while-estop")
&& nativeErrors.has("run-before-homed")
&& webErrors.has("run-before-homed")
&& webExecution.completed === true
&& webExecution.eventCount > 0
&& pathComparison.executionVsExecution.comparable === true, {
linuxCncRules: ["EMC_TASK_PLAN_RUN", "all_homed", "program open", "motion plan loaded"],
nativeErrorPaths: [...nativeErrors],
webErrorPaths: [...webErrors],
webExecution,
executionPath: {
nativeSampleCount: pathComparison.executionVsExecution.nativeSampleCount,
webSampleCount: pathComparison.executionVsExecution.webSampleCount,
},
}),
check("functional", "cppPauseResumeParity", taskHalReady
&& webExecution.eventCount > 0
&& typeof taskPolicy.canPause === "boolean"
&& typeof taskPolicy.canResume === "boolean"
&& semanticPath.status === "pass"
&& semanticPath.machineStateMismatchCount === 0, {
linuxCncRules: ["EMC_TASK_PLAN_PAUSE", "EMC_TASK_PLAN_RESUME", "EMCMOT_PAUSE", "EMCMOT_RESUME"],
taskPolicy: {
canPause: taskPolicy.canPause,
canResume: taskPolicy.canResume,
interpState: taskPolicy.interpState,
},
semanticExecutionMachineStateMismatchCount: semanticPath.machineStateMismatchCount,
}),
check("functional", "cppStepParity", taskHalReady
&& typeof taskPolicy.canRunAuto === "boolean"
&& lineExecutionComparison.status === "pass"
&& axisValuesByLineComparison.status === "pass"
&& gcodeExecutionProcessComparison.status === "pass"
&& gcodeExecutionProcessComparison.nativeExecutionStepCount > 0
&& gcodeExecutionProcessComparison.webExecutionStepCount > 0, {
linuxCncRules: ["EMC_TASK_PLAN_STEP", "EMCMOT_STEP", "motion id/current line progression"],
lineExecution: {
nativeTraceCount: lineExecutionComparison.nativeTraceCount,
webTraceCount: lineExecutionComparison.webTraceCount,
},
gcodeExecution: {
nativeExecutionStepCount: gcodeExecutionProcessComparison.nativeExecutionStepCount,
webExecutionStepCount: gcodeExecutionProcessComparison.webExecutionStepCount,
},
}),
check("functional", "illegalCommandParity", errorReady
&& requiredIllegalPaths.every((id) => nativeErrors.has(id) && webErrors.has(id))
&& strictComparison.limitInterlocksComparison?.status === "pass", {
linuxCncRules: ["runtime command rejection", "UI policy gate consistency", "operator error parity"],
requiredIllegalPaths,
nativeErrorPaths: [...nativeErrors],
webErrorPaths: [...webErrors],
limitInterlocksStatus: strictComparison.limitInterlocksComparison?.status,
}),
check("functional", "realProgramExecutionParity", runtimeReady
&& pathComparison.semanticExecutionVsSemanticExecution.status === "pass"
&& lineExecutionComparison.status === "pass"
&& axisValuesByLineComparison.status === "pass"
&& gcodeExecutionProcessComparison.status === "pass", {
linuxCncRules: ["real G-code line/currentLine/motion/path/status parity"],
runtimeExecutionStatus: strictComparison.runtimeExecutionComparison?.status,
semanticExecution: {
nativeSampleCount: semanticPath.nativeSampleCount,
webSampleCount: semanticPath.webSampleCount,
maxTcpErrorMm: semanticPath.maxTcpErrorMm,
maxJointError: semanticPath.maxJointError,
maxToolAxisAngleDeg: semanticPath.maxToolAxisAngleDeg,
},
lineExecutionStatus: lineExecutionComparison.status,
axisValuesStatus: axisValuesByLineComparison.status,
gcodeExecutionStatus: gcodeExecutionProcessComparison.status,
}),
];
}
function errorPathIds(evidence) {
return new Set((evidence.errorPathParity?.paths || [])
.filter((item) => item?.nativeExpected !== false && item?.webRepresented !== false)
.map((item) => item.id)
.filter(Boolean));
}
function comparePathEvidence(nativeEvidence, webEvidence) {
const samplePeriodMs = 50;
return {