feat(lab): add lazy E40 evidence review
This commit is contained in:
@@ -5,6 +5,8 @@ import { createServer } from "vite";
|
||||
|
||||
let server;
|
||||
let fetchAdvancedLaboratoryResults;
|
||||
let fetchAdvancedLaboratoryIndex;
|
||||
let fetchAdvancedLaboratoryResult;
|
||||
let AdvancedLaboratoryContractError;
|
||||
|
||||
const authority = {
|
||||
@@ -637,6 +639,10 @@ before(async () => {
|
||||
fetchAdvancedLaboratoryResults,
|
||||
AdvancedLaboratoryContractError,
|
||||
} = await server.ssrLoadModule("/src/core/laboratory/advancedResults.ts"));
|
||||
({
|
||||
fetchAdvancedLaboratoryIndex,
|
||||
fetchAdvancedLaboratoryResult,
|
||||
} = await server.ssrLoadModule("/src/core/laboratory/advancedIndex.ts"));
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
@@ -703,6 +709,53 @@ test("decodes E31–E40 from separate read-only catalogs", async () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test("LAB bootstrap reads a lightweight advanced index", async () => {
|
||||
const requests = [];
|
||||
const decoded = await fetchAdvancedLaboratoryIndex({
|
||||
fetcher: async (input, init) => {
|
||||
requests.push({ input: String(input), method: init?.method });
|
||||
return new Response(JSON.stringify({
|
||||
schema_version: "missioncore.laboratory-advanced-index/v1",
|
||||
items: [
|
||||
{
|
||||
work_id: "e40-perception-product-gate",
|
||||
result_id: `e40-perception-product-gate-${"a".repeat(64)}`,
|
||||
created_at_utc: "2026-07-28T11:00:00Z",
|
||||
access: "read-only",
|
||||
},
|
||||
],
|
||||
access: "read-only",
|
||||
}), { status: 200 });
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepEqual(decoded.map((item) => item.workId), [
|
||||
"e40-perception-product-gate",
|
||||
]);
|
||||
assert.deepEqual(requests, [
|
||||
{ input: "/api/v1/laboratory/advanced-index", method: "GET" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("selected advanced LAB fetches only its own strict catalog", async () => {
|
||||
const requests = [];
|
||||
const decoded = await fetchAdvancedLaboratoryResult(
|
||||
"e40-perception-product-gate",
|
||||
{
|
||||
fetcher: async (input, init) => {
|
||||
requests.push({ input: String(input), method: init?.method });
|
||||
return new Response(JSON.stringify(catalog(e40())), { status: 200 });
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
assert.equal(decoded.e40.qualityGatePassed, true);
|
||||
assert.equal(decoded.e31, null);
|
||||
assert.deepEqual(requests, [
|
||||
{ input: "/api/v1/laboratory/e40/results?limit=1", method: "GET" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("keeps valid LAB catalogs available when one transport endpoint fails", async () => {
|
||||
const decoded = await fetchAdvancedLaboratoryResults({
|
||||
fetcher: async (input) => {
|
||||
|
||||
@@ -73,6 +73,8 @@ function item(overrides = {}) {
|
||||
materialization: {
|
||||
frame_point_count: 1813,
|
||||
projected_point_count: 3,
|
||||
projection_width: 800,
|
||||
projection_height: 600,
|
||||
candidate_point_count: 2,
|
||||
selected_point_count: 1,
|
||||
rejected_candidate_point_count: 1,
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { after, before, test } from "node:test";
|
||||
|
||||
import { createServer } from "vite";
|
||||
|
||||
let server;
|
||||
let parseE40CaseCatalog;
|
||||
let parseE40OperatorReview;
|
||||
let fetchE40CaseCatalog;
|
||||
let saveE40OperatorVerdict;
|
||||
let E40CaseReviewContractError;
|
||||
|
||||
const resultId = `e40-perception-product-gate-${"a".repeat(64)}`;
|
||||
const materializationId = `e30-materialization-${"b".repeat(64)}`;
|
||||
const itemId = `e30-review-item-${"c".repeat(64)}`;
|
||||
|
||||
function payload(overrides = {}) {
|
||||
return {
|
||||
schema_version: "missioncore.laboratory-e40-case-catalog/v1",
|
||||
result_id: resultId,
|
||||
materialization_id: materializationId,
|
||||
items: [{
|
||||
item_id: itemId,
|
||||
sequence: 3,
|
||||
source_frame_index: 1080,
|
||||
source_stratum: "geometry-only",
|
||||
severity: "high",
|
||||
presence_confidence: 1,
|
||||
prediction_basis: "fixed-stratum-policy",
|
||||
reference: {
|
||||
presence: "object-present",
|
||||
geometry_association: "object-associated",
|
||||
freshness: "current",
|
||||
},
|
||||
prediction: {
|
||||
presence: "occupied-environment",
|
||||
geometry_association: "independent-occupied",
|
||||
freshness: "current",
|
||||
},
|
||||
mismatched_dimensions: ["presence", "geometry_association"],
|
||||
access: "read-only",
|
||||
}],
|
||||
total: 23,
|
||||
truncated: false,
|
||||
access: "read-only",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function reviewPayload(overrides = {}) {
|
||||
return {
|
||||
schema_version: "missioncore.e40-operator-review/v1",
|
||||
review_id: `e40-operator-review-${"f".repeat(64)}`,
|
||||
protocol: "sealed-error-adjudication/v1",
|
||||
source: {
|
||||
result_id: resultId,
|
||||
materialization_id: materializationId,
|
||||
case_catalog_sha256: "1".repeat(64),
|
||||
item_count: 1,
|
||||
item_set_sha256: "2".repeat(64),
|
||||
},
|
||||
reviewer_id: "DC",
|
||||
revision: 1,
|
||||
decisions: [{
|
||||
item_id: itemId,
|
||||
verdict: "confirmed-error",
|
||||
revision: 1,
|
||||
idempotency_key: "ui-test",
|
||||
decided_at_utc: "2026-07-30T17:00:00.000Z",
|
||||
event_id: `e40-operator-verdict-${"3".repeat(64)}`,
|
||||
}],
|
||||
reviewed_item_count: 1,
|
||||
remaining_item_count: 0,
|
||||
updated_at_utc: "2026-07-30T17:00:00.000Z",
|
||||
access: "review-write",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
before(async () => {
|
||||
server = await createServer({
|
||||
configFile: false,
|
||||
appType: "custom",
|
||||
optimizeDeps: { noDiscovery: true },
|
||||
server: { middlewareMode: true, hmr: false },
|
||||
});
|
||||
({
|
||||
parseE40CaseCatalog,
|
||||
parseE40OperatorReview,
|
||||
fetchE40CaseCatalog,
|
||||
saveE40OperatorVerdict,
|
||||
E40CaseReviewContractError,
|
||||
} = await server.ssrLoadModule("/src/core/laboratory/e40CaseReview.ts"));
|
||||
});
|
||||
|
||||
test("E40 operator review preserves the sealed source and verdict", () => {
|
||||
const review = parseE40OperatorReview(reviewPayload());
|
||||
|
||||
assert.equal(review.resultId, resultId);
|
||||
assert.equal(review.materializationId, materializationId);
|
||||
assert.equal(review.caseCatalogSha256, "1".repeat(64));
|
||||
assert.equal(review.reviewedItemCount, 1);
|
||||
assert.equal(review.decisions[0].verdict, "confirmed-error");
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await server.close();
|
||||
});
|
||||
|
||||
test("E40 case catalog preserves the sealed error binding", () => {
|
||||
const catalog = parseE40CaseCatalog(payload());
|
||||
|
||||
assert.equal(catalog.resultId, resultId);
|
||||
assert.equal(catalog.materializationId, materializationId);
|
||||
assert.equal(catalog.items[0].sourceFrameIndex, 1080);
|
||||
assert.equal(catalog.items[0].predictionBasis, "fixed-stratum-policy");
|
||||
assert.deepEqual(
|
||||
catalog.items[0].mismatchedDimensions,
|
||||
["presence", "geometry_association"],
|
||||
);
|
||||
assert.equal(
|
||||
catalog.items[0].prediction.geometryAssociation,
|
||||
"independent-occupied",
|
||||
);
|
||||
});
|
||||
|
||||
test("E40 case fetch is bounded and rejects a foreign result", async () => {
|
||||
let requestUrl = "";
|
||||
const fetcher = async (input) => {
|
||||
requestUrl = String(input);
|
||||
return new Response(JSON.stringify(payload({
|
||||
result_id: `e40-perception-product-gate-${"d".repeat(64)}`,
|
||||
})), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
};
|
||||
|
||||
await assert.rejects(
|
||||
fetchE40CaseCatalog(resultId, { fetcher }),
|
||||
E40CaseReviewContractError,
|
||||
);
|
||||
assert.match(requestUrl, /cases\?limit=48$/);
|
||||
});
|
||||
|
||||
test("E40 operator verdict is committed with revision and idempotency", async () => {
|
||||
let requestUrl = "";
|
||||
let requestInit;
|
||||
const fetcher = async (input, init) => {
|
||||
requestUrl = String(input);
|
||||
requestInit = init;
|
||||
return new Response(JSON.stringify(reviewPayload()), {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
};
|
||||
|
||||
const review = await saveE40OperatorVerdict(resultId, itemId, {
|
||||
expectedRevision: 0,
|
||||
idempotencyKey: "ui-test",
|
||||
verdict: "confirmed-error",
|
||||
fetcher,
|
||||
});
|
||||
|
||||
assert.match(requestUrl, /operator-review\/decisions\/e30-review-item-/);
|
||||
assert.equal(requestInit.method, "PUT");
|
||||
assert.deepEqual(JSON.parse(requestInit.body), {
|
||||
reviewer_id: "DC",
|
||||
expected_revision: 0,
|
||||
idempotency_key: "ui-test",
|
||||
verdict: "confirmed-error",
|
||||
});
|
||||
assert.equal(review.revision, 1);
|
||||
});
|
||||
@@ -42,6 +42,10 @@ const e40ResultUrl = new URL(
|
||||
"../src/workspaces/laboratory/E40Result.tsx",
|
||||
import.meta.url,
|
||||
);
|
||||
const e40CaseReviewUrl = new URL(
|
||||
"../src/workspaces/laboratory/E40CaseReview.tsx",
|
||||
import.meta.url,
|
||||
);
|
||||
const e35StylesUrl = new URL(
|
||||
"../src/styles/e35-degradation-recovery.css",
|
||||
import.meta.url,
|
||||
@@ -265,9 +269,10 @@ test("E39 reports refinement and the CV-to-validation gap through the canonical
|
||||
assert.match(advancedSource, /<E39Result/);
|
||||
});
|
||||
|
||||
test("E40 reports dual grouped qualification and the sealed product gate through the canonical LAB anatomy", async () => {
|
||||
const [e40Source, advancedSource] = await Promise.all([
|
||||
test("E40 reports historical visible evaluation with bounded camera-LiDAR case review", async () => {
|
||||
const [e40Source, caseReviewSource, advancedSource] = await Promise.all([
|
||||
readFile(e40ResultUrl, "utf8"),
|
||||
readFile(e40CaseReviewUrl, "utf8"),
|
||||
readFile(advancedLaboratoryResultUrl, "utf8"),
|
||||
]);
|
||||
|
||||
@@ -275,10 +280,22 @@ test("E40 reports dual grouped qualification and the sealed product gate through
|
||||
assert.match(e40Source, /<LaboratoryEvidence/);
|
||||
assert.match(e40Source, /<LaboratoryResultSummary/);
|
||||
assert.match(e40Source, /frame index, session time, review ordinal, track ID/);
|
||||
assert.match(e40Source, /validation labels при выборе и обучении не использовались/);
|
||||
assert.match(e40Source, /Whole track \/ scene CV/);
|
||||
assert.match(e40Source, /[Ss]ource-scoped perception gate/);
|
||||
assert.match(e40Source, /Только camera-only использует softmax/);
|
||||
assert.match(e40Source, /<E40CaseReview resultId=\{result\.resultId\}/);
|
||||
assert.match(e40Source, /historical visible engineering evaluation/);
|
||||
assert.match(e40Source, /не подбирая профиль по validation/);
|
||||
assert.match(caseReviewSource, /<LaboratoryEvidenceViewer/);
|
||||
assert.match(caseReviewSource, /<E30EvidenceProjection/);
|
||||
assert.match(caseReviewSource, /<E30EvidencePointCloud/);
|
||||
assert.match(caseReviewSource, /fetchE30ReviewItemDetail/);
|
||||
assert.match(caseReviewSource, /fetchE40OperatorReview/);
|
||||
assert.match(caseReviewSource, /saveE40OperatorVerdict/);
|
||||
assert.match(caseReviewSource, /Расхождение исторической оценки E40/);
|
||||
assert.match(caseReviewSource, /label="Предыдущее расхождение"/);
|
||||
assert.match(caseReviewSource, /label="Следующее расхождение"/);
|
||||
assert.match(caseReviewSource, /расхождение E40 подтверждается/);
|
||||
assert.match(caseReviewSource, /предполагаемая ошибка отклоняется/);
|
||||
assert.match(caseReviewSource, /фиксированная stratum-policy, не вероятность/);
|
||||
assert.doesNotMatch(
|
||||
e40Source,
|
||||
/className="laboratory-(?:summary|result-summary|result-metrics|result-conclusion)"/,
|
||||
|
||||
Reference in New Issue
Block a user