240 lines
7.4 KiB
JavaScript
240 lines
7.4 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
CODE_AGENT_M3_IO_ROUTE,
|
|
codeAgentM3EvidenceContractSummary,
|
|
extractCodeAgentM3Evidence,
|
|
isCodeAgentM3SkillCompletion,
|
|
m3EvidenceRows
|
|
} from "./code-agent-m3-evidence.mjs";
|
|
|
|
test("renders accepted M3 Skill CLI operation/audit/evidence metadata", () => {
|
|
const evidence = extractCodeAgentM3Evidence(m3Message({
|
|
status: "succeeded",
|
|
accepted: true,
|
|
operationId: "op_m3_cli_accepted",
|
|
traceId: "trc_m3_cli_accepted",
|
|
auditId: "aud_m3_cli_accepted_succeeded",
|
|
evidenceId: "evd_m3_cli_accepted_succeeded",
|
|
value: true,
|
|
readbackValue: true
|
|
}));
|
|
|
|
assert.equal(evidence.verdict.key, "accepted");
|
|
assert.equal(evidence.route, CODE_AGENT_M3_IO_ROUTE);
|
|
assert.equal(evidence.target.resourceId, "res_boxsimu_1");
|
|
assert.equal(evidence.target.port, "DO1");
|
|
assert.equal(evidence.target.value, true);
|
|
assert.equal(evidence.readback.resourceId, "res_boxsimu_2");
|
|
assert.equal(evidence.readback.port, "DI1");
|
|
assert.equal(evidence.readback.value, true);
|
|
assert.equal(evidence.ids.operationId, "op_m3_cli_accepted");
|
|
assert.equal(evidence.ids.traceId, "trc_m3_cli_accepted");
|
|
assert.equal(evidence.ids.auditId, "aud_m3_cli_accepted_succeeded");
|
|
assert.equal(evidence.ids.evidenceId, "evd_m3_cli_accepted_succeeded");
|
|
assert.equal(isCodeAgentM3SkillCompletion(m3Message()), true);
|
|
assert.equal(rowValue(evidence, "evidenceId"), "evd_m3_cli_accepted_succeeded");
|
|
});
|
|
|
|
test("renders blocker state from Skill CLI without trusted pass", () => {
|
|
const evidence = extractCodeAgentM3Evidence(m3Message({
|
|
status: "blocked",
|
|
accepted: false,
|
|
operationId: "op_m3_blocked",
|
|
blocker: {
|
|
code: "m3_wiring_missing",
|
|
zh: "hwlab-patch-panel 未确认 active DO1 -> DI1 接线"
|
|
}
|
|
}));
|
|
|
|
assert.equal(evidence.verdict.key, "blocked");
|
|
assert.equal(evidence.verdict.tone, "blocked");
|
|
assert.match(rowValue(evidence, "blocker"), /m3_wiring_missing/u);
|
|
assert.equal(isCodeAgentM3SkillCompletion({ ...m3Message(), status: "failed" }), false);
|
|
});
|
|
|
|
test("shows missing evidenceId as unavailable proof instead of fabricating one", () => {
|
|
const evidence = extractCodeAgentM3Evidence(m3Message({
|
|
status: "succeeded",
|
|
accepted: true,
|
|
evidenceId: null
|
|
}));
|
|
|
|
assert.equal(evidence.verdict.key, "accepted-missing-proof");
|
|
assert.equal(rowValue(evidence, "evidenceId"), "未产生/不可证明");
|
|
assert.equal(row(evidence, "evidenceId").copyable, false);
|
|
});
|
|
|
|
test("classifies DO1 target and DI1 readback mismatch as blocked proof", () => {
|
|
const evidence = extractCodeAgentM3Evidence(m3Message({
|
|
status: "blocked",
|
|
accepted: false,
|
|
operationId: "op_m3_readback_mismatch",
|
|
value: true,
|
|
readbackValue: false,
|
|
blocker: {
|
|
code: "m3_readback_mismatch",
|
|
zh: "DI1 回读值 false 与 DO1 写入值 true 不一致"
|
|
}
|
|
}));
|
|
|
|
assert.equal(evidence.readbackMismatch, true);
|
|
assert.equal(evidence.verdict.key, "readback-mismatch");
|
|
assert.match(rowValue(evidence, "readback"), /res_boxsimu_2:DI1 value=false/u);
|
|
});
|
|
|
|
test("classifies direct gateway/box/patch-panel path as invalid and never trusted", () => {
|
|
const evidence = extractCodeAgentM3Evidence(m3Message({
|
|
status: "succeeded",
|
|
accepted: true,
|
|
operationId: "op_m3_direct_path",
|
|
controlPath: {
|
|
cloudApi: false,
|
|
gatewaySimu: true,
|
|
boxSimu: true,
|
|
patchPanel: true,
|
|
frontendBypass: true
|
|
},
|
|
blocker: {
|
|
code: "direct_hardware_target_blocked",
|
|
zh: "Skill CLI target must be HWLAB cloud-api, not gateway/box/patch-panel."
|
|
}
|
|
}));
|
|
|
|
assert.equal(evidence.directPathInvalid, true);
|
|
assert.equal(evidence.verdict.key, "direct-path-invalid");
|
|
assert.equal(evidence.verdict.tone, "blocked");
|
|
});
|
|
|
|
test("contract summary documents operation/audit/evidence visibility", () => {
|
|
assert.match(codeAgentM3EvidenceContractSummary(), /operationId/u);
|
|
assert.match(codeAgentM3EvidenceContractSummary(), /auditId/u);
|
|
assert.match(codeAgentM3EvidenceContractSummary(), /evidenceId/u);
|
|
assert.match(codeAgentM3EvidenceContractSummary(), /direct gateway\/box\/patch-panel/u);
|
|
});
|
|
|
|
function row(evidence, label) {
|
|
const found = m3EvidenceRows(evidence).find((item) => item.label === label);
|
|
assert.ok(found, `missing row ${label}`);
|
|
return found;
|
|
}
|
|
|
|
function rowValue(evidence, label) {
|
|
return row(evidence, label).value;
|
|
}
|
|
|
|
function m3Message(overrides = {}) {
|
|
const operationId = overrides.operationId ?? "op_m3_cli_accepted";
|
|
const traceId = overrides.traceId ?? "trc_m3_cli_accepted";
|
|
const auditId = Object.hasOwn(overrides, "auditId") ? overrides.auditId : "aud_m3_cli_accepted_succeeded";
|
|
const evidenceId = Object.hasOwn(overrides, "evidenceId") ? overrides.evidenceId : "evd_m3_cli_accepted_succeeded";
|
|
const value = Object.hasOwn(overrides, "value") ? overrides.value : true;
|
|
const readbackValue = Object.hasOwn(overrides, "readbackValue") ? overrides.readbackValue : value;
|
|
const status = overrides.status ?? "succeeded";
|
|
const accepted = Object.hasOwn(overrides, "accepted") ? overrides.accepted : true;
|
|
const toolCall = {
|
|
id: "tool_m3_fixture",
|
|
type: "skill-cli",
|
|
name: "hwlab-agent-runtime.m3-io",
|
|
status: accepted ? "completed" : "blocked",
|
|
route: CODE_AGENT_M3_IO_ROUTE,
|
|
accepted,
|
|
operationId,
|
|
traceId,
|
|
audit: {
|
|
auditId
|
|
},
|
|
evidence: {
|
|
evidenceId,
|
|
status: evidenceId ? "green" : "blocked",
|
|
sourceKind: evidenceId ? "DEV-LIVE" : "BLOCKED"
|
|
},
|
|
command: {
|
|
action: "do.write",
|
|
resourceId: "res_boxsimu_1",
|
|
port: "DO1",
|
|
value
|
|
},
|
|
result: {
|
|
value,
|
|
targetReadback: {
|
|
resourceId: "res_boxsimu_2",
|
|
port: "DI1",
|
|
value: readbackValue
|
|
}
|
|
},
|
|
blocker: overrides.blocker ?? null,
|
|
blockers: overrides.blocker ? [overrides.blocker] : [],
|
|
controlPath: overrides.controlPath ?? {
|
|
cloudApi: true,
|
|
gatewaySimu: true,
|
|
boxSimu: true,
|
|
patchPanel: true,
|
|
frontendBypass: false
|
|
},
|
|
safety: {
|
|
cloudApiRouteOnly: true,
|
|
allowedRoute: CODE_AGENT_M3_IO_ROUTE,
|
|
directGatewayCalls: false,
|
|
directBoxCalls: false,
|
|
directPatchPanelCalls: false,
|
|
fallbackUsed: false
|
|
},
|
|
stdout: JSON.stringify({
|
|
route: CODE_AGENT_M3_IO_ROUTE,
|
|
status,
|
|
accepted,
|
|
traceId,
|
|
operationId,
|
|
audit: { auditId },
|
|
evidence: { evidenceId },
|
|
blocker: overrides.blocker ?? null,
|
|
result: {
|
|
value,
|
|
targetReadback: {
|
|
resourceId: "res_boxsimu_2",
|
|
port: "DI1",
|
|
value: readbackValue
|
|
}
|
|
}
|
|
})
|
|
};
|
|
|
|
return {
|
|
status: "completed",
|
|
provider: "hwlab-skill-cli",
|
|
model: "controlled-m3-io",
|
|
backend: "hwlab-cloud-api/hwlab-agent-runtime-skill-cli",
|
|
traceId,
|
|
conversationId: "conv_m3_fixture",
|
|
sessionId: "sess_m3_fixture",
|
|
messageId: "msg_m3_fixture",
|
|
runner: {
|
|
kind: "hwlab-m3-io-skill-cli"
|
|
},
|
|
runnerTrace: {
|
|
runnerKind: "hwlab-m3-io-skill-cli",
|
|
route: CODE_AGENT_M3_IO_ROUTE,
|
|
status,
|
|
accepted,
|
|
operationId,
|
|
traceId
|
|
},
|
|
providerTrace: {
|
|
runnerKind: "hwlab-m3-io-skill-cli",
|
|
skill: "hwlab-agent-runtime.m3-io",
|
|
route: CODE_AGENT_M3_IO_ROUTE,
|
|
status,
|
|
accepted,
|
|
operationId,
|
|
traceId,
|
|
fallbackUsed: false
|
|
},
|
|
toolCalls: [toolCall],
|
|
reply: {
|
|
content: "M3 IO Skill CLI result fixture."
|
|
}
|
|
};
|
|
}
|