195 lines
5.8 KiB
JavaScript
195 lines
5.8 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { after, before, test } from "node:test";
|
|
|
|
import { createServer } from "vite";
|
|
|
|
let server;
|
|
let parseE30EngineeringCatalog;
|
|
let parseE30EngineeringDecision;
|
|
let fetchE30EngineeringDecision;
|
|
let E30EngineeringContractError;
|
|
|
|
const resultId = `e30-materialization-${"a".repeat(64)}`;
|
|
const generationId = `e30-engineering-generation-${"b".repeat(64)}`;
|
|
const itemId = `e30-review-item-${"c".repeat(64)}`;
|
|
|
|
function generation(overrides = {}) {
|
|
return {
|
|
generation_id: generationId,
|
|
created_at_utc: "2026-07-26T22:01:18.464Z",
|
|
materialization_id: resultId,
|
|
producer: {
|
|
kind: "ai-assisted-engineering-review",
|
|
producer_id: "codex:a3-engineering-review",
|
|
method_id: "camera-lidar-42-sheet-audit/v1",
|
|
review_sheet_identity_sha256: "d".repeat(64),
|
|
claims_human_ground_truth: false,
|
|
},
|
|
summary: {
|
|
item_count: 486,
|
|
reviewed_item_count: 486,
|
|
verdict_distribution: {
|
|
confirmed: 401,
|
|
corrected: 80,
|
|
"insufficient-evidence": 5,
|
|
},
|
|
detector_distribution: { valid: 259, "false-positive": 78 },
|
|
projection_distribution: { aligned: 371, "not-assessable": 115 },
|
|
point_ownership_distribution: { object: 108 },
|
|
human_exception_count: 5,
|
|
mean_confidence: 0.8705,
|
|
},
|
|
cause_distribution: {
|
|
schema_version: "missioncore.e30-engineering-causes/v1",
|
|
item_count_with_cause: 312,
|
|
reasons: [
|
|
{ reason_code: "detector_error", count: 109 },
|
|
{ reason_code: "time_mismatch", count: 91 },
|
|
],
|
|
},
|
|
human_exceptions: [{
|
|
item_id: itemId,
|
|
review_key: "semantic:162:7",
|
|
source_stratum: "camera-only",
|
|
confidence: 0.48,
|
|
review_prompt: {
|
|
question: "Белый кластер — самостоятельное препятствие?",
|
|
focus: "Проверьте выбранные белые точки.",
|
|
effects: {
|
|
"object-present": "Сохранить занятую геометрию.",
|
|
"background-or-noise": "Исключить кластер.",
|
|
"insufficient-evidence": "Оставить неизвестным.",
|
|
},
|
|
},
|
|
}],
|
|
ai_review_complete: true,
|
|
human_exception_complete: false,
|
|
human_review_complete: false,
|
|
lab_published: false,
|
|
access: "read-only",
|
|
authority: {
|
|
commands_enabled: false,
|
|
navigation_or_safety_accepted: false,
|
|
},
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function catalog(overrides = {}) {
|
|
return {
|
|
schema_version: "missioncore.laboratory-e30-engineering-generations/v1",
|
|
configured: true,
|
|
items: [generation()],
|
|
candidate_total: 1,
|
|
invalid_total: 0,
|
|
access: "read-only",
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
function decision(overrides = {}) {
|
|
return {
|
|
schema_version: "missioncore.laboratory-e30-engineering-decision/v1",
|
|
generation_id: generationId,
|
|
decision: {
|
|
sequence: 362,
|
|
item_id: itemId,
|
|
review_key: "semantic:343:2",
|
|
source_stratum: "conflict",
|
|
verdict: "corrected",
|
|
effective_stratum: null,
|
|
detector_assessment: "false-positive",
|
|
projection_assessment: "aligned",
|
|
point_ownership: "surface-or-background",
|
|
cause_code: "detector_error",
|
|
confidence: 0.95,
|
|
human_exception_required: false,
|
|
exception_reason: null,
|
|
evidence_note: "Кадр 343. Рамка находится на ограждении.",
|
|
review_sheet: {
|
|
path: "conflict-01.jpg",
|
|
sha256: "e".repeat(64),
|
|
ordinal: 1,
|
|
},
|
|
...overrides,
|
|
},
|
|
access: "read-only",
|
|
};
|
|
}
|
|
|
|
before(async () => {
|
|
server = await createServer({
|
|
appType: "custom",
|
|
logLevel: "silent",
|
|
server: { middlewareMode: true },
|
|
});
|
|
({
|
|
parseE30EngineeringCatalog,
|
|
parseE30EngineeringDecision,
|
|
fetchE30EngineeringDecision,
|
|
E30EngineeringContractError,
|
|
} = await server.ssrLoadModule(
|
|
"/src/core/laboratory/e30Engineering.ts",
|
|
));
|
|
});
|
|
|
|
after(async () => {
|
|
await server?.close();
|
|
});
|
|
|
|
test("decodes immutable A3 summary and per-item engineering decision", () => {
|
|
const decodedCatalog = parseE30EngineeringCatalog(catalog());
|
|
const decodedDecision = parseE30EngineeringDecision(decision());
|
|
|
|
assert.equal(decodedCatalog.items[0].summary.reviewedItemCount, 486);
|
|
assert.equal(decodedCatalog.items[0].summary.humanExceptionCount, 5);
|
|
assert.equal(decodedCatalog.items[0].humanExceptions[0].reviewKey, "semantic:162:7");
|
|
assert.equal(
|
|
decodedCatalog.items[0].humanExceptions[0].reviewPrompt.effects["object-present"],
|
|
"Сохранить занятую геометрию.",
|
|
);
|
|
assert.equal(decodedDecision.verdict, "corrected");
|
|
assert.equal(decodedDecision.effectiveStratum, null);
|
|
assert.equal(decodedDecision.detectorAssessment, "false-positive");
|
|
});
|
|
|
|
test("rejects a generation that claims human ground truth", () => {
|
|
assert.throws(
|
|
() => parseE30EngineeringCatalog(catalog({
|
|
items: [generation({
|
|
producer: {
|
|
...generation().producer,
|
|
claims_human_ground_truth: true,
|
|
},
|
|
})],
|
|
})),
|
|
E30EngineeringContractError,
|
|
);
|
|
});
|
|
|
|
test("fetches one content-addressed item decision", async () => {
|
|
const requests = [];
|
|
const decoded = await fetchE30EngineeringDecision(
|
|
resultId,
|
|
generationId,
|
|
itemId,
|
|
{
|
|
fetcher: async (input, init) => {
|
|
requests.push({ input: String(input), method: init?.method });
|
|
return new Response(JSON.stringify(decision()), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
},
|
|
},
|
|
);
|
|
|
|
assert.equal(decoded.pointOwnership, "surface-or-background");
|
|
assert.deepEqual(requests, [{
|
|
input:
|
|
`/api/v1/laboratory/e30/reviews/${resultId}/engineering-generations/`
|
|
+ `${generationId}/items/${itemId}`,
|
|
method: "GET",
|
|
}]);
|
|
});
|