6 Commits
41 changed files with 4495 additions and 101 deletions
@@ -42,12 +42,14 @@ import {
fetchM48LifecycleResult,
} from "./m48ObjectCentricQuality";
import { fetchM48SmallStaticRegression } from "./m48SmallStaticRegression";
import { fetchM48StaticOccupancyQualification } from "./m48StaticOccupancyQualification";
import { fetchM48SFixedClassDetectorResult } from "./m48sFixedClassDetector";
import { fetchM48TRiskQualityResult } from "./m48tRiskQuality";
export type AdvancedLaboratoryWorkId =
| "m48-object-centric-quality"
| "m48-small-static-passage-regression"
| "m48-static-occupancy-qualification"
| "m48s-fixed-class-detector"
| "m48t-risk-quality-temporal"
| "m47-reference-graph-shadow"
@@ -94,6 +96,7 @@ export interface AdvancedLaboratoryIndexItem {
const WORK_IDS: readonly AdvancedLaboratoryWorkId[] = [
"m48-object-centric-quality",
"m48-small-static-passage-regression",
"m48-static-occupancy-qualification",
"m48s-fixed-class-detector",
"m48t-risk-quality-temporal",
"m47-reference-graph-shadow",
@@ -135,8 +138,9 @@ const WORK_IDS: readonly AdvancedLaboratoryWorkId[] = [
const RESULT_PREFIX: Readonly<Record<AdvancedLaboratoryWorkId, string>> = {
"m48-object-centric-quality": "m48-object-quality-(?:pack|result)",
"m48-small-static-passage-regression": "m48-small-static-passage-regression",
"m48-static-occupancy-qualification": "m48-static-occupancy-qualification",
"m48s-fixed-class-detector": "m48s-fixed-class-detector-lab",
"m48t-risk-quality-temporal": "m48t-risk-quality-temporal-lab",
"m48t-risk-quality-temporal": "(?:m48t-risk-quality-temporal-lab|m48q-native-risk-quality-lab)",
"m47-reference-graph-shadow": "m47-reference-graph-lab",
"m4-replay-threat": "m4-threat-replay",
"l3-pointpillars-visual-audit": "l3-pointpillars-visual-audit",
@@ -184,6 +188,7 @@ export function emptyAdvancedLaboratoryResults(): AdvancedLaboratoryResults {
m47Graph: null,
m48: null,
m48SmallStatic: null,
m48StaticOccupancy: null,
m48s: null,
m48t: null,
m4Threat: null,
@@ -312,6 +317,7 @@ export function advancedLaboratoryResultAvailable(
): boolean {
return workId === "m48-object-centric-quality" ? results.m48 !== null
: workId === "m48-small-static-passage-regression" ? results.m48SmallStatic !== null
: workId === "m48-static-occupancy-qualification" ? results.m48StaticOccupancy !== null
: workId === "m48s-fixed-class-detector" ? results.m48s !== null
: workId === "m48t-risk-quality-temporal" ? results.m48t !== null
: workId === "m47-reference-graph-shadow" ? results.m47Graph !== null
@@ -369,6 +375,9 @@ export async function fetchAdvancedLaboratoryResult(
} else if (workId === "m48-small-static-passage-regression") {
if (!resultId) throw new AdvancedLaboratoryContractError("M4.8R1 regression identity не выбрана.");
results.m48SmallStatic = await fetchM48SmallStaticRegression(resultId, { fetcher, signal });
} else if (workId === "m48-static-occupancy-qualification") {
if (!resultId) throw new AdvancedLaboratoryContractError("M4.8R2 qualification identity не выбрана.");
results.m48StaticOccupancy = await fetchM48StaticOccupancyQualification(resultId, { fetcher, signal });
} else if (workId === "m48s-fixed-class-detector") {
if (!resultId) throw new AdvancedLaboratoryContractError("M4.8S LAB identity не выбрана.");
results.m48s = await fetchM48SFixedClassDetectorResult(resultId, { fetcher, signal });
@@ -36,6 +36,7 @@ import type { M4ThreatReplayResult } from "./m4ReplayThreat";
import type { M47ReferenceGraphLabResult } from "./m47ReferenceGraph";
import type { M48AdvancedResult } from "./m48ObjectCentricQuality";
import type { M48SmallStaticRegressionResult } from "./m48SmallStaticRegression";
import type { M48StaticOccupancyQualificationResult } from "./m48StaticOccupancyQualification";
import type { M48SFixedClassDetectorResult } from "./m48sFixedClassDetector";
import type { M48TRiskQualityResult } from "./m48tRiskQuality";
@@ -43,6 +44,7 @@ export interface AdvancedLaboratoryResults {
m47Graph: M47ReferenceGraphLabResult | null;
m48: M48AdvancedResult | null;
m48SmallStatic: M48SmallStaticRegressionResult | null;
m48StaticOccupancy: M48StaticOccupancyQualificationResult | null;
m48s: M48SFixedClassDetectorResult | null;
m48t: M48TRiskQualityResult | null;
m4Threat: M4ThreatReplayResult | null;
@@ -967,10 +967,9 @@ export async function fetchAdvancedLaboratoryResults({
const e39 = settledCatalogValue(settled[7]);
const e40 = settledCatalogValue(settled[8]);
return {
m47Graph: null, m48: null, m48SmallStatic: null, m48s: null, m48t: null, m4Threat: null,
l3: null, l31: null,
l32: null,
l33: null,
m47Graph: null, m48: null, m48SmallStatic: null, m48StaticOccupancy: null,
m48s: null, m48t: null, m4Threat: null,
l3: null, l31: null, l32: null, l33: null,
e31,
e32,
e33,
@@ -0,0 +1,248 @@
import type { LaboratoryFetch } from "./advancedResults";
import type { M48Authority } from "./m48ObjectCentricQuality";
const RESULT_ID = /^m48-static-occupancy-qualification-[a-f0-9]{64}$/;
const M47_RESULT_ID = /^m47-reference-graph-lab-[a-f0-9]{64}$/;
const M48R1_RESULT_ID = /^m48-small-static-passage-regression-[a-f0-9]{64}$/;
const ANCHOR_ID = /^anchor-[a-f0-9]{24}$/;
export interface M48StaticOccupancyMetrics {
operatorStaticAnchorCount: number;
baselineQualifiedCount: number;
candidateQualifiedCount: number;
unresolvedUnknownCount: number;
criticalNearAnchorCount: number;
criticalNearBaselineRecall: number;
criticalNearCandidateRecall: number;
approachAnchorCount: number;
approachBaselineRecall: number;
approachCandidateRecall: number;
canonicalEngineeringAnchorCount: number;
canonicalEngineeringRecall: number;
falseFreeCount: number;
}
export interface M48StaticOccupancyQualificationResult {
resultId: string;
referenceGraphLabResultId: string;
smallStaticResultId: string;
createdAtUtc: string;
runLabel: "M4.8R2";
pipelineId: "m4-current-rolling-plus-step-static-occupancy/v1";
experimentId: "m48-static-occupancy-qualification/v1";
accepted: boolean;
metrics: M48StaticOccupancyMetrics;
gates: {
criticalNearCandidateRecall: boolean;
approachCandidateRecall: boolean;
canonicalEngineeringRecall: boolean;
zeroFalseFree: boolean;
independentTruthAvailable: false;
};
decision: {
state: "accepted-bounded-static-occupancy-qualification" | "partial-static-occupancy-qualification";
criticalNearCandidateReadyForShadow: boolean;
productionAccepted: false;
summary: string;
nextAction: string;
};
authority: M48Authority;
}
export interface M48StaticOccupancyCase {
anchorId: string;
clipId: string;
sequence: number;
extentXyxy: readonly [number, number, number, number];
distanceM: number;
distanceBand: "critical-near" | "approach" | "outside-qualified-bands";
baselineQualified: boolean;
candidateQualified: boolean;
outcome: "candidate-qualified" | "unresolved-unknown-never-free";
graphMatched: boolean;
}
export class M48StaticOccupancyContractError extends Error {}
function objectValue(value: unknown, label: string): Record<string, unknown> {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new M48StaticOccupancyContractError(`${label}: ожидался объект.`);
}
return value as Record<string, unknown>;
}
function text(value: unknown, label: string): string {
if (typeof value !== "string" || !value.trim()) {
throw new M48StaticOccupancyContractError(`${label}: ожидалась строка.`);
}
return value;
}
function numberValue(value: unknown, label: string): number {
if (typeof value !== "number" || !Number.isFinite(value)) {
throw new M48StaticOccupancyContractError(`${label}: ожидалось число.`);
}
return value;
}
function integer(value: unknown, label: string): number {
const parsed = numberValue(value, label);
if (!Number.isInteger(parsed) || parsed < 0) {
throw new M48StaticOccupancyContractError(`${label}: ожидалось целое число.`);
}
return parsed;
}
function bool(value: unknown, label: string): boolean {
if (typeof value !== "boolean") {
throw new M48StaticOccupancyContractError(`${label}: ожидался флаг.`);
}
return value;
}
function exact(value: unknown, expected: string | boolean, label: string): void {
if (value !== expected) throw new M48StaticOccupancyContractError(`${label}: нарушен контракт.`);
}
function member<T extends string>(value: unknown, allowed: readonly T[], label: string): T {
const parsed = text(value, label);
if (!allowed.includes(parsed as T)) {
throw new M48StaticOccupancyContractError(`${label}: недопустимое значение.`);
}
return parsed as T;
}
function extent(value: unknown): readonly [number, number, number, number] {
if (!Array.isArray(value) || value.length !== 4 || value.some((item) => typeof item !== "number" || !Number.isFinite(item))) {
throw new M48StaticOccupancyContractError("M4.8R2.case.extent: нарушен контракт.");
}
const result = value as number[];
if (result.some((item) => item < 0 || item > 1) || result[0]! >= result[2]! || result[1]! >= result[3]!) {
throw new M48StaticOccupancyContractError("M4.8R2.case.extent: нарушена геометрия.");
}
return result as unknown as readonly [number, number, number, number];
}
function authority(value: unknown): M48Authority {
const row = objectValue(value, "M4.8R2.authority");
exact(row.mode, "replay-simulated", "M4.8R2.authority.mode");
exact(row.physical_live, false, "M4.8R2.authority.physical_live");
exact(row.commands_enabled, false, "M4.8R2.authority.commands_enabled");
exact(row.actuation_allowed, false, "M4.8R2.authority.actuation_allowed");
exact(row.navigation_or_safety_accepted, false, "M4.8R2.authority.navigation_or_safety_accepted");
return { mode: "replay-simulated", physicalLive: false, commandsEnabled: false, actuationAllowed: false, navigationOrSafetyAccepted: false };
}
function metrics(value: unknown): M48StaticOccupancyMetrics {
const row = objectValue(value, "M4.8R2.metrics");
return {
operatorStaticAnchorCount: integer(row.operator_static_anchor_count, "operator_static_anchor_count"),
baselineQualifiedCount: integer(row.baseline_qualified_count, "baseline_qualified_count"),
candidateQualifiedCount: integer(row.candidate_qualified_count, "candidate_qualified_count"),
unresolvedUnknownCount: integer(row.unresolved_unknown_count, "unresolved_unknown_count"),
criticalNearAnchorCount: integer(row.critical_near_anchor_count, "critical_near_anchor_count"),
criticalNearBaselineRecall: numberValue(row.critical_near_baseline_recall, "critical_near_baseline_recall"),
criticalNearCandidateRecall: numberValue(row.critical_near_candidate_recall, "critical_near_candidate_recall"),
approachAnchorCount: integer(row.approach_anchor_count, "approach_anchor_count"),
approachBaselineRecall: numberValue(row.approach_baseline_recall, "approach_baseline_recall"),
approachCandidateRecall: numberValue(row.approach_candidate_recall, "approach_candidate_recall"),
canonicalEngineeringAnchorCount: integer(row.canonical_engineering_anchor_count, "canonical_engineering_anchor_count"),
canonicalEngineeringRecall: numberValue(row.canonical_engineering_recall, "canonical_engineering_recall"),
falseFreeCount: integer(row.false_free_count, "false_free_count"),
};
}
export async function fetchM48StaticOccupancyQualification(
resultId: string,
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
): Promise<M48StaticOccupancyQualificationResult> {
if (!RESULT_ID.test(resultId)) throw new M48StaticOccupancyContractError("M4.8R2 identity недопустима.");
const response = await fetcher(`/api/v1/laboratory/m48/regressions/static-occupancy/${encodeURIComponent(resultId)}`, { method: "GET", headers: { Accept: "application/json" }, signal });
if (!response.ok) throw new M48StaticOccupancyContractError(`M4.8R2 недоступен: HTTP ${response.status}.`);
const payload = objectValue(await response.json(), "M4.8R2");
exact(payload.schema_version, "missioncore.m48-static-occupancy-qualification-result-view/v1", "M4.8R2.schema_version");
const m47 = text(payload.reference_graph_lab_result_id, "M4.8R2.reference_graph_lab_result_id");
const m48r1 = text(payload.small_static_result_id, "M4.8R2.small_static_result_id");
if (!M47_RESULT_ID.test(m47) || !M48R1_RESULT_ID.test(m48r1)) throw new M48StaticOccupancyContractError("M4.8R2 source identity нарушена.");
exact(payload.run_label, "M4.8R2", "M4.8R2.run_label");
exact(payload.pipeline_id, "m4-current-rolling-plus-step-static-occupancy/v1", "M4.8R2.pipeline_id");
exact(payload.experiment_id, "m48-static-occupancy-qualification/v1", "M4.8R2.experiment_id");
exact(payload.ground_truth, false, "M4.8R2.ground_truth");
exact(payload.independent_truth, false, "M4.8R2.independent_truth");
const gates = objectValue(payload.gates, "M4.8R2.gates");
const decision = objectValue(payload.decision, "M4.8R2.decision");
exact(decision.production_accepted, false, "M4.8R2.decision.production_accepted");
return {
resultId,
referenceGraphLabResultId: m47,
smallStaticResultId: m48r1,
createdAtUtc: text(payload.created_at_utc, "M4.8R2.created_at_utc"),
runLabel: "M4.8R2",
pipelineId: "m4-current-rolling-plus-step-static-occupancy/v1",
experimentId: "m48-static-occupancy-qualification/v1",
accepted: bool(payload.accepted, "M4.8R2.accepted"),
metrics: metrics(payload.metrics),
gates: {
criticalNearCandidateRecall: bool(gates.critical_near_candidate_recall, "critical_near_candidate_recall"),
approachCandidateRecall: bool(gates.approach_candidate_recall, "approach_candidate_recall"),
canonicalEngineeringRecall: bool(gates.canonical_engineering_recall, "canonical_engineering_recall"),
zeroFalseFree: bool(gates.zero_false_free, "zero_false_free"),
independentTruthAvailable: false,
},
decision: {
state: member(
decision.state,
[
"accepted-bounded-static-occupancy-qualification",
"partial-static-occupancy-qualification",
] as const,
"M4.8R2.decision.state",
),
criticalNearCandidateReadyForShadow: bool(decision.critical_near_candidate_ready_for_shadow, "critical_near_candidate_ready_for_shadow"),
productionAccepted: false,
summary: text(decision.summary, "M4.8R2.decision.summary"),
nextAction: text(decision.next_action, "M4.8R2.decision.next_action"),
},
authority: authority(payload.authority),
};
}
export async function fetchM48StaticOccupancyCases(
resultId: string,
{ fetcher = fetch, signal }: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
): Promise<readonly M48StaticOccupancyCase[]> {
if (!RESULT_ID.test(resultId)) throw new M48StaticOccupancyContractError("M4.8R2 identity недопустима.");
const response = await fetcher(`/api/v1/laboratory/m48/regressions/static-occupancy/${encodeURIComponent(resultId)}/cases`, { method: "GET", headers: { Accept: "application/json" }, signal });
if (!response.ok) throw new M48StaticOccupancyContractError(`M4.8R2 cases недоступны: HTTP ${response.status}.`);
const payload = objectValue(await response.json(), "M4.8R2 cases");
exact(payload.schema_version, "missioncore.m48-static-occupancy-case-catalog/v1", "M4.8R2 cases.schema_version");
if (!Array.isArray(payload.cases) || payload.cases.length !== integer(payload.case_count, "M4.8R2.case_count")) throw new M48StaticOccupancyContractError("M4.8R2 cases: размер изменился.");
return payload.cases.map((value, index) => {
const row = objectValue(value, `M4.8R2.case[${index}]`);
const anchorId = text(row.anchor_id, "anchor_id");
if (!ANCHOR_ID.test(anchorId)) throw new M48StaticOccupancyContractError("M4.8R2 anchor identity нарушена.");
const graph = objectValue(row.accepted_graph, "accepted_graph");
const band = member(
row.distance_band,
["critical-near", "approach", "outside-qualified-bands"] as const,
"distance_band",
);
const outcome = member(
row.outcome,
["candidate-qualified", "unresolved-unknown-never-free"] as const,
"outcome",
);
return {
anchorId,
clipId: text(row.clip_id, "clip_id"),
sequence: integer(row.sequence, "sequence"),
extentXyxy: extent(row.extent_xyxy),
distanceM: numberValue(row.distance_m, "distance_m"),
distanceBand: band,
baselineQualified: bool(row.baseline_qualified, "baseline_qualified"),
candidateQualified: bool(row.candidate_qualified, "candidate_qualified"),
outcome,
graphMatched: bool(graph.matched, "accepted_graph.matched"),
};
});
}
@@ -19,7 +19,8 @@ export interface M48TReviewCase {
sha256: string;
}
export interface M48TRiskQualityResult {
export interface M48TLegacyRiskQualityResult {
variant: "legacy-coco-quality";
resultId: string;
createdAtUtc: string;
source: {
@@ -93,6 +94,90 @@ export interface M48TRiskQualityResult {
limitations: readonly string[];
}
export type M48QRiskFamily = "person" | "animal" | "light-road-user" | "vehicle";
export interface M48QNativeProposal {
proposalId: string;
className: string;
riskFamily: M48QRiskFamily;
score: number;
boxXyxy: readonly [number, number, number, number];
}
export interface M48QNativeReviewCase {
caseId: string;
sequence: number;
frameId: string;
evidenceTimeNs: number;
imageUrl: string;
width: 800;
height: 600;
byteLength: number;
sha256: string;
selectionBuckets: readonly string[];
nativeDetectionCount: number;
legacyDetectionCount: number;
matchedDetectionCount: number;
proposals: readonly M48QNativeProposal[];
}
export interface M48QNativeRiskQualityResult {
variant: "native-risk-review";
resultId: string;
createdAtUtc: string;
source: {
sourceId: "RAVNOVES00";
frameCount: 4489;
width: 800;
height: 600;
geometricResampling: false;
};
candidate: {
providerId: string;
modelId: "rf_detr_large_native_kb4:1";
preprocessId: "raw-kb4-uint8-fused-mask-rgb-pad8-imagenet-trt/v0";
minimumScore: 0.25;
};
execution: {
effectiveWorldStateFps: number;
worldStateCompletionP95Ms: number;
detectorTotalP95Ms: number;
gpuUtilizationP95Percent: number;
gpuMemoryMaximumMib: number;
additionalInferencePasses: 0;
};
selection: {
caseCount: 24;
minimumSequenceSeparation: number;
bucketCoverage: Readonly<Record<string, number>>;
classCounts: Readonly<Record<string, number>>;
};
runtime: {
deliveryRatio: number;
integratedGatePassed: true;
operatingTargetGatePassed: true;
};
parity: {
precision: number;
recall: number;
meanIou: number;
};
acceptance: {
reviewReady: true;
independentQualityEvaluated: false;
semanticCandidateAccepted: false;
};
review: {
cases: readonly M48QNativeReviewCase[];
};
method: M48TLaboratoryMethod;
limitations: readonly string[];
}
export type M48TRiskQualityResult =
| M48TLegacyRiskQualityResult
| M48QNativeRiskQualityResult;
type LaboratoryFetch = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
export class M48TContractError extends Error {}
@@ -173,9 +258,10 @@ function method(value: unknown): M48TLaboratoryMethod {
};
}
function parseResult(value: unknown, expectedResultId: string): M48TRiskQualityResult {
function parseLegacyResult(value: unknown, expectedResultId: string): M48TLegacyRiskQualityResult {
const raw = object(value, "M4.8T result");
exact(raw.schema_version, "missioncore.m48t-risk-quality-temporal-view/v1", "M4.8T schema");
exact(raw.variant, "legacy-coco-quality", "M4.8T variant");
exact(raw.result_id, expectedResultId, "M4.8T identity");
exact(raw.status, "complete-quality-gate-failed-temporal-invariant-passed", "M4.8T status");
exact(raw.access, "read-only", "M4.8T access");
@@ -234,6 +320,7 @@ function parseResult(value: unknown, expectedResultId: string): M48TRiskQualityR
for (const [key, count] of Object.entries(failures)) parsedFailures[key] = integer(count, `M4.8T failure ${key}`);
const temporalConfiguration = object(configuration.temporal, "M4.8T temporal configuration");
return {
variant: "legacy-coco-quality",
resultId: expectedResultId,
createdAtUtc: text(raw.created_at_utc, "M4.8T created at"),
source: {
@@ -306,6 +393,207 @@ function parseResult(value: unknown, expectedResultId: string): M48TRiskQualityR
};
}
function numberRecord(value: unknown, label: string): Readonly<Record<string, number>> {
const raw = object(value, label);
const parsed: Record<string, number> = {};
for (const [key, item] of Object.entries(raw)) parsed[key] = integer(item, `${label}.${key}`);
return parsed;
}
function nativeRiskFamily(value: unknown): M48QRiskFamily {
const parsed = text(value, "M4.8Q risk family");
if (!["person", "animal", "light-road-user", "vehicle"].includes(parsed)) {
throw new M48TContractError("M4.8Q risk family: неизвестное значение.");
}
return parsed as M48QRiskFamily;
}
function nativeProposal(value: unknown): M48QNativeProposal {
const raw = object(value, "M4.8Q proposal");
const coordinates = array(raw.box_xyxy, "M4.8Q proposal box").map((item) =>
number(item, "M4.8Q proposal coordinate")
);
if (
coordinates.length !== 4
|| coordinates[0] >= coordinates[2]
|| coordinates[1] >= coordinates[3]
|| coordinates[2] > 800
|| coordinates[3] > 600
) {
throw new M48TContractError("M4.8Q proposal box: нарушена raw-raster геометрия.");
}
const score = number(raw.score, "M4.8Q proposal score");
if (score < 0.25 || score > 1) throw new M48TContractError("M4.8Q proposal score: нарушен threshold.");
return {
proposalId: text(raw.proposal_id, "M4.8Q proposal id"),
className: text(raw.class_name, "M4.8Q proposal class"),
riskFamily: nativeRiskFamily(raw.risk_family),
score,
boxXyxy: coordinates as [number, number, number, number],
};
}
function parseNativeResult(value: unknown, expectedResultId: string): M48QNativeRiskQualityResult {
const raw = object(value, "M4.8Q result");
exact(raw.schema_version, "missioncore.m48q-native-risk-quality-view/v1", "M4.8Q schema");
exact(raw.variant, "native-risk-review", "M4.8Q variant");
exact(raw.result_id, expectedResultId, "M4.8Q identity");
exact(raw.status, "complete-review-ready-quality-not-adjudicated", "M4.8Q status");
exact(raw.access, "read-only", "M4.8Q access");
exact(raw.ground_truth, false, "M4.8Q ground truth");
const source = object(raw.source, "M4.8Q source");
exact(source.source_id, "RAVNOVES00", "M4.8Q source id");
exact(source.frame_count, 4489, "M4.8Q source frames");
exact(source.raster_width, 800, "M4.8Q source width");
exact(source.raster_height, 600, "M4.8Q source height");
exact(source.geometric_resampling, false, "M4.8Q source resampling");
exact(source.rectification, false, "M4.8Q source rectification");
exact(source.warp, false, "M4.8Q source warp");
const configuration = object(raw.configuration, "M4.8Q configuration");
const candidate = object(configuration.candidate, "M4.8Q candidate");
const execution = object(raw.execution, "M4.8Q execution");
const metrics = object(raw.metrics, "M4.8Q metrics");
const selection = object(metrics.selection, "M4.8Q selection");
const runtime = object(metrics.runtime, "M4.8Q runtime");
const parity = object(metrics.native_tensor_parity, "M4.8Q parity");
const acceptance = object(raw.acceptance, "M4.8Q acceptance");
exact(acceptance.review_ready, true, "M4.8Q review readiness");
exact(acceptance.integrated_runtime_gate_passed, true, "M4.8Q runtime gate");
exact(acceptance.independent_quality_evaluated, false, "M4.8Q quality state");
exact(acceptance.semantic_candidate_accepted, false, "M4.8Q candidate state");
exact(selection.case_count, 24, "M4.8Q selected cases");
const review = object(raw.review, "M4.8Q review");
const raster = object(review.source_raster, "M4.8Q review raster");
exact(raster.width, 800, "M4.8Q review width");
exact(raster.height, 600, "M4.8Q review height");
const overlay = object(review.overlay, "M4.8Q overlay");
exact(overlay.client_rendered, true, "M4.8Q client overlay");
exact(overlay.toggleable, true, "M4.8Q overlay toggle");
const cases = array(review.cases, "M4.8Q review cases").map((value) => {
const item = object(value, "M4.8Q review case");
const caseId = text(item.case_id, "M4.8Q case id");
if (!/^[0-9]{6}$/.test(caseId)) throw new M48TContractError("M4.8Q case identity нарушена.");
const sequence = integer(item.sequence, "M4.8Q case sequence");
exact(caseId, sequence.toString().padStart(6, "0"), "M4.8Q case/sequence identity");
exact(item.frame_id, `frame-${caseId}`, "M4.8Q frame identity");
exact(item.media_type, "image/jpeg", "M4.8Q case media");
exact(item.width, 800, "M4.8Q case width");
exact(item.height, 600, "M4.8Q case height");
exact(item.geometric_resampling, false, "M4.8Q case resampling");
const comparison = object(item.comparison, "M4.8Q comparison");
const proposals = array(item.proposals, "M4.8Q proposals").map(nativeProposal);
if (!proposals.length) throw new M48TContractError("M4.8Q proposals: пустой review case.");
return {
caseId,
sequence,
frameId: `frame-${caseId}`,
evidenceTimeNs: integer(item.evidence_time_ns, "M4.8Q evidence time"),
imageUrl: text(item.image_url, "M4.8Q image URL"),
width: 800 as const,
height: 600 as const,
byteLength: integer(item.byte_length, "M4.8Q image bytes"),
sha256: sha(item.sha256, "M4.8Q image SHA"),
selectionBuckets: array(item.selection_buckets, "M4.8Q selection buckets").map((bucket) =>
text(bucket, "M4.8Q selection bucket")
),
nativeDetectionCount: integer(comparison.native_detection_count, "M4.8Q native count"),
legacyDetectionCount: integer(comparison.legacy_704_detection_count, "M4.8Q legacy count"),
matchedDetectionCount: integer(
comparison.matched_detection_count_iou_at_least_0_5,
"M4.8Q matched count",
),
proposals,
};
});
if (cases.length !== 24 || new Set(cases.map(({ caseId }) => caseId)).size !== 24) {
throw new M48TContractError("M4.8Q review catalog: нарушен размер.");
}
return {
variant: "native-risk-review",
resultId: expectedResultId,
createdAtUtc: text(raw.created_at_utc, "M4.8Q created at"),
source: {
sourceId: "RAVNOVES00",
frameCount: 4489,
width: 800,
height: 600,
geometricResampling: false,
},
candidate: {
providerId: text(candidate.provider_id, "M4.8Q provider"),
modelId: exact(candidate.model_id, "rf_detr_large_native_kb4:1", "M4.8Q model"),
preprocessId: exact(
candidate.preprocess_id,
"raw-kb4-uint8-fused-mask-rgb-pad8-imagenet-trt/v0",
"M4.8Q preprocess",
),
minimumScore: exact(candidate.minimum_score, 0.25, "M4.8Q threshold"),
},
execution: {
effectiveWorldStateFps: number(execution.effective_world_state_fps, "M4.8Q FPS"),
worldStateCompletionP95Ms: number(
execution.world_state_completion_p95_ms,
"M4.8Q world-state p95",
),
detectorTotalP95Ms: number(execution.detector_total_p95_ms, "M4.8Q detector p95"),
gpuUtilizationP95Percent: number(
execution.gpu_utilization_p95_percent,
"M4.8Q GPU p95",
),
gpuMemoryMaximumMib: number(
execution.gpu_memory_used_maximum_mib,
"M4.8Q VRAM maximum",
),
additionalInferencePasses: exact(
execution.additional_inference_passes,
0,
"M4.8Q inference passes",
),
},
selection: {
caseCount: 24,
minimumSequenceSeparation: integer(
selection.minimum_sequence_separation,
"M4.8Q case separation",
),
bucketCoverage: numberRecord(selection.selected_bucket_coverage, "M4.8Q bucket coverage"),
classCounts: numberRecord(selection.selected_class_counts, "M4.8Q class counts"),
},
runtime: {
deliveryRatio: number(runtime.delivery_ratio, "M4.8Q delivery ratio"),
integratedGatePassed: exact(
runtime.integrated_runtime_gate_passed,
true,
"M4.8Q integrated gate",
),
operatingTargetGatePassed: exact(
runtime.operating_target_gate_passed,
true,
"M4.8Q target gate",
),
},
parity: {
precision: number(parity.risk_detection_precision, "M4.8Q parity precision"),
recall: number(parity.risk_detection_recall, "M4.8Q parity recall"),
meanIou: number(parity.matched_mean_iou, "M4.8Q parity IoU"),
},
acceptance: {
reviewReady: true,
independentQualityEvaluated: false,
semanticCandidateAccepted: false,
},
review: { cases },
method: method(raw.method),
limitations: array(raw.limitations, "M4.8Q limitations").map((item) =>
text(item, "M4.8Q limitation")
),
};
}
export async function fetchM48TRiskQualityResult(
resultId: string,
{
@@ -313,7 +601,7 @@ export async function fetchM48TRiskQualityResult(
signal,
}: { fetcher?: LaboratoryFetch; signal?: AbortSignal } = {},
): Promise<M48TRiskQualityResult> {
if (!/^m48t-risk-quality-temporal-lab-[a-f0-9]{64}$/.test(resultId)) {
if (!/^(?:m48t-risk-quality-temporal-lab|m48q-native-risk-quality-lab)-[a-f0-9]{64}$/.test(resultId)) {
throw new M48TContractError("M4.8T result identity недопустима.");
}
const response = await fetcher(`/api/v1/laboratory/m48t/risk-quality/results/${resultId}`, {
@@ -322,5 +610,9 @@ export async function fetchM48TRiskQualityResult(
signal,
});
if (!response.ok) throw new M48TContractError(`M4.8T недоступен: HTTP ${response.status}.`);
return parseResult(await response.json(), resultId);
const payload: unknown = await response.json();
const raw = object(payload, "M4.8T/M4.8Q result");
return raw.schema_version === "missioncore.m48q-native-risk-quality-view/v1"
? parseNativeResult(payload, resultId)
: parseLegacyResult(payload, resultId);
}
@@ -44,6 +44,7 @@ import { M4ReplayThreatResultView } from "./M4ReplayThreatResult";
import { M47ReferenceGraphResultView } from "./M47ReferenceGraphResult";
import { M48ObjectCentricQualityResultView } from "./M48ObjectCentricQualityResult";
import { M48SmallStaticPassageRegressionResultView } from "./M48SmallStaticPassageRegressionResult";
import { M48StaticOccupancyQualificationResultView } from "./M48StaticOccupancyQualificationResult";
import { M48SFixedClassDetectorResultView } from "./M48SFixedClassDetectorResult";
import { M48TRiskQualityResultView } from "./M48TRiskQualityResult";
@@ -94,6 +95,9 @@ export function AdvancedLaboratoryResult({
if (workId === "m48-small-static-passage-regression" && results.m48SmallStatic) {
return <M48SmallStaticPassageRegressionResultView rigLabel={rigLabel} result={results.m48SmallStatic} />;
}
if (workId === "m48-static-occupancy-qualification" && results.m48StaticOccupancy) {
return <M48StaticOccupancyQualificationResultView rigLabel={rigLabel} result={results.m48StaticOccupancy} />;
}
if (workId === "m48s-fixed-class-detector" && results.m48s) {
return <M48SFixedClassDetectorResultView rigLabel={rigLabel} result={results.m48s} />;
}
@@ -0,0 +1,91 @@
import { useEffect, useMemo, useState } from "react";
import { Icon } from "@nodedc/ui-react";
import { fetchM47ReferenceGraphLab, type M47ReferenceGraphLabResult } from "../../core/laboratory/m47ReferenceGraph";
import {
fetchM48StaticOccupancyCases,
type M48StaticOccupancyCase,
type M48StaticOccupancyQualificationResult,
} from "../../core/laboratory/m48StaticOccupancyQualification";
import {
M4ReplayThreatVisual,
type M4ReplayThreatReviewAnchor,
} from "./M4ReplayThreatVisual";
function message(error: unknown): string {
return error instanceof Error && error.message.trim()
? error.message
: "Каноническое graph evidence M4.8R2 недоступно.";
}
export function M48StaticOccupancyQualificationEvidence({
result,
}: {
result: M48StaticOccupancyQualificationResult;
}) {
const [graph, setGraph] = useState<M47ReferenceGraphLabResult | null>(null);
const [cases, setCases] = useState<readonly M48StaticOccupancyCase[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const controller = new AbortController();
setLoading(true);
setError(null);
void Promise.all([
fetchM47ReferenceGraphLab({
resultId: result.referenceGraphLabResultId,
signal: controller.signal,
}),
fetchM48StaticOccupancyCases(result.resultId, { signal: controller.signal }),
])
.then(([nextGraph, nextCases]) => {
if (controller.signal.aborted) return;
if (nextCases.some((item) => item.sequence < 1 || item.sequence > nextGraph.frames.expected)) {
throw new Error("M4.8R2 anchor вышел за immutable timeline Canonical Reference Graph.");
}
setGraph(nextGraph);
setCases(nextCases);
})
.catch((caught: unknown) => {
if (!controller.signal.aborted) setError(message(caught));
})
.finally(() => {
if (!controller.signal.aborted) setLoading(false);
});
return () => controller.abort();
}, [result.referenceGraphLabResultId, result.resultId]);
const reviewAnchors = useMemo<readonly M4ReplayThreatReviewAnchor[]>(() => (
cases.map((item) => ({
id: item.anchorId,
sourceSequence: item.sequence - 1,
extentXyxyNormalized: item.extentXyxy,
matchedAtThreshold: item.candidateQualified,
}))
), [cases]);
if (loading) {
return (
<div className="l3-visual-audit__state" role="status">
<span className="busy-indicator" aria-hidden="true" />
<span>Открываем M4.7 graph и M4.8R2 static anchors</span>
</div>
);
}
if (error || !graph) {
return (
<div className="l3-visual-audit__state" role="alert">
<Icon name="alert" size={18} />
<span>{error ?? "Canonical Reference Graph не связан с M4.8R2."}</span>
</div>
);
}
return (
<M4ReplayThreatVisual
resultId={graph.visual.resultId}
semantic={{ resultId: graph.semantic.resultId, taxonomy: graph.semantic.taxonomy }}
reviewAnchors={reviewAnchors}
/>
);
}
@@ -0,0 +1,85 @@
import {
LaboratoryEvidence,
LaboratoryResultSummary,
LaboratorySummary,
LaboratoryWorkTemplate,
} from "../../components/laboratory/LaboratoryPresentation";
import type { M48StaticOccupancyQualificationResult } from "../../core/laboratory/m48StaticOccupancyQualification";
import { M48StaticOccupancyQualificationEvidence } from "./M48StaticOccupancyQualificationEvidence";
function percent(value: number): string {
return `${(value * 100).toLocaleString("ru-RU", { maximumFractionDigits: 1 })}%`;
}
export function M48StaticOccupancyQualificationResultView({
rigLabel,
result,
}: {
rigLabel: string;
result: M48StaticOccupancyQualificationResult;
}) {
const nearReady = result.decision.criticalNearCandidateReadyForShadow;
const status = nearReady
? "0–8 м: кандидат закрыл все assisted-якоря; готов к Worker shadow"
: "0–8 м: статическая occupancy ещё не закрыта";
return (
<LaboratoryWorkTemplate
summary={(
<LaboratorySummary
title="M4.8R2 · консервативная static occupancy"
description="RF-DETR не изменяется. Отдельный детерминированный прогон проверяет, удерживает ли current/rolling LiDAR низкие полусферы, столбы и другие безымянные ограничения, и оценивает уже вычисляемый CPU-признак low-step как additive occupied-only слой."
status={status}
statusTone={nearReady ? "success" : "warning"}
facts={[
{ label: "Конфигурация", value: `${rigLabel} RIGHT · Canonical Reference Graph · VIDEO/CAMERA/3D/PLAN/SEMANTICS` },
{ label: "Пайплайн", value: result.pipelineId },
{ label: "Прогон", value: `${result.runLabel} · immutable ${result.resultId}` },
{ label: "Нагрузка", value: "CPU-only geometry · 0 дополнительных detector inference" },
{ label: "Authority", value: "REPLAY-SIMULATED · free-space/commands/actuation OFF" },
]}
brief={{
question: "Не превратятся ли близкие полусферы, столбы и другие статические ограничения в пропуск только потому, что камера не знает их название?",
approach: `На ${result.metrics.operatorStaticAnchorCount} существующих operator-assisted static anchors принятую current/rolling occupancy сравнили с additive low-step evidence. Отдельно сохранены четыре канонических hemisphere-якоря кадров 1880/2584.`,
principalResult: `Принятый граф покрывает ${result.metrics.baselineQualifiedCount}/${result.metrics.operatorStaticAnchorCount}; additive кандидат — ${result.metrics.candidateQualifiedCount}/${result.metrics.operatorStaticAnchorCount}. В критической зоне 0–8 м: ${percent(result.metrics.criticalNearCandidateRecall)}.`,
limitation: "Это assisted diagnostic, а не independent truth. Кандидат пока не включён в Worker и может увеличить ложную занятость; требуются полный shadow-прогон, FPS и occupancy-volume gate.",
}}
method={{
completeness: "complete",
executionClass: "deterministic",
pipelineId: result.pipelineId,
components: [
{ kind: "source", name: result.referenceGraphLabResultId, version: "accepted M4.7", role: "immutable current/rolling occupied/unknown + threat graph", identitySha256: result.referenceGraphLabResultId.split("-").at(-1) ?? null },
{ kind: "source", name: result.smallStaticResultId, version: "M4.8R1 assisted seed", role: "static avoidance anchors · not independent truth", identitySha256: result.smallStaticResultId.split("-").at(-1) ?? null },
{ kind: "algorithm", name: "low-step occupied-only candidate", version: "v1", role: "additive CPU geometry; never clearing", identitySha256: result.resultId.split("-").at(-1) ?? null },
],
}}
/>
)}
evidence={(
<LaboratoryEvidence eyebrow="M4.8R2 VISUAL EVIDENCE · CANONICAL REFERENCE GRAPH" title="Те же CAMERA/3D/PLAN, 11 static anchors и неизменённый M4.7 timeline" kind="recorded-replay" resizable>
<M48StaticOccupancyQualificationEvidence result={result} />
</LaboratoryEvidence>
)}
result={(
<LaboratoryResultSummary
title="Что дал прогон: локализован лёгкий геометрический слой для близких препятствий"
status={status}
statusTone={nearReady ? "success" : "warning"}
metrics={[
{ label: "Current graph", value: `${result.metrics.baselineQualifiedCount}/${result.metrics.operatorStaticAnchorCount}`, hint: `${percent(result.metrics.criticalNearBaselineRecall)} в 0–8 м` },
{ label: "+ low-step candidate", value: `${result.metrics.candidateQualifiedCount}/${result.metrics.operatorStaticAnchorCount}`, hint: `${percent(result.metrics.criticalNearCandidateRecall)} в 0–8 м` },
{ label: "8–12 м", value: percent(result.metrics.approachCandidateRecall), hint: `${result.metrics.approachAnchorCount} assisted anchors · ещё не gate` },
{ label: "False free", value: result.metrics.falseFreeCount.toLocaleString("ru-RU"), hint: `${result.metrics.canonicalEngineeringAnchorCount}/${result.metrics.canonicalEngineeringAnchorCount} canonical anchors retained` },
]}
conclusion={{
proved: `На замороженном assisted seed additive low-step evidence поднял покрытие близких static anchors до ${percent(result.metrics.criticalNearCandidateRecall)} без дополнительной нейросети и без единого free-space утверждения.`,
notProved: "Не доказаны independent precision/recall, приемлемый рост консервативной occupancy, realtime Worker FPS после интеграции, физический clearance и collision safety.",
decision: nearReady
? "Интегрировать low-step только как occupied/unknown Worker shadow. Затем прогнать все 4 489 кадров и принять по FPS, росту компонентов, отсутствию capacity drops и повторному static-anchor gate."
: "Не интегрировать в Worker до исправления близких пропусков.",
}}
/>
)}
/>
);
}
@@ -4,7 +4,11 @@ import {
LaboratorySummary,
LaboratoryWorkTemplate,
} from "../../components/laboratory/LaboratoryPresentation";
import type { M48TRiskQualityResult } from "../../core/laboratory/m48tRiskQuality";
import type {
M48QNativeRiskQualityResult,
M48TLegacyRiskQualityResult,
M48TRiskQualityResult,
} from "../../core/laboratory/m48tRiskQuality";
import { M48TRiskQualityVisual } from "./M48TRiskQualityVisual";
function percent(value: number, digits = 1): string {
@@ -21,6 +25,19 @@ export function M48TRiskQualityResultView({
}: {
rigLabel: string;
result: M48TRiskQualityResult;
}) {
if (result.variant === "native-risk-review") {
return <M48QNativeRiskQualityResultView rigLabel={rigLabel} result={result} />;
}
return <M48TLegacyRiskQualityResultView rigLabel={rigLabel} result={result} />;
}
function M48TLegacyRiskQualityResultView({
rigLabel,
result,
}: {
rigLabel: string;
result: M48TLegacyRiskQualityResult;
}) {
return (
<LaboratoryWorkTemplate
@@ -77,3 +94,69 @@ export function M48TRiskQualityResultView({
/>
);
}
function M48QNativeRiskQualityResultView({
rigLabel,
result,
}: {
rigLabel: string;
result: M48QNativeRiskQualityResult;
}) {
const classes = Object.entries(result.selection.classCounts)
.map(([name, count]) => `${name} ${count}`)
.join(" · ");
return (
<LaboratoryWorkTemplate
summary={(
<LaboratorySummary
title="M4.8Q · native raw-fisheye risk review"
description="Нативный RF-DETR прогнан внутри полного reference graph прямо на исходном KB4 raster 800×600: без rectification, warp, resize и обратного преобразования. Из immutable frame ledger детерминированно отобраны реальные risk-кейсы для операторской проверки в существующем M4.8 image-case instrument."
status="Runtime принят · 24 native cases готовы · quality ещё не adjudicated"
statusTone="success"
facts={[
{ label: "Source", value: `${rigLabel} · ${result.source.frameCount.toLocaleString("ru-RU")} raw frames · 800×600` },
{ label: "Candidate", value: `${result.candidate.modelId} · score ≥ ${decimal(result.candidate.minimumScore, 2)}` },
{ label: "Image path", value: "RAW KB4 → fused GPU graph · geometric resampling NO" },
{ label: "Authority", value: "SHADOW ONLY · independent quality NO · production NO" },
]}
brief={{
question: "Работает ли нативная risk-классификация на нашей исходной fisheye-картинке в realtime envelope, и какие реальные кадры надо проверить человеком?",
approach: `Полный ${result.source.frameCount.toLocaleString("ru-RU")}-кадровый native graph оставлен неизменным. Повторной инференс-сессии для лабы нет: 24 кадра выбраны из его hash-bound ledger по person, animal, light-road-user, vehicle, low-confidence, fisheye-edge и расхождениям с диагностической legacy 704 веткой.`,
principalResult: `${decimal(result.execution.effectiveWorldStateFps, 3)} FPS при detector p95 ${decimal(result.execution.detectorTotalP95Ms, 2)} ms и world-state p95 ${decimal(result.execution.worldStateCompletionP95Ms, 2)} ms. В review pack реально попали ${classes}.`,
limitation: "Это диагностическая выборка маршрута без независимой разметки. Наличие бокса и класса можно осмотреть, но precision/recall и корректность каждого класса этой фазой ещё не доказаны.",
}}
method={result.method}
/>
)}
evidence={(
<LaboratoryEvidence
eyebrow="M4.8Q VISUAL EVIDENCE · NATIVE RAW KB4"
title="24 исходных fisheye-кадра с отключаемым client-side overlay"
kind="diagnostic-model"
resizable
>
<M48TRiskQualityVisual result={result} />
</LaboratoryEvidence>
)}
result={(
<LaboratoryResultSummary
title="Native runtime закрыт; следующий честный шаг — adjudication этих кейсов"
status="Review-ready · quality-not-adjudicated"
statusTone="success"
metrics={[
{ label: "Full graph", value: `${decimal(result.execution.effectiveWorldStateFps, 3)} FPS`, hint: `delivery ${percent(result.runtime.deliveryRatio, 2)} · 4 489/4 489` },
{ label: "Detector / world-state p95", value: `${decimal(result.execution.detectorTotalP95Ms, 2)} / ${decimal(result.execution.worldStateCompletionP95Ms, 2)} ms`, hint: "один native pass · additional inference 0" },
{ label: "GPU / VRAM peak", value: `${decimal(result.execution.gpuUtilizationP95Percent, 1)}% / ${decimal(result.execution.gpuMemoryMaximumMib / 1024, 2)} GiB`, hint: "Worker 006 · RTX 4090 envelope" },
{ label: "Native parity", value: `${percent(result.parity.precision, 2)} / ${percent(result.parity.recall, 2)}`, hint: `precision / recall · mean IoU ${percent(result.parity.meanIou, 2)}` },
{ label: "Review pack", value: `${result.selection.caseCount}/24 cases`, hint: "8 diagnostic buckets · raw 800×600" },
]}
conclusion={{
proved: `Полный reference graph доставил все ${result.source.frameCount.toLocaleString("ru-RU")} world states на ${decimal(result.execution.effectiveWorldStateFps, 3)} FPS. Детектор использовал ровно один native 800×600 KB4 pass без геометрического resampling. Hash-bound review содержит person, dog, bicycle, skateboard, car и truck; боксы рисуются поверх чистого кадра и отключаются кнопкой.`,
notProved: "Не доказаны route-domain precision/recall, истинность 24 классов и боксов, child/adult, поведение объектов, физическая track identity и безопасность навигации. Legacy 704 count delta остаётся только диагностикой, потому что старая ветка растягивала 4:3 raster.",
decision: "Не добавлять второй detector и не менять realtime graph. Использовать эти 24 кейса как вход существующего M4.8 review/correction workflow; только после независимой adjudication считать route-domain semantic quality.",
}}
/>
)}
/>
);
}
@@ -1,18 +1,35 @@
import { useState } from "react";
import { useMemo, useState } from "react";
import { Icon, IconButton } from "@nodedc/ui-react";
import { LaboratoryEvidenceViewer } from "../../components/laboratory/LaboratoryEvidenceViewer";
import type { M48TRiskQualityResult } from "../../core/laboratory/m48tRiskQuality";
import { RecordedEvidenceImageScene } from "../../components/laboratory/RecordedEvidenceImageScene";
import type {
RecordedEvidenceBox,
RecordedEvidenceBoxTone,
} from "../../components/laboratory/RecordedEvidenceBoxOverlay";
import type {
M48QNativeRiskQualityResult,
M48QRiskFamily,
M48TLegacyRiskQualityResult,
M48TRiskQualityResult,
} from "../../core/laboratory/m48tRiskQuality";
export function M48TRiskQualityVisual({ result }: { result: M48TRiskQualityResult }) {
function navigateIndex(current: number, offset: -1 | 1, length: number): number {
return (current + offset + length) % length;
}
function familyTone(family: M48QRiskFamily): RecordedEvidenceBoxTone {
if (family === "person" || family === "animal") return "danger";
if (family === "light-road-user") return "warning";
return "accent";
}
function LegacyVisual({ result }: { result: M48TLegacyRiskQualityResult }) {
const [index, setIndex] = useState(0);
const [expanded, setExpanded] = useState(false);
const item = result.review.cases[index] ?? null;
const navigate = (offset: -1 | 1) => {
setIndex((current) => (
current + offset + result.review.cases.length
) % result.review.cases.length);
};
const navigate = (offset: -1 | 1) =>
setIndex((current) => navigateIndex(current, offset, result.review.cases.length));
return (
<div className="l3-visual-audit">
@@ -61,3 +78,85 @@ export function M48TRiskQualityVisual({ result }: { result: M48TRiskQualityResul
</div>
);
}
function NativeVisual({ result }: { result: M48QNativeRiskQualityResult }) {
const [index, setIndex] = useState(0);
const [expanded, setExpanded] = useState(false);
const [boxesVisible, setBoxesVisible] = useState(true);
const item = result.review.cases[index] ?? null;
const boxes = useMemo<readonly RecordedEvidenceBox[]>(() => {
if (!item || !boxesVisible) return [];
return item.proposals.map((proposal) => ({
boxXyxy: proposal.boxXyxy,
label: `${proposal.className} · ${proposal.score.toFixed(2)}`,
tone: familyTone(proposal.riskFamily),
}));
}, [boxesVisible, item]);
const navigate = (offset: -1 | 1) =>
setIndex((current) => navigateIndex(current, offset, result.review.cases.length));
return (
<div className="l3-visual-audit">
<LaboratoryEvidenceViewer
label="M4.8Q native raw-fisheye risk review"
mode="native"
modes={[{ value: "native", label: "NATIVE RF-DETR" }]}
expanded={expanded}
onModeChange={() => undefined}
onExpandedChange={setExpanded}
actions={(
<div className="l3-visual-audit__pagination">
<IconButton label="Предыдущий M4.8Q review case" onClick={() => navigate(-1)}>
<Icon name="chevron-left" size={16} />
</IconButton>
<IconButton label="Следующий M4.8Q review case" onClick={() => navigate(1)}>
<Icon name="chevron-right" size={16} />
</IconButton>
</div>
)}
trailingActions={(
<IconButton
label={boxesVisible ? "Скрыть native RF-DETR боксы" : "Показать native RF-DETR боксы"}
onClick={() => setBoxesVisible((visible) => !visible)}
>
<Icon name={boxesVisible ? "eye-off" : "eye"} size={16} />
</IconButton>
)}
overlay={item ? (
<div className="l3-visual-audit__overlay">
<div>
<span>RAVNOVES00 · raw KB4 800×600 · resampling NO</span>
<strong>
case {index + 1}/{result.review.cases.length} · frame {item.sequence} · {item.proposals.length} native boxes
</strong>
<small>
{item.selectionBuckets.join(" · ")} · native/legacy {item.nativeDetectionCount}/{item.legacyDetectionCount} (diagnostic only)
</small>
</div>
</div>
) : null}
>
{item ? (
<RecordedEvidenceImageScene
src={item.imageUrl}
imageWidth={item.width}
imageHeight={item.height}
boxes={boxes}
ariaLabel={`M4.8Q frame ${item.sequence}: ${boxes.length} visible native risk boxes`}
/>
) : (
<div className="l3-visual-audit__state" role="alert">
<Icon name="alert" size={18} />
M4.8Q native visual evidence недоступно.
</div>
)}
</LaboratoryEvidenceViewer>
</div>
);
}
export function M48TRiskQualityVisual({ result }: { result: M48TRiskQualityResult }) {
return result.variant === "native-risk-review"
? <NativeVisual result={result} />
: <LegacyVisual result={result} />;
}
@@ -77,6 +77,13 @@ const KNOWN_WORKS: Readonly<Record<Exclude<LaboratoryWorkId, `session:${string}`
experimentName: "M4.8 · small static passage regression",
variantName: "M4.8R1 · Worker 006 small-static assisted baseline",
},
"m48-static-occupancy-qualification": {
profileId: "rig-dual-evidence-virtual-corridor-v1",
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Canonical Reference Graph`,
experimentId: "m48-static-occupancy-qualification",
experimentName: "M4.8 · conservative static occupancy qualification",
variantName: "M4.8R2 · current/rolling + low-step occupied-only candidate",
},
"m48s-fixed-class-detector": {
profileId: "rig-ravnoves-perception-gate-v1",
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · RAVNOVES00 perception gate`,
@@ -86,10 +93,10 @@ const KNOWN_WORKS: Readonly<Record<Exclude<LaboratoryWorkId, `session:${string}`
},
"m48t-risk-quality-temporal": {
profileId: "rig-ravnoves-perception-gate-v1",
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · COCO quality + bounded temporal identity`,
profileName: (rigLabel) => `${rig(rigLabel)} RIGHT · Native raw-fisheye perception gate`,
experimentId: "m48t-risk-quality-temporal",
experimentName: "RF-DETR independent semantic quality and temporal identity",
variantName: "M4.8T · COCO val2017 truth + RAVNOVES00 temporal shadow",
experimentName: "RF-DETR native risk review and temporal identity",
variantName: "M4.8Q · native raw KB4 review · quality not adjudicated",
},
"m47-reference-graph-shadow": {
profileId: "rig-dual-evidence-virtual-corridor-v1",
@@ -21,6 +21,7 @@ function mergeResults(
m47Graph: next.m47Graph ?? current.m47Graph,
m48: next.m48 ?? current.m48,
m48SmallStatic: next.m48SmallStatic ?? current.m48SmallStatic,
m48StaticOccupancy: next.m48StaticOccupancy ?? current.m48StaticOccupancy,
m48s: next.m48s ?? current.m48s,
m48t: next.m48t ?? current.m48t,
m4Threat: next.m4Threat ?? current.m4Threat,
@@ -120,6 +121,7 @@ export function useAdvancedLaboratoryCatalog({
"m47-reference-graph-shadow",
"m48-object-centric-quality",
"m48-small-static-passage-regression",
"m48-static-occupancy-qualification",
].includes(selectedWorkId)
&& !indexedResultId
) return;
@@ -0,0 +1,172 @@
import assert from "node:assert/strict";
import { after, before, test } from "node:test";
import { readFile } from "node:fs/promises";
import { createServer } from "vite";
let server;
let fetchM48TRiskQualityResult;
const resultId = `m48q-native-risk-quality-lab-${"a".repeat(64)}`;
before(async () => {
server = await createServer({
appType: "custom",
logLevel: "silent",
server: { middlewareMode: true },
});
({ fetchM48TRiskQualityResult } = await server.ssrLoadModule(
"/src/core/laboratory/m48tRiskQuality.ts",
));
});
after(async () => server?.close());
function response(value) {
return { ok: true, status: 200, json: async () => value };
}
function payload() {
return {
schema_version: "missioncore.m48q-native-risk-quality-view/v1",
variant: "native-risk-review",
result_id: resultId,
created_at_utc: "2026-08-26T10:00:00Z",
status: "complete-review-ready-quality-not-adjudicated",
access: "read-only",
ground_truth: false,
source: {
source_id: "RAVNOVES00",
frame_count: 4489,
raster_width: 800,
raster_height: 600,
geometric_resampling: false,
rectification: false,
warp: false,
},
configuration: {
candidate: {
provider_id: "triton-rf-detr-large-coco-native-kb4-risk-fp16-shadow/v0",
model_id: "rf_detr_large_native_kb4:1",
preprocess_id: "raw-kb4-uint8-fused-mask-rgb-pad8-imagenet-trt/v0",
minimum_score: 0.25,
},
},
method: {
schema_version: "missioncore.laboratory-method/v1",
completeness: "complete",
execution_class: "hybrid",
pipeline_id: "m48q-native-raw-fisheye-risk-case-review/v1",
components: [{
kind: "model",
name: "RF-DETR-L native KB4 TensorRT",
version: "rf_detr_large_native_kb4:1",
role: "risk proposals",
identity_sha256: "b".repeat(64),
}],
},
execution: {
effective_world_state_fps: 11.84338,
world_state_completion_p95_ms: 47.940779,
detector_total_p95_ms: 21.19895,
gpu_utilization_p95_percent: 53,
gpu_memory_used_maximum_mib: 9718,
additional_inference_passes: 0,
},
metrics: {
selection: {
case_count: 24,
minimum_sequence_separation: 12,
selected_bucket_coverage: { person: 22, animal: 3 },
selected_class_counts: { person: 44, dog: 3 },
},
runtime: {
delivery_ratio: 1,
integrated_runtime_gate_passed: true,
operating_target_gate_passed: true,
},
native_tensor_parity: {
risk_detection_precision: 0.9887,
risk_detection_recall: 0.9831,
matched_mean_iou: 0.9882,
},
},
acceptance: {
review_ready: true,
integrated_runtime_gate_passed: true,
independent_quality_evaluated: false,
semantic_candidate_accepted: false,
},
review: {
source_raster: { width: 800, height: 600 },
overlay: { client_rendered: true, toggleable: true },
cases: Array.from({ length: 24 }, (_, index) => {
const caseId = String(index * 20 + 12).padStart(6, "0");
return {
case_id: caseId,
sequence: Number(caseId),
frame_id: `frame-${caseId}`,
evidence_time_ns: 35_000_000_000 + index * 1_000_000,
image_url: `/review/${caseId}.jpg`,
media_type: "image/jpeg",
width: 800,
height: 600,
byte_length: 1000 + index,
sha256: String(index.toString(16)).padStart(64, "0"),
geometric_resampling: false,
selection_buckets: [index % 2 ? "person" : "animal"],
comparison: {
native_detection_count: 1,
legacy_704_detection_count: 1,
matched_detection_count_iou_at_least_0_5: 1,
},
proposals: [{
proposal_id: `proposal-${index}-0`,
class_name: index % 2 ? "person" : "dog",
risk_family: index % 2 ? "person" : "animal",
score: 0.75,
box_xyxy: [10, 20, 100, 200],
}],
};
}),
},
limitations: ["No independent route truth."],
};
}
test("M4.8Q parser accepts only the native 800x600 no-resampling review contract", async () => {
const result = await fetchM48TRiskQualityResult(resultId, {
fetcher: async () => response(payload()),
});
assert.equal(result.variant, "native-risk-review");
assert.equal(result.review.cases.length, 24);
assert.equal(result.review.cases[0].width, 800);
assert.equal(result.review.cases[0].proposals[0].className, "dog");
assert.equal(result.execution.additionalInferencePasses, 0);
assert.equal(result.acceptance.independentQualityEvaluated, false);
});
test("M4.8Q parser fails closed if raw-fisheye geometry is resampled", async () => {
const invalid = payload();
invalid.source.geometric_resampling = true;
await assert.rejects(
fetchM48TRiskQualityResult(resultId, {
fetcher: async () => response(invalid),
}),
/source resampling/,
);
});
test("M4.8Q reuses the canonical image scene and viewer overlay toggle", async () => {
const source = await readFile(
new URL("../src/workspaces/laboratory/M48TRiskQualityVisual.tsx", import.meta.url),
"utf8",
);
assert.match(source, /<LaboratoryEvidenceViewer/);
assert.match(source, /<RecordedEvidenceImageScene/);
assert.match(source, /name=\{boxesVisible \? "eye-off" : "eye"\}/);
assert.match(source, /raw KB4 800×600 · resampling NO/);
assert.doesNotMatch(source, /<canvas/);
});
@@ -0,0 +1,10 @@
{
"schema_version": "missioncore.laboratory-evidence-definition/v1",
"work_id": "m48-static-occupancy-qualification",
"evidence": {
"runtime_relative_root": "m48/static-occupancy-qualification-results",
"result_id_prefix": "m48-static-occupancy-qualification",
"document_name": "manifest.json",
"schema_version": "missioncore.m48-static-occupancy-qualification-result/v1"
}
}
@@ -1,10 +1,20 @@
{
"schema_version": "missioncore.laboratory-evidence-definition/v1",
"schema_version": "missioncore.laboratory-evidence-definition/v2",
"work_id": "m48t-risk-quality-temporal",
"evidence": {
"runtime_relative_root": "m48t-risk-quality/lab-results",
"result_id_prefix": "m48t-risk-quality-temporal-lab",
"document_name": "manifest.json",
"schema_version": "missioncore.m48t-risk-quality-temporal-lab/v1"
}
"evidence_lifecycle": [
{
"phase": "legacy-quality",
"runtime_relative_root": "m48t-risk-quality/lab-results",
"result_id_prefix": "m48t-risk-quality-temporal-lab",
"document_name": "manifest.json",
"schema_version": "missioncore.m48t-risk-quality-temporal-lab/v1"
},
{
"phase": "result",
"runtime_relative_root": "m48t-risk-quality/native-lab-results",
"result_id_prefix": "m48q-native-risk-quality-lab",
"document_name": "manifest.json",
"schema_version": "missioncore.m48q-native-risk-quality-lab/v1"
}
]
}
+20
View File
@@ -1,6 +1,26 @@
{
"schema_version": "missioncore.laboratory-execution-registry/v1",
"definitions": [
{
"work_id": "m48-static-occupancy-qualification",
"lifecycle": "canonical",
"isolation": "core-adapter",
"adapter_id": "canonical.m48-static-occupancy-qualification/v1",
"input_roles": [
"repository_root",
"profile_path",
"m47_lab_root",
"graph_result_root",
"small_static_result_root"
],
"contracts": {
"source": "missioncore.m48-static-occupancy-source-set/v1",
"provider": "missioncore.m48-additive-low-step-occupancy/v1",
"graph": "missioncore.m48-static-occupancy-case/v1",
"run": "missioncore.laboratory-run/v1",
"evidence": "missioncore.m48-static-occupancy-qualification-result/v1"
}
},
{
"work_id": "m48-small-static-passage-regression",
"lifecycle": "canonical",
+9 -2
View File
@@ -1,6 +1,6 @@
{
"schema_version": "missioncore.laboratory-value-review-registry/v1",
"reviewed_at_utc": "2026-08-25T11:06:28Z",
"reviewed_at_utc": "2026-08-26T08:34:34Z",
"entries": [
{
"catalog_id": "e28-local-surface",
@@ -247,6 +247,13 @@
"lifecycle": "current",
"visual_evidence": "available"
},
{
"catalog_id": "m48-static-occupancy-qualification",
"evidence_id": "m48-static-occupancy-qualification-568024554cff011332ff19ca4739f70555a6232c0607dec2a71be6db408ea69a",
"signal": "progress",
"lifecycle": "current",
"visual_evidence": "available"
},
{
"catalog_id": "m48s-fixed-class-detector",
"evidence_id": "m48s-fixed-class-detector-lab-4a901d811f53734540337f8d1f2c01666539aa0a9b7786f26d4f1f2e08cc858a",
@@ -256,7 +263,7 @@
},
{
"catalog_id": "m48t-risk-quality-temporal",
"evidence_id": "m48t-risk-quality-temporal-lab-ed5355fe0adb9b18942d75aff2362d79190b9e864f070ebe7a1c15fccbc0fbfb",
"evidence_id": "m48q-native-risk-quality-lab-e8961d4db8ffb751503b9646bc8eeebec6c80c948ce2f5b4fa5b89c471e673c1",
"signal": "progress",
"lifecycle": "current",
"visual_evidence": "available"
@@ -0,0 +1,56 @@
{
"schema_version": "missioncore.m48-static-occupancy-qualification-profile/v1",
"profile_id": "m48-conservative-static-occupancy/v1",
"pipeline_id": "m4-current-rolling-plus-step-static-occupancy/v1",
"experiment_id": "m48-static-occupancy-qualification/v1",
"human_lab_id": "M4.8",
"run_label": "M4.8R2",
"source": {
"source_id": "RAVNOVES00",
"source_session_id": "20260720T065719Z_viewer_live",
"m47_lab_result_id": "m47-reference-graph-lab-49678f0a7c628c7e991af0964fa57d005baa027d2d1eea19f38bbfe27ed39ce5",
"m47_graph_result_id": "m47-reference-graph-5f6a851cd655c7cf07c3025dacadbc188018b0afa97eda3a08802266e12da87d",
"m47_graph_frames_sha256": "d2cd53f8cff555410959600a79eb9a101aad4a8009ba87bdd0f3c5f122948071",
"small_static_result_id": "m48-small-static-passage-regression-3e3a2001f87fd3adcb736de52a65e42515044d83faa3515f892705b40915c084",
"small_static_anchors_sha256": "6a317aa75dde8204d5574a56166bebc9347e8797934dbc82f076a0abfdfaa95a"
},
"selection": {
"motion": "static",
"requires_avoidance_or_clearance": true,
"canonical_engineering_sequences": [1880, 2584],
"independent_truth": false
},
"distance_bands_m": {
"critical_near": [0.0, 8.0],
"approach": [8.0, 12.0]
},
"candidate": {
"point_sources": ["local-surface-occupied", "local-surface-step-candidate"],
"minimum_points": 2,
"minimum_voxels": 1,
"voxel_size_m": 0.35,
"depth_cluster_minimum_gap_m": 0.65,
"depth_cluster_gap_fraction": 0.08,
"spatial_cluster_radius_m": 0.75
},
"acceptance": {
"minimum_critical_near_candidate_recall": 1.0,
"minimum_approach_candidate_recall": 0.95,
"minimum_canonical_engineering_recall": 1.0,
"maximum_false_free_count": 0
},
"policy": {
"absence_of_points_means_free": false,
"absence_of_camera_detection_means_free": false,
"step_candidate_can_only_add_occupied_or_unknown": true,
"semantic_class_used": false,
"planner_authoritative_free_space_claimed": false
},
"authority": {
"mode": "replay-simulated",
"physical_live": false,
"commands_enabled": false,
"actuation_allowed": false,
"navigation_or_safety_accepted": false
}
}
@@ -0,0 +1,58 @@
{
"schema_version": "missioncore.m48q-native-risk-case-mining-profile/v1",
"profile_id": "m48q-ravnoves00-native-raw-kb4-risk-review/v1",
"question": "Which real RAVNOVES00 raw-fisheye frames expose the native RF-DETR risk semantics that require operator review before independent route truth exists?",
"source": {
"source_id": "RAVNOVES00",
"frame_count": 4489,
"raster_width": 800,
"raster_height": 600,
"video_sha256": "cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8",
"geometric_resampling": false,
"rectification": false,
"warp": false
},
"candidate": {
"provider_id": "triton-rf-detr-large-coco-native-kb4-risk-fp16-shadow/v0",
"model_id": "rf_detr_large_native_kb4:1",
"preprocess_id": "raw-kb4-uint8-fused-mask-rgb-pad8-imagenet-trt/v0",
"engine_sha256": "b8a40b3580edff001ec9680de68707242294ff590ab296000fae371f1083f695",
"minimum_score": 0.25
},
"risk_families": {
"person": ["person"],
"animal": ["bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe"],
"light-road-user": ["bicycle", "motorcycle", "skateboard"],
"vehicle": ["car", "bus", "truck"]
},
"selection": {
"case_count": 24,
"minimum_sequence_separation": 12,
"low_confidence_maximum_score": 0.4,
"fisheye_edge_margin_fraction": 0.12,
"bucket_quotas": {
"person": 3,
"animal": 3,
"light-road-user": 3,
"vehicle": 3,
"low-confidence": 3,
"fisheye-edge": 3,
"native-fewer-than-legacy": 3,
"native-more-than-legacy": 3
}
},
"scope": {
"quality_evaluated": false,
"ground_truth": false,
"candidate_accepted": false,
"production_accepted": false,
"purpose": "bounded-native-risk-case-review"
},
"authority": {
"ground_truth": false,
"candidate_accepted": false,
"commands_enabled": false,
"actuation_allowed": false,
"navigation_or_safety_accepted": false
}
}
@@ -912,6 +912,17 @@ authority.
Exit: local collision-space quality and deadline gates pass in replay and
shadow. This still does not authorize control.
M4.8R2 now supplies the bounded pre-shadow qualification for the first item.
On eleven operator-assisted static passage anchors, the accepted current/rolling
graph covers `6/11`, while the additive sealed low-step signal covers `10/11`;
the critical `0–8 m` subset is `9/9`, four canonical engineering anchors remain
matched and false-free count is zero. The item remains unchecked because this
is not independent truth and the candidate is not yet part of the Worker
pipeline. Its next gate is a full `4,489`-frame occupied-only Worker 006 shadow
with FPS, latency, occupancy growth, component-count and capacity-drop bounds.
Dynamic decay, Nav2 publication and planner-authoritative free space remain
separate later work.
### L6 — alternative odometry/mapping
This stage starts only when a source supplies unregistered sensor scans. Add
@@ -179,6 +179,13 @@ only on the annotated frame unless a separately evidenced and reviewable
tracking result exists; ordinary model proposals and graph layers continue on
their own full recorded timeline.
M4.8R2 is the canonical static-occupancy example of this rule. Its report and
eleven typed anchors bind to the accepted M4.7 LAB identity, use the same
`VIDEO/CAMERA/3D/PLAN/SEMANTICS` timeline and add no renderer or transport. A
qualified anchor means the additive occupied-only candidate has LiDAR support
inside that exact reviewed camera extent; it does not turn the extent into a 3D
collider or grant clearance, free-space, navigation or safety authority.
A third perception instrument is a product-surface change. It requires explicit
product-owner agreement before implementation and cannot be introduced by a LAB
adapter, result component or experiment configuration.
@@ -1445,6 +1445,65 @@ configuration, dataset release, metrics and ONNX identity; only then is a
candidate loaded through the existing Triton seam and measured by a new
append-only M4.8R run plus an independent validation gate.
### 2026-08-26 — M4.8Q native raw-fisheye risk review ready
The terminal phase of the existing `m48t-risk-quality-temporal` work is now the
content-addressed M4.8Q result
`m48q-native-risk-quality-lab-e8961d4db8ffb751503b9646bc8eeebec6c80c948ce2f5b4fa5b89c471e673c1`.
It replaces neither the historical M4.8T evidence nor either admitted M4 viewer.
The result projects `24` deterministic diagnostic cases into the existing M4.8
image-case review instrument, with source-pixel boxes rendered by the client and
an explicit clean-image toggle. The JPEG review derivatives retain the exact
`800×600` raster geometry; rectification, warp and geometric resampling are all
false. Boxes are not baked into the images.
Worker 006 selected the cases from the immutable full native reference-graph
ledger without another inference pass. The selection covers person, animal,
light-road-user, vehicle, low-confidence, fisheye-edge and both directions of
native-versus-legacy count divergence, with at least 12 source frames between
selected cases. The source graph delivered all `4,489/4,489` frames at
`11.84338 FPS`; detector p95 was `21.19895 ms`, world-state completion p95 was
`47.940779 ms`, GPU utilization p95 was `53%`, and maximum used GPU memory was
`9,718 MiB`. The isolated case-mining container was removed after execution and
the canonical Triton predecessor was verified healthy and unchanged.
This closes evidence preparation, not semantic quality. The cases are
diagnostic samples rather than independent route truth; native-versus-legacy
count differences are not a verdict because the legacy `704×704` path stretches
the raw 4:3 image. Accordingly `review_ready=true`, while ground truth,
candidate acceptance, production acceptance, navigation, safety, commands and
actuation authority remain false. The next action is operator adjudication in
the existing M4.8 review instrument.
### 2026-08-26 — M4.8R2 conservative static-occupancy qualification
M4.8R2 moves the small-static problem out of semantic detector tuning and into
the existing LiDAR occupancy boundary. RF-DETR, native fisheye input and its
risk taxonomy are unchanged. The deterministic qualification consumes the
accepted M4.7 current/rolling graph plus the frozen M4.8R1 operator-assisted
static anchors. It evaluates one already sealed local-surface signal,
`point_step_candidate`, only as additive occupied-or-unknown evidence. It never
clears a cell, claims free space, starts detector inference or uses the GPU.
Immutable result
`m48-static-occupancy-qualification-568024554cff011332ff19ca4739f70555a6232c0607dec2a71be6db408ea69a`
contains `11` static passage anchors. The accepted graph qualifies `6/11`; the
additive low-step candidate qualifies `10/11`. In the critical `0–8 m` band the
change is `6/9 → 9/9`; in the `8–12 m` approach band it is `0/2 → 1/2`. All
four existing canonical engineering anchors remain matched and the result
contains zero false-free claims. One approach anchor remains explicitly
`unresolved-unknown-never-free`.
This is candidate-visible development evidence, not independent truth or a
production cutover. The result accepts only a bounded next action: integrate
the low-step contribution as an occupied-only Worker shadow and replay all
`4,489` frames on Worker 006 while measuring effective FPS, stage latency,
occupancy/component growth, capacity drops and the same static anchors. The LAB
reuses the M4.7 `VIDEO/CAMERA/3D/PLAN/SEMANTICS` viewer and projects the eleven
anchors onto its immutable timeline; no third perception instrument exists.
Navigation, commands, actuation, physical clearance and collision-safety
authority remain false.
## Implementation order
The implementation sequence is intentionally strict:
@@ -0,0 +1,677 @@
#!/usr/bin/env python3
"""Mine bounded native raw-fisheye risk cases from immutable Worker 006 ledgers."""
from __future__ import annotations
import argparse
import hashlib
import json
import math
import sys
from collections import Counter
from collections.abc import Iterable, Mapping, Sequence
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Final
PROFILE_SCHEMA: Final = "missioncore.m48q-native-risk-case-mining-profile/v1"
RESULT_SCHEMA: Final = "missioncore.m48q-native-risk-case-mining-result/v1"
CASE_SCHEMA: Final = "missioncore.m48q-native-risk-review-case/v1"
GRAPH_FRAME_SCHEMA: Final = "missioncore.m48s-reference-graph-frame-evidence/v1"
COMPARISON_FRAME_SCHEMA: Final = "missioncore.m48n-native-vs-704-frame/v0"
FALSE_AUTHORITY: Final = {
"ground_truth": False,
"candidate_accepted": False,
"commands_enabled": False,
"actuation_allowed": False,
"navigation_or_safety_accepted": False,
}
class M48QCaseMiningError(RuntimeError):
"""Raised when immutable native review evidence is inconsistent."""
@dataclass(frozen=True, slots=True)
class Proposal:
proposal_id: str
class_name: str
risk_family: str
score: float
box_xyxy: tuple[float, float, float, float]
@dataclass(frozen=True, slots=True)
class FrameCandidate:
sequence: int
frame_id: str
evidence_time_ns: int
proposals: tuple[Proposal, ...]
native_count: int
legacy_count: int
matched_count: int
buckets: frozenset[str]
def canonical_json(value: object) -> bytes:
return json.dumps(
value,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
).encode("utf-8")
def sha256_path(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def _read_object(path: Path) -> dict[str, Any]:
try:
value: object = json.loads(path.read_text("utf-8"))
except (OSError, json.JSONDecodeError) as exc:
raise M48QCaseMiningError(f"cannot read JSON object: {path.name}") from exc
if not isinstance(value, dict):
raise M48QCaseMiningError(f"JSON evidence is not an object: {path.name}")
return value
def _verify_hash(path: Path, expected: str, label: str) -> str:
actual = sha256_path(path)
if actual != expected:
raise M48QCaseMiningError(f"{label} SHA-256 changed: {actual}")
return actual
def _risk_family_map(profile: Mapping[str, Any]) -> dict[str, str]:
raw = profile.get("risk_families")
if not isinstance(raw, dict):
raise M48QCaseMiningError("risk family profile is invalid")
result: dict[str, str] = {}
for family, classes in raw.items():
if (
family not in {"person", "animal", "light-road-user", "vehicle"}
or not isinstance(classes, list)
or not classes
):
raise M48QCaseMiningError("risk family profile changed")
for class_name in classes:
if not isinstance(class_name, str) or class_name in result:
raise M48QCaseMiningError("risk classes are invalid or duplicated")
result[class_name] = family
return result
def _proposal(
value: object,
*,
sequence: int,
profile: Mapping[str, Any],
families: Mapping[str, str],
) -> Proposal:
if not isinstance(value, dict):
raise M48QCaseMiningError("detector proposal is not an object")
candidate = profile["candidate"]
expected_frame_id = f"frame-{sequence:06d}"
if (
value.get("frame_id") != expected_frame_id
or value.get("provider_id") != candidate["provider_id"]
or value.get("model_id") != candidate["model_id"]
or value.get("preprocess_id") != candidate["preprocess_id"]
):
raise M48QCaseMiningError("native detector proposal identity changed")
proposal_id = value.get("proposal_id")
class_name = value.get("semantic_hint")
score = value.get("objectness")
region = value.get("region")
if (
not isinstance(proposal_id, str)
or not isinstance(class_name, str)
or class_name not in families
or not isinstance(score, (float, int))
or isinstance(score, bool)
or not math.isfinite(float(score))
or float(score) < candidate["minimum_score"]
or not isinstance(region, dict)
):
raise M48QCaseMiningError("native detector proposal contract changed")
coordinates = tuple(region.get(key) for key in ("x_min", "y_min", "x_max", "y_max"))
if not all(
isinstance(item, (float, int)) and not isinstance(item, bool) and math.isfinite(float(item))
for item in coordinates
):
raise M48QCaseMiningError("native detector box is invalid")
left, top, right, bottom = (float(item) for item in coordinates)
source = profile["source"]
if not (
0 <= left < right <= source["raster_width"] and 0 <= top < bottom <= source["raster_height"]
):
raise M48QCaseMiningError("native detector box escaped the raw source raster")
return Proposal(
proposal_id=proposal_id,
class_name=class_name,
risk_family=families[class_name],
score=float(score),
box_xyxy=(left, top, right, bottom),
)
def load_comparison_rows(path: Path, expected_count: int) -> dict[int, tuple[int, int, int]]:
rows: dict[int, tuple[int, int, int]] = {}
try:
with path.open("r", encoding="utf-8") as stream:
for line_number, line in enumerate(stream, start=1):
value = json.loads(line)
if not isinstance(value, dict):
raise M48QCaseMiningError("comparison frame is not an object")
if value.get("schema_version") not in {None, COMPARISON_FRAME_SCHEMA}:
raise M48QCaseMiningError("comparison frame schema changed")
sequence = value.get("frame_index")
counts = tuple(
value.get(key)
for key in (
"native_detection_count",
"baseline_detection_count",
"matched_detection_count_iou_at_least_0_5",
)
)
if (
not isinstance(sequence, int)
or isinstance(sequence, bool)
or sequence in rows
or not all(
isinstance(item, int) and not isinstance(item, bool) and item >= 0
for item in counts
)
):
raise M48QCaseMiningError(f"comparison frame {line_number} is invalid")
rows[sequence] = counts
except (OSError, json.JSONDecodeError) as exc:
raise M48QCaseMiningError("comparison frame ledger cannot be read") from exc
if set(rows) != set(range(expected_count)):
raise M48QCaseMiningError("comparison frame ledger is incomplete")
return rows
def _case_buckets(
proposals: Sequence[Proposal],
*,
native_count: int,
legacy_count: int,
profile: Mapping[str, Any],
) -> frozenset[str]:
selection = profile["selection"]
buckets = {item.risk_family for item in proposals}
if any(item.score <= selection["low_confidence_maximum_score"] for item in proposals):
buckets.add("low-confidence")
width = profile["source"]["raster_width"]
height = profile["source"]["raster_height"]
margin = selection["fisheye_edge_margin_fraction"]
if any(
item.box_xyxy[0] <= width * margin
or item.box_xyxy[2] >= width * (1 - margin)
or item.box_xyxy[1] <= height * margin
or item.box_xyxy[3] >= height * (1 - margin)
for item in proposals
):
buckets.add("fisheye-edge")
if native_count < legacy_count:
buckets.add("native-fewer-than-legacy")
elif native_count > legacy_count:
buckets.add("native-more-than-legacy")
return frozenset(buckets)
def load_graph_candidates(
path: Path,
*,
profile: Mapping[str, Any],
comparisons: Mapping[int, tuple[int, int, int]],
) -> list[FrameCandidate]:
families = _risk_family_map(profile)
expected_count = profile["source"]["frame_count"]
candidates: list[FrameCandidate] = []
try:
with path.open("r", encoding="utf-8") as stream:
for sequence, line in enumerate(stream):
value = json.loads(line)
if not isinstance(value, dict) or value.get("schema_version") != GRAPH_FRAME_SCHEMA:
raise M48QCaseMiningError("graph frame schema changed")
source = value.get("source_envelope")
raw_proposals = value.get("detector_proposals")
if (
not isinstance(source, dict)
or source.get("sequence") != sequence
or source.get("frame_id") != f"frame-{sequence:06d}"
or not isinstance(raw_proposals, list)
or value.get("authority") != FALSE_AUTHORITY
):
raise M48QCaseMiningError("graph frame identity or authority changed")
timestamps = source.get("timestamps")
evidence_time_ns = (
timestamps.get("source_ns") if isinstance(timestamps, dict) else None
)
if (
not isinstance(evidence_time_ns, int)
or isinstance(evidence_time_ns, bool)
or evidence_time_ns < 0
):
raise M48QCaseMiningError("graph frame evidence time is invalid")
proposals = tuple(
_proposal(item, sequence=sequence, profile=profile, families=families)
for item in raw_proposals
)
native_count, legacy_count, matched_count = comparisons[sequence]
if len(proposals) != native_count:
raise M48QCaseMiningError("native graph/comparison detector count changed")
buckets = _case_buckets(
proposals,
native_count=native_count,
legacy_count=legacy_count,
profile=profile,
)
candidates.append(
FrameCandidate(
sequence=sequence,
frame_id=source["frame_id"],
evidence_time_ns=evidence_time_ns,
proposals=proposals,
native_count=native_count,
legacy_count=legacy_count,
matched_count=matched_count,
buckets=buckets,
)
)
except (OSError, json.JSONDecodeError) as exc:
raise M48QCaseMiningError("graph frame ledger cannot be read") from exc
if len(candidates) != expected_count:
raise M48QCaseMiningError("graph frame ledger is incomplete")
return candidates
def _quantile_order(items: Sequence[FrameCandidate]) -> Iterable[FrameCandidate]:
if not items:
return ()
indexes: list[int] = []
left = 0
right = len(items) - 1
while left <= right:
middle = (left + right) // 2
indexes.append(middle)
if middle - left > 0:
indexes.append((left + middle - 1) // 2)
if right - middle > 0:
indexes.append((middle + 1 + right) // 2)
left += 1
right -= 1
seen: set[int] = set()
return (items[index] for index in indexes if not (index in seen or seen.add(index)))
def select_cases(
candidates: Sequence[FrameCandidate],
*,
bucket_quotas: Mapping[str, int],
minimum_sequence_separation: int,
) -> list[FrameCandidate]:
selected: list[FrameCandidate] = []
selected_sequences: set[int] = set()
for bucket, quota in bucket_quotas.items():
eligible = [item for item in candidates if bucket in item.buckets]
admitted = 0
for item in _quantile_order(eligible):
if item.sequence in selected_sequences:
continue
if any(
abs(item.sequence - prior.sequence) < minimum_sequence_separation
for prior in selected
):
continue
selected.append(item)
selected_sequences.add(item.sequence)
admitted += 1
if admitted == quota:
break
if admitted != quota:
raise M48QCaseMiningError(
f"selection bucket {bucket} produced {admitted}/{quota} separated cases"
)
expected = sum(bucket_quotas.values())
if len(selected) != expected:
raise M48QCaseMiningError("selected case count changed")
return sorted(selected, key=lambda item: item.sequence)
def render_selected_frames(
*,
video_path: Path,
selected: Sequence[FrameCandidate],
cases_root: Path,
width: int,
height: int,
) -> dict[int, dict[str, object]]:
import av
from av.error import FFmpegError
from PIL import Image
wanted = {item.sequence for item in selected}
rendered: dict[int, dict[str, object]] = {}
cases_root.mkdir(mode=0o700, parents=True, exist_ok=False)
try:
with av.open(str(video_path), mode="r") as container:
streams = list(container.streams.video)
if len(streams) != 1:
raise M48QCaseMiningError("RAVNOVES00 video stream contract changed")
for sequence, frame in enumerate(container.decode(streams[0])):
if sequence not in wanted:
continue
array = frame.to_ndarray(format="rgb24")
if array.shape != (height, width, 3):
raise M48QCaseMiningError("decoded raw-fisheye raster changed")
name = f"frame-{sequence:06d}.jpg"
path = cases_root / name
Image.fromarray(array, mode="RGB").save(
path,
format="JPEG",
quality=94,
subsampling=0,
optimize=False,
)
rendered[sequence] = {
"path": f"cases/{name}",
"media_type": "image/jpeg",
"width": width,
"height": height,
"byte_length": path.stat().st_size,
"sha256": sha256_path(path),
"geometric_resampling": False,
}
if len(rendered) == len(wanted):
break
except (FFmpegError, OSError) as exc:
raise M48QCaseMiningError("RAVNOVES00 raw-fisheye frames cannot be decoded") from exc
if set(rendered) != wanted:
raise M48QCaseMiningError("not every selected raw-fisheye frame was decoded")
return rendered
def _case_document(
candidate: FrameCandidate,
*,
image: Mapping[str, object],
) -> dict[str, object]:
return {
"schema_version": CASE_SCHEMA,
"case_id": f"{candidate.sequence:06d}",
"sequence": candidate.sequence,
"frame_id": candidate.frame_id,
"evidence_time_ns": candidate.evidence_time_ns,
"selection_buckets": sorted(candidate.buckets),
"comparison": {
"native_detection_count": candidate.native_count,
"legacy_704_detection_count": candidate.legacy_count,
"matched_detection_count_iou_at_least_0_5": candidate.matched_count,
"quality_interpretation": "diagnostic-only",
},
"image": dict(image),
"proposals": [
{
"proposal_id": item.proposal_id,
"class_name": item.class_name,
"risk_family": item.risk_family,
"score": round(item.score, 9),
"box_xyxy": [round(value, 6) for value in item.box_xyxy],
}
for item in candidate.proposals
],
"ground_truth": False,
"quality_evaluated": False,
"authority": dict(FALSE_AUTHORITY),
}
def run(args: argparse.Namespace) -> dict[str, object]:
for path in (
args.profile,
args.graph_result,
args.graph_frames,
args.comparison_result,
args.comparison_frames,
args.video,
):
if path.is_symlink() or not path.is_file():
raise M48QCaseMiningError(f"required evidence is missing: {path.name}")
profile_sha256 = _verify_hash(args.profile, args.expected_profile_sha256, "profile")
graph_result_sha256 = _verify_hash(
args.graph_result, args.expected_graph_result_sha256, "graph result"
)
graph_frames_sha256 = _verify_hash(
args.graph_frames, args.expected_graph_frames_sha256, "graph frames"
)
comparison_result_sha256 = _verify_hash(
args.comparison_result,
args.expected_comparison_result_sha256,
"comparison result",
)
comparison_frames_sha256 = _verify_hash(
args.comparison_frames,
args.expected_comparison_frames_sha256,
"comparison frames",
)
video_sha256 = _verify_hash(args.video, args.expected_video_sha256, "video")
runner_sha256 = _verify_hash(Path(__file__), args.expected_runner_sha256, "runner")
profile = _read_object(args.profile)
graph_result = _read_object(args.graph_result)
comparison_result = _read_object(args.comparison_result)
source = profile.get("source")
candidate = profile.get("candidate")
selection = profile.get("selection")
scope = profile.get("scope")
if (
profile.get("schema_version") != PROFILE_SCHEMA
or not isinstance(source, dict)
or source.get("video_sha256") != video_sha256
or source.get("raster_width") != 800
or source.get("raster_height") != 600
or source.get("frame_count") != 4489
or source.get("geometric_resampling") is not False
or source.get("rectification") is not False
or source.get("warp") is not False
or not isinstance(candidate, dict)
or candidate.get("engine_sha256")
!= "b8a40b3580edff001ec9680de68707242294ff590ab296000fae371f1083f695"
or not isinstance(selection, dict)
or selection.get("case_count") != 24
or not isinstance(selection.get("bucket_quotas"), dict)
or sum(selection["bucket_quotas"].values()) != 24
or scope
!= {
"quality_evaluated": False,
"ground_truth": False,
"candidate_accepted": False,
"production_accepted": False,
"purpose": "bounded-native-risk-case-review",
}
or profile.get("authority") != FALSE_AUTHORITY
):
raise M48QCaseMiningError("M4.8Q profile contract changed")
if (
graph_result.get("schema_version") != "missioncore.m48s-reference-graph-shadow-load/v5"
or graph_result.get("completed") is not True
or graph_result.get("identity", {}).get("detector_provider_id") != candidate["provider_id"]
or graph_result.get("identity", {}).get("inputs", {}).get("video") != video_sha256
or graph_result.get("execution", {}).get("frame_evidence", {}).get("sha256")
!= graph_frames_sha256
or graph_result.get("authority") != FALSE_AUTHORITY
or graph_result.get("production_accepted") is not False
):
raise M48QCaseMiningError("native graph result contract changed")
if (
comparison_result.get("schema_version") != "missioncore.m48n-native-vs-704-ravnoves00/v0"
or comparison_result.get("completed") is not True
or comparison_result.get("source", {}).get("video_sha256") != video_sha256
or comparison_result.get("source", {}).get("frame_count") != source["frame_count"]
or comparison_result.get("execution", {}).get("frames_sha256") != comparison_frames_sha256
or comparison_result.get("authority") != FALSE_AUTHORITY
):
raise M48QCaseMiningError("native/legacy comparison result contract changed")
output_root = args.output_root
if output_root.exists():
raise M48QCaseMiningError("M4.8Q output root already exists")
output_root.mkdir(mode=0o700, parents=True)
comparisons = load_comparison_rows(args.comparison_frames, source["frame_count"])
candidates = load_graph_candidates(
args.graph_frames,
profile=profile,
comparisons=comparisons,
)
selected = select_cases(
candidates,
bucket_quotas=selection["bucket_quotas"],
minimum_sequence_separation=selection["minimum_sequence_separation"],
)
rendered = render_selected_frames(
video_path=args.video,
selected=selected,
cases_root=output_root / "cases",
width=source["raster_width"],
height=source["raster_height"],
)
cases = [
_case_document(
item,
image=rendered[item.sequence],
)
for item in selected
]
cases_path = output_root / "cases.jsonl"
with cases_path.open("xb") as stream:
for case in cases:
stream.write(canonical_json(case) + b"\n")
class_counts = Counter(proposal.class_name for item in selected for proposal in item.proposals)
selected_bucket_coverage = Counter(bucket for item in selected for bucket in item.buckets)
identity = {
"schema_version": RESULT_SCHEMA,
"profile": {"profile_id": profile["profile_id"], "sha256": profile_sha256},
"source": {
"source_id": source["source_id"],
"video_sha256": video_sha256,
"graph_result_sha256": graph_result_sha256,
"graph_frames_sha256": graph_frames_sha256,
"comparison_result_sha256": comparison_result_sha256,
"comparison_frames_sha256": comparison_frames_sha256,
},
"candidate": dict(candidate),
"runner_sha256": runner_sha256,
"cases_sha256": sha256_path(cases_path),
"authority": dict(FALSE_AUTHORITY),
}
result: dict[str, object] = {
"schema_version": RESULT_SCHEMA,
"status": "complete-review-ready-quality-not-adjudicated",
"completed": True,
"worker": {"worker_id": "worker-006", "node": "DESKTOP-OPJ8J04"},
"identity": identity,
"report_identity_sha256": hashlib.sha256(canonical_json(identity)).hexdigest(),
"source": {
**dict(source),
"graph_result_sha256": graph_result_sha256,
"graph_frames_sha256": graph_frames_sha256,
"comparison_result_sha256": comparison_result_sha256,
"comparison_frames_sha256": comparison_frames_sha256,
},
"candidate": dict(candidate),
"selection": {
"case_count": len(cases),
"minimum_sequence_separation": selection["minimum_sequence_separation"],
"configured_bucket_quotas": selection["bucket_quotas"],
"selected_bucket_coverage": dict(sorted(selected_bucket_coverage.items())),
"selected_sequences": [item.sequence for item in selected],
"selected_class_counts": dict(sorted(class_counts.items())),
},
"artifacts": {
"cases": {
"path": "cases.jsonl",
"schema_version": CASE_SCHEMA,
"row_count": len(cases),
"sha256": sha256_path(cases_path),
},
"images": {
"root": "cases",
"count": len(rendered),
"geometric_resampling": False,
},
},
"decision": {
"quality_evaluated": False,
"ground_truth": False,
"candidate_accepted": False,
"production_accepted": False,
"next_action": "operator-adjudication-in-existing-m48-review-instrument",
},
"limitations": [
"The selected RAVNOVES00 cases are diagnostic samples, not independent truth.",
(
"Native-versus-legacy detection-count differences are not quality "
"verdicts because legacy 704 stretches the raw 4:3 raster."
),
(
"No child/adult, behavior, physical track identity, navigation or "
"actuation claim is made."
),
(
"JPEG review derivatives preserve the 800x600 raster without geometric "
"resampling but are not lossless source frames."
),
],
"authority": dict(FALSE_AUTHORITY),
}
(output_root / "result.json").write_bytes(canonical_json(result) + b"\n")
return result
def parse_args(argv: Sequence[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
for name in (
"profile",
"graph-result",
"graph-frames",
"comparison-result",
"comparison-frames",
"video",
"output-root",
):
parser.add_argument(f"--{name}", type=Path, required=True)
for name in (
"profile",
"graph-result",
"graph-frames",
"comparison-result",
"comparison-frames",
"video",
"runner",
):
parser.add_argument(f"--expected-{name}-sha256", required=True)
return parser.parse_args(argv)
def main(argv: Sequence[str] | None = None) -> int:
try:
result = run(parse_args(argv))
except M48QCaseMiningError as exc:
print(f"M4.8Q case mining refused: {exc}", file=sys.stderr)
return 2
print(json.dumps(result, ensure_ascii=False, sort_keys=True))
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,39 @@
#!/usr/bin/env python3
"""Publish the immutable M4.8Q native raw-fisheye review LAB result."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from k1link.laboratory.m48q_native_risk_quality_lab import (
build_m48q_native_risk_quality_lab,
)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--repository-root", type=Path, required=True)
parser.add_argument("--output-root", type=Path, required=True)
arguments = parser.parse_args()
result = build_m48q_native_risk_quality_lab(
repository_root=arguments.repository_root,
output_root=arguments.output_root,
)
print(
json.dumps(
{
"result_id": result.result_id,
"result_root": str(result.result_root),
"status": result.manifest["status"],
},
ensure_ascii=False,
sort_keys=True,
)
)
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,207 @@
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ReleaseRoot,
[Parameter(Mandatory = $true)]
[ValidatePattern("^[A-Za-z0-9._-]{1,96}$")]
[string]$RunId,
[string]$OutputRoot = "D:\NDC_MISSIONCORE\runtime\results\m48q-native-risk-case-mining"
)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
function Assert-LastExitCode([string]$Operation) {
if ($LASTEXITCODE -ne 0) { throw "$Operation failed with exit code $LASTEXITCODE" }
}
function Get-Sha256([string]$Path) {
return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
}
function Resolve-DDirectory([string]$Path, [string]$Label, [bool]$Create) {
if ($Create -and -not (Test-Path -LiteralPath $Path)) {
$null = New-Item -ItemType Directory -Path $Path
}
$item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
if (
-not $item.PSIsContainer -or
($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -or
[IO.Path]::GetPathRoot($item.FullName).TrimEnd("\") -ine "D:"
) {
throw "$Label must be a real D: directory"
}
return $item.FullName
}
function Assert-RegularFile([string]$Path, [string]$Label) {
$item = Get-Item -LiteralPath (Resolve-Path -LiteralPath $Path).Path -Force
if ($item.PSIsContainer -or ($item.Attributes -band [IO.FileAttributes]::ReparsePoint)) {
throw "$Label must be a regular file"
}
return $item.FullName
}
function Convert-ToDockerPath([string]$Path) { return $Path.Replace("\", "/") }
function Get-Container([string]$Name) {
$rows = @((& docker inspect $Name) | ConvertFrom-Json)
Assert-LastExitCode "Docker inspection for $Name"
if ($rows.Count -ne 1) { throw "Container identity for $Name is not unique" }
return $rows[0]
}
if ($env:COMPUTERNAME -cne "DESKTOP-OPJ8J04") {
throw "M4.8Q native risk case mining is pinned to DESKTOP-OPJ8J04"
}
$release = Resolve-DDirectory $ReleaseRoot "M4.8Q release root" $false
$output = Resolve-DDirectory $OutputRoot "M4.8Q output root" $true
$runOutput = Join-Path $output $RunId
if (Test-Path -LiteralPath $runOutput) { throw "M4.8Q output already exists" }
$runner = Assert-RegularFile (
Join-Path $release "run_m48q_native_risk_case_mining_worker.py"
) "M4.8Q runner"
$profile = Assert-RegularFile (
Join-Path $release "m48q-native-risk-case-mining-v1.json"
) "M4.8Q profile"
$runnerSha256 = Get-Sha256 $runner
$profileSha256 = Get-Sha256 $profile
if ($runnerSha256 -cne "39bb1d810b167d6e97dcb091505b52d4a812d69419dcb32fe23ea5d14d605d67") {
throw "M4.8Q runner SHA-256 changed"
}
if ($profileSha256 -cne "c455055e63578d505edc80b66d67e795916a3d0297cc18bfee5a6af7b032ceda") {
throw "M4.8Q profile SHA-256 changed"
}
$graphRoot = Resolve-DDirectory (
"D:\NDC_MISSIONCORE\runtime\results\m48n-native-reference-graph-shadow\ravnoves00-full-12fps-v0"
) "M4.8Q graph evidence root" $false
$comparisonRoot = Resolve-DDirectory (
"D:\NDC_MISSIONCORE\runtime\results\m48n-native-vs-704\ravnoves00-full-v0"
) "M4.8Q comparison evidence root" $false
$graphResult = Assert-RegularFile (Join-Path $graphRoot "result.json") "graph result"
$graphFrames = Assert-RegularFile (Join-Path $graphRoot "frames.jsonl") "graph frames"
$comparisonResult = Assert-RegularFile (Join-Path $comparisonRoot "result.json") "comparison result"
$comparisonFrames = Assert-RegularFile (Join-Path $comparisonRoot "frames.jsonl") "comparison frames"
$video = Assert-RegularFile (
"D:\NDC_MISSIONCORE\runtime\experiments\e46e\inputs\right-cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8.mp4"
) "RAVNOVES00 video"
$graphResultSha256 = Get-Sha256 $graphResult
$graphFramesSha256 = Get-Sha256 $graphFrames
$comparisonResultSha256 = Get-Sha256 $comparisonResult
$comparisonFramesSha256 = Get-Sha256 $comparisonFrames
$videoSha256 = Get-Sha256 $video
if ($graphResultSha256 -cne "c5c3a831b1d1c3271161c91fa5c5c40533eb663ca288ed0220334a147aed6e15") {
throw "M4.8Q graph result SHA-256 changed"
}
if ($graphFramesSha256 -cne "b245af969600670d0975e89cae02b44206e3f1328eff48d5b4639b1b2ab57346") {
throw "M4.8Q graph frame evidence SHA-256 changed"
}
if ($comparisonResultSha256 -cne "fd91c2f1f477038d5af51656d510aba39d69ad2e1a387f15d98ade19dd3a0c49") {
throw "M4.8Q comparison result SHA-256 changed"
}
if ($comparisonFramesSha256 -cne "6a35125d4e003edfd8a33b4239bad0910f137fde3a770e9d5baab721cdc145b2") {
throw "M4.8Q comparison frame evidence SHA-256 changed"
}
if ($videoSha256 -cne "cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8") {
throw "RAVNOVES00 video SHA-256 changed"
}
$media = Resolve-DDirectory (
"D:\NDC_MISSIONCORE\runtime\derived\perception-e15-media-pyav180-lz445-v1"
) "PyAV dependency" $false
$pillow = Resolve-DDirectory (
"D:\NDC_MISSIONCORE\runtime\derived\perception-p0-env-v1"
) "Pillow dependency" $false
$image = (
"nvcr.io/nvidia/tritonserver:26.06-py3@" +
"sha256:58df7489c3f2276f9591d500a012dee03e23d35543ce3c390b4c001e6bf90794"
)
& docker image inspect $image *> $null
Assert-LastExitCode "pinned M4.8Q image inspection"
$canonicalTriton = Get-Container "ndc-mission-core-triton"
if (-not $canonicalTriton.State.Running -or $canonicalTriton.State.Health.Status -cne "healthy") {
throw "Canonical Triton must remain healthy during M4.8Q mining"
}
$canonicalTritonId = [string]$canonicalTriton.Id
$runnerName = "ndc-mission-core-m48q-native-risk-case-mining"
if (& docker ps -a --format "{{.Names}}" --filter "name=^/$runnerName$") {
throw "M4.8Q bounded container already exists"
}
try {
& docker run `
--name $runnerName `
--label "com.nodedc.product=mission-core" `
--label "com.nodedc.stack=ndc-mission-core-compute" `
--label "com.nodedc.role=bounded-native-risk-case-mining" `
--label "com.nodedc.managed-by=codex-bounded-experiment" `
--network none `
--read-only `
--security-opt "no-new-privileges:true" `
--cap-drop ALL `
--pids-limit 128 `
--cpus 4 `
--memory 4g `
--tmpfs "/tmp:rw,noexec,nosuid,size=512m" `
-e "PYTHONDONTWRITEBYTECODE=1" `
-e "PYTHONPATH=/opt/media:/opt/pillow" `
-v ((Convert-ToDockerPath $release) + ":/release:ro") `
-v ((Convert-ToDockerPath $output) + ":/output:rw") `
-v ((Convert-ToDockerPath $media) + ":/opt/media:ro") `
-v ((Convert-ToDockerPath $pillow) + ":/opt/pillow:ro") `
-v ((Convert-ToDockerPath $graphRoot) + ":/evidence/graph:ro") `
-v ((Convert-ToDockerPath $comparisonRoot) + ":/evidence/comparison:ro") `
-v ((Convert-ToDockerPath $video) + ":/source/right.mp4:ro") `
--entrypoint python3 `
$image `
/release/run_m48q_native_risk_case_mining_worker.py `
--profile /release/m48q-native-risk-case-mining-v1.json `
--graph-result /evidence/graph/result.json `
--graph-frames /evidence/graph/frames.jsonl `
--comparison-result /evidence/comparison/result.json `
--comparison-frames /evidence/comparison/frames.jsonl `
--video /source/right.mp4 `
--output-root ("/output/{0}" -f $RunId) `
--expected-profile-sha256 $profileSha256 `
--expected-graph-result-sha256 $graphResultSha256 `
--expected-graph-frames-sha256 $graphFramesSha256 `
--expected-comparison-result-sha256 $comparisonResultSha256 `
--expected-comparison-frames-sha256 $comparisonFramesSha256 `
--expected-video-sha256 $videoSha256 `
--expected-runner-sha256 $runnerSha256
Assert-LastExitCode "M4.8Q native risk case mining"
if (
-not (Test-Path -LiteralPath (Join-Path $runOutput "result.json") -PathType Leaf) -or
-not (Test-Path -LiteralPath (Join-Path $runOutput "cases.jsonl") -PathType Leaf) -or
@(Get-ChildItem -LiteralPath (Join-Path $runOutput "cases") -Filter "*.jpg" -File).Count -ne 24
) {
throw "M4.8Q result artifacts are incomplete"
}
} finally {
if (& docker ps -a --format "{{.Names}}" --filter "name=^/$runnerName$") {
& docker rm -f $runnerName *> $null
}
$canonicalAfter = Get-Container "ndc-mission-core-triton"
if (
[string]$canonicalAfter.Id -cne $canonicalTritonId -or
-not $canonicalAfter.State.Running -or
$canonicalAfter.State.Health.Status -cne "healthy"
) {
throw "Canonical Triton changed during M4.8Q mining"
}
}
$result = Get-Content -LiteralPath (Join-Path $runOutput "result.json") -Raw | ConvertFrom-Json
[pscustomobject]@{
run_id = $RunId
output_root = $runOutput
status = $result.status
case_count = $result.selection.case_count
report_identity_sha256 = $result.report_identity_sha256
canonical_triton = "healthy-and-unchanged"
} | ConvertTo-Json -Depth 4
@@ -0,0 +1,81 @@
#!/usr/bin/env python3
"""Publish one canonical append-only M4.8R2 static-occupancy qualification."""
from __future__ import annotations
import argparse
import json
import socket
from pathlib import Path
from k1link.compute.pipeline_telemetry import JsonlPipelineTelemetrySink
from k1link.laboratory import (
LaboratoryEvidenceRegistry,
LaboratoryExecutionRegistry,
LaboratoryRunner,
LaboratoryRunRequest,
)
def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser()
parser.add_argument("--profile", type=Path, required=True)
parser.add_argument("--m47-lab-root", type=Path, required=True)
parser.add_argument("--graph-result-root", type=Path, required=True)
parser.add_argument("--small-static-result-root", type=Path, required=True)
parser.add_argument("--output-root", type=Path, required=True)
parser.add_argument("--receipt-root", type=Path, required=True)
parser.add_argument("--telemetry-path", type=Path, required=True)
parser.add_argument("--run-id", required=True)
parser.add_argument("--request-id", required=True)
return parser
def main() -> int:
args = _parser().parse_args()
repository_root = Path(__file__).resolve().parents[1]
evidence = LaboratoryEvidenceRegistry.from_directory(
repository_root / "config" / "laboratories"
)
execution = LaboratoryExecutionRegistry.from_file(
repository_root / "config" / "laboratory-execution.json",
evidence,
)
runner = LaboratoryRunner(
registry=execution,
evidence_registry=evidence,
sink=JsonlPipelineTelemetrySink(args.telemetry_path),
)
result = runner.run(
LaboratoryRunRequest(
work_id="m48-static-occupancy-qualification",
run_id=args.run_id,
request_id=args.request_id,
contour_id="mission-core-laboratory",
agent_id="local-control-plane",
node_id=socket.gethostname(),
source_id="RAVNOVES00",
source_package_id=args.m47_lab_root.name,
method_id="m48-conservative-static-occupancy/v1",
inputs={
"repository_root": repository_root,
"profile_path": args.profile,
"m47_lab_root": args.m47_lab_root,
"graph_result_root": args.graph_result_root,
"small_static_result_root": args.small_static_result_root,
},
output_root=args.output_root,
receipt_root=args.receipt_root,
)
)
print(json.dumps({
"result_id": result.result_id,
"result_root": str(result.result_root),
"receipt_id": result.receipt_id,
"receipt_root": str(result.receipt_root),
}, ensure_ascii=False, sort_keys=True))
return 0
if __name__ == "__main__":
raise SystemExit(main())
+24
View File
@@ -312,6 +312,9 @@ class LaboratoryRunner:
def canonical_laboratory_adapters() -> dict[str, LaboratoryAdapter]:
return {
"canonical.m48-static-occupancy-qualification/v1": (
_run_m48_static_occupancy_qualification
),
"canonical.m48-small-static-passage-regression/v1": (
_run_m48_small_static_passage_regression
),
@@ -326,6 +329,27 @@ def canonical_laboratory_adapters() -> dict[str, LaboratoryAdapter]:
}
def _run_m48_static_occupancy_qualification(
request: LaboratoryRunRequest,
) -> LaboratoryAdapterResult:
from k1link.laboratory.m48_static_occupancy_qualification import (
build_m48_static_occupancy_qualification,
)
result = build_m48_static_occupancy_qualification(
repository_root=request.inputs["repository_root"],
profile_path=request.inputs["profile_path"],
m47_lab_root=request.inputs["m47_lab_root"],
graph_result_root=request.inputs["graph_result_root"],
small_static_result_root=request.inputs["small_static_result_root"],
output_root=request.output_root,
)
return LaboratoryAdapterResult(
result_root=result.result_root,
result_id=result.result_id,
)
def _run_m48s_fixed_class_detector(
request: LaboratoryRunRequest,
) -> LaboratoryAdapterResult:
@@ -0,0 +1,754 @@
"""Immutable M4.8R2 qualification of conservative static LiDAR occupancy.
The experiment does not run a detector and does not mutate the accepted M4.7
graph. It measures the accepted current/rolling occupied output on the frozen
operator-assisted small-static anchors, then evaluates one additive CPU-only
candidate already present in the local-surface artifact: low step candidates.
Neither missing evidence nor a camera miss is ever converted to free space.
"""
from __future__ import annotations
import hashlib
import json
import os
import shutil
import uuid
from dataclasses import dataclass, replace
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, Final
import numpy as np
from k1link.laboratory.m47_reference_graph import (
M47ReferenceGraphLabError,
read_m47_reference_graph_lab,
)
from k1link.laboratory.m48_small_static_regression import (
M48SmallStaticRegressionError,
read_m48_small_static_passage_regression,
)
from k1link.perception.geometry import RecordedGeometryStore
from k1link.perception.geometry_math import (
POINT_OCCUPIED,
project_map_points_kb4,
semantic_geometry_support,
)
M48_STATIC_OCCUPANCY_PROFILE_SCHEMA: Final = (
"missioncore.m48-static-occupancy-qualification-profile/v1"
)
M48_STATIC_OCCUPANCY_RESULT_SCHEMA: Final = (
"missioncore.m48-static-occupancy-qualification-result/v1"
)
M48_STATIC_OCCUPANCY_REPORT_SCHEMA: Final = (
"missioncore.m48-static-occupancy-qualification-report/v1"
)
M48_STATIC_OCCUPANCY_CASE_SCHEMA: Final = "missioncore.m48-static-occupancy-case/v1"
M48_STATIC_OCCUPANCY_CANONICAL_SCHEMA: Final = (
"missioncore.m48-static-occupancy-canonical-anchor/v1"
)
M48_STATIC_OCCUPANCY_PREFIX: Final = "m48-static-occupancy-qualification-"
_METHOD_SCHEMA: Final = "missioncore.laboratory-method/v1"
_AUTHORITY: Final = {
"mode": "replay-simulated",
"physical_live": False,
"commands_enabled": False,
"actuation_allowed": False,
"navigation_or_safety_accepted": False,
}
class M48StaticOccupancyQualificationError(RuntimeError):
"""The static-occupancy source, method, or immutable result is invalid."""
@dataclass(frozen=True, slots=True)
class M48StaticOccupancyQualificationResult:
result_id: str
result_root: Path
manifest: dict[str, Any]
report: dict[str, Any]
cases: tuple[dict[str, Any], ...]
canonical_anchors: tuple[dict[str, Any], ...]
def build_m48_static_occupancy_qualification(
*,
repository_root: Path,
profile_path: Path,
m47_lab_root: Path,
graph_result_root: Path,
small_static_result_root: Path,
output_root: Path,
run_created_at_utc: str | None = None,
) -> M48StaticOccupancyQualificationResult:
"""Publish one deterministic, append-only M4.8R2 qualification result."""
repository = repository_root.resolve(strict=True)
profile_bytes, profile = _read_profile(profile_path)
source = _object(profile["source"], "M4.8R2 source")
try:
m47 = read_m47_reference_graph_lab(m47_lab_root)
small_static = read_m48_small_static_passage_regression(small_static_result_root)
except (M47ReferenceGraphLabError, M48SmallStaticRegressionError) as exc:
raise M48StaticOccupancyQualificationError(
"accepted M4.7/M4.8R1 evidence is invalid"
) from exc
if (
m47.result_id != source.get("m47_lab_result_id")
or small_static.result_id != source.get("small_static_result_id")
or m47.manifest.get("accepted") is not True
or m47.manifest.get("ground_truth") is not False
):
raise M48StaticOccupancyQualificationError("M4.8R2 source identity changed")
anchors_path = small_static.result_root / "anchors.jsonl"
if _file_sha256(anchors_path) != source.get("small_static_anchors_sha256"):
raise M48StaticOccupancyQualificationError("M4.8R2 anchor ledger changed")
graph_root = graph_result_root.resolve(strict=True)
graph_manifest = _read_json(graph_root / "manifest.json", maximum=2 * 1024 * 1024)
frames_path = graph_root / "frames.jsonl"
graph_files = _object(graph_manifest.get("files"), "M4.8R2 graph files")
graph_frames = _object(graph_files.get("frames.jsonl"), "M4.8R2 graph frame artifact")
if (
graph_root.name != source.get("m47_graph_result_id")
or graph_manifest.get("result_id") != graph_root.name
or graph_manifest.get("accepted") is not True
or graph_frames.get("sha256") != source.get("m47_graph_frames_sha256")
or _file_sha256(frames_path) != source.get("m47_graph_frames_sha256")
):
raise M48StaticOccupancyQualificationError("M4.8R2 graph binding changed")
selection = _object(profile["selection"], "M4.8R2 selection")
anchors = tuple(
row
for row in small_static.anchors
if row.get("motion") == selection.get("motion")
and row.get("requires_avoidance_or_clearance")
is selection.get("requires_avoidance_or_clearance")
)
if not anchors:
raise M48StaticOccupancyQualificationError("M4.8R2 selected no static anchors")
frame_rows = _selected_graph_frames(frames_path, {int(row["sequence"]) for row in anchors})
store = RecordedGeometryStore.from_repository(repository)
candidate = _object(profile["candidate"], "M4.8R2 candidate")
candidate_association = replace(
store.profile.association,
semantic_minimum_occupied_points=int(candidate["minimum_points"]),
semantic_minimum_occupied_voxels=int(candidate["minimum_voxels"]),
semantic_voxel_size_m=float(candidate["voxel_size_m"]),
depth_cluster_minimum_gap_m=float(candidate["depth_cluster_minimum_gap_m"]),
depth_cluster_gap_fraction=float(candidate["depth_cluster_gap_fraction"]),
spatial_cluster_radius_m=float(candidate["spatial_cluster_radius_m"]),
)
cases: list[dict[str, Any]] = []
for anchor in anchors:
sequence = int(anchor["sequence"])
graph_row = frame_rows[sequence]
frame = store.frame_for_index(sequence)
if frame is None or not frame.surface_valid:
raise M48StaticOccupancyQualificationError(
"selected M4.8R2 anchor lacks qualified current LiDAR"
)
projected = project_map_points_kb4(
frame.points_map,
position_map_xyz=frame.sensor_position_map,
orientation_map_from_lidar_xyzw=frame.sensor_orientation_xyzw,
profile=frame.projection,
)
bbox = _pixel_bbox(anchor["extent_xyxy"], frame.projection.width, frame.projection.height)
baseline = semantic_geometry_support(
bbox,
projected=projected,
frame_points_map=frame.points_map,
point_class=frame.point_class,
profile=store.profile.association,
)
step_candidates = store.point_step_candidates_for_frame(sequence)
if step_candidates is None:
raise M48StaticOccupancyQualificationError(
"selected M4.8R2 anchor lacks low-step evidence"
)
union_classes = np.array(frame.point_class, copy=True)
union_classes[step_candidates > 0] = POINT_OCCUPIED
additive = semantic_geometry_support(
bbox,
projected=projected,
frame_points_map=frame.points_map,
point_class=union_classes,
profile=candidate_association,
)
graph_matches = _graph_component_matches(
graph_row=graph_row,
frame=frame,
bbox=bbox,
voxel_size_m=0.45,
)
raw_depths = _depths_in_bbox(projected.pixels_xy, projected.depths_m, bbox)
distance = _support_distance(
additive.occupied_depths_m, baseline.occupied_depths_m, raw_depths
)
band = _distance_band(distance, _object(profile["distance_bands_m"], "distance bands"))
accepted_graph = bool(graph_matches)
baseline_qualified = bool(baseline.qualified or accepted_graph)
candidate_qualified = bool(additive.qualified or accepted_graph)
false_free = graph_row["obstacle_map"].get("free_space_claimed") is True
cases.append(
{
"schema_version": M48_STATIC_OCCUPANCY_CASE_SCHEMA,
"anchor_id": anchor["anchor_id"],
"clip_id": anchor["clip_id"],
"sequence": sequence,
"extent_xyxy": anchor["extent_xyxy"],
"distance_m": distance,
"distance_band": band,
"accepted_graph": {
"matched": accepted_graph,
"component_count": len(graph_matches),
"components": graph_matches,
"free_space_claimed": false_free,
},
"current_local_surface": _support_projection(baseline),
"additive_step_candidate": _support_projection(additive),
"baseline_qualified": baseline_qualified,
"candidate_qualified": candidate_qualified,
"outcome": (
"candidate-qualified"
if candidate_qualified
else "unresolved-unknown-never-free"
),
"authority": "operator-assisted-development-anchor-not-truth",
}
)
cases.sort(key=lambda row: (int(row["sequence"]), str(row["anchor_id"])))
visual_report = _read_json(
m47.result_root / "visual-report.json",
maximum=2 * 1024 * 1024,
)
canonical = _canonical_anchors(visual_report, selection)
metrics = _metrics(cases, canonical)
acceptance = _object(profile["acceptance"], "M4.8R2 acceptance")
gates = {
"critical_near_candidate_recall": (
metrics["critical_near_candidate_recall"]
>= float(acceptance["minimum_critical_near_candidate_recall"])
),
"approach_candidate_recall": (
metrics["approach_candidate_recall"]
>= float(acceptance["minimum_approach_candidate_recall"])
),
"canonical_engineering_recall": (
metrics["canonical_engineering_recall"]
>= float(acceptance["minimum_canonical_engineering_recall"])
),
"zero_false_free": metrics["false_free_count"]
<= int(acceptance["maximum_false_free_count"]),
"independent_truth_available": False,
}
near_ready = bool(
gates["critical_near_candidate_recall"]
and gates["canonical_engineering_recall"]
and gates["zero_false_free"]
)
accepted = bool(near_ready and gates["approach_candidate_recall"])
created_at = _utc_timestamp(run_created_at_utc or datetime.now(UTC).isoformat())
profile_sha256 = hashlib.sha256(profile_bytes).hexdigest()
producer_sha256 = _file_sha256(Path(__file__).resolve())
identity = {
"schema_version": M48_STATIC_OCCUPANCY_RESULT_SCHEMA,
"human_lab_id": profile["human_lab_id"],
"run_label": profile["run_label"],
"run_created_at_utc": created_at,
"pipeline_id": profile["pipeline_id"],
"experiment_id": profile["experiment_id"],
"profile_id": profile["profile_id"],
"profile_sha256": profile_sha256,
"producer_sha256": producer_sha256,
"source": source,
"selection": {
"operator_static_anchor_count": len(cases),
"canonical_engineering_anchor_count": len(canonical),
},
"authority": dict(_AUTHORITY),
}
result_id = M48_STATIC_OCCUPANCY_PREFIX + _canonical_sha256(identity)
method = {
"schema_version": _METHOD_SCHEMA,
"completeness": "complete",
"execution_class": "deterministic",
"pipeline_id": profile["pipeline_id"],
"components": [
{
"kind": "source",
"name": "accepted M4.7 current/rolling obstacle graph",
"version": source["m47_graph_result_id"],
"role": "immutable baseline occupied/unknown and threat decisions",
"identity_sha256": source["m47_graph_frames_sha256"],
},
{
"kind": "source",
"name": "M4.8R1 operator-assisted static anchors",
"version": source["small_static_result_id"],
"role": "candidate-visible diagnostic anchors; not independent truth",
"identity_sha256": source["small_static_anchors_sha256"],
},
{
"kind": "algorithm",
"name": "additive low-step static occupancy candidate",
"version": profile["profile_id"],
"role": "CPU-only occupied-or-unknown evidence; never clearing",
"identity_sha256": producer_sha256,
},
],
}
report = {
"schema_version": M48_STATIC_OCCUPANCY_REPORT_SCHEMA,
"result_id": result_id,
"source": source,
"configuration": {
key: profile[key]
for key in (
"profile_id",
"pipeline_id",
"experiment_id",
"human_lab_id",
"run_label",
"distance_bands_m",
"candidate",
"acceptance",
"policy",
)
},
"method": method,
"metrics": metrics,
"gates": gates,
"decision": {
"state": "accepted-bounded-static-occupancy-qualification"
if accepted
else "partial-static-occupancy-qualification",
"critical_near_candidate_ready_for_shadow": near_ready,
"production_accepted": False,
"summary": (
"Accepted graph covers "
f"{metrics['baseline_qualified_count']}/{len(cases)} static assisted "
"anchors; the additive step candidate covers "
f"{metrics['candidate_qualified_count']}/{len(cases)}."
),
"next_action": (
"Integrate the additive step evidence as an occupied-only Worker shadow, "
"then measure full replay FPS, occupancy growth and the unresolved 8-12 m "
"case."
),
},
"limitations": [
(
"Operator-assisted anchors are candidate-visible development evidence, "
"not independent truth."
),
"Projected camera rectangles do not define physical 3D colliders or chassis clearance.",
(
"The step candidate may add conservative false occupancy and therefore "
"requires a full replay load/volume shadow before cutover."
),
(
"No ray clearing, planner-authoritative free space, physical navigation, "
"command, actuation or collision-safety authority is granted."
),
],
"authority": dict(_AUTHORITY),
}
destination = output_root.resolve(strict=False) / result_id
_publish_result(destination, identity, created_at, accepted, report, tuple(cases), canonical)
return read_m48_static_occupancy_qualification(destination)
def read_m48_static_occupancy_qualification(
result_root: Path,
) -> M48StaticOccupancyQualificationResult:
if result_root.is_symlink():
raise M48StaticOccupancyQualificationError("M4.8R2 result root is invalid")
root = result_root.resolve(strict=True)
if root.name.startswith(M48_STATIC_OCCUPANCY_PREFIX) is False:
raise M48StaticOccupancyQualificationError("M4.8R2 result root is invalid")
manifest = _read_json(root / "manifest.json", maximum=2 * 1024 * 1024)
report = _read_json(root / "report.json", maximum=4 * 1024 * 1024)
cases = tuple(_read_jsonl(root / "cases.jsonl"))
canonical = tuple(_read_jsonl(root / "canonical-anchors.jsonl"))
if (
manifest.get("schema_version") != M48_STATIC_OCCUPANCY_RESULT_SCHEMA
or manifest.get("result_id") != root.name
or report.get("schema_version") != M48_STATIC_OCCUPANCY_REPORT_SCHEMA
or report.get("result_id") != root.name
or manifest.get("ground_truth") is not False
or manifest.get("authority") != _AUTHORITY
):
raise M48StaticOccupancyQualificationError("M4.8R2 result identity changed")
identity = _object(manifest.get("identity"), "M4.8R2 identity")
identity_sha256 = _canonical_sha256(identity)
if root.name != M48_STATIC_OCCUPANCY_PREFIX + identity_sha256:
raise M48StaticOccupancyQualificationError("M4.8R2 result identity changed")
artifacts = manifest.get("artifacts")
if not isinstance(artifacts, list):
raise M48StaticOccupancyQualificationError("M4.8R2 artifact proof changed")
artifact_paths = [
str(_object(item, "M4.8R2 artifact").get("path")) for item in artifacts
]
if sorted(artifact_paths) != [
"canonical-anchors.jsonl",
"cases.jsonl",
"report.json",
]:
raise M48StaticOccupancyQualificationError("M4.8R2 artifact proof changed")
for artifact in artifacts:
item = _object(artifact, "M4.8R2 artifact")
path = root / str(item.get("path"))
if path.parent != root or _file_sha256(path) != item.get("sha256"):
raise M48StaticOccupancyQualificationError("M4.8R2 artifact proof changed")
if manifest.get("identity_sha256") != identity_sha256:
raise M48StaticOccupancyQualificationError("M4.8R2 identity digest changed")
if not cases or any(
row.get("schema_version") != M48_STATIC_OCCUPANCY_CASE_SCHEMA for row in cases
):
raise M48StaticOccupancyQualificationError("M4.8R2 case ledger changed")
if any(
row.get("schema_version") != M48_STATIC_OCCUPANCY_CANONICAL_SCHEMA
for row in canonical
):
raise M48StaticOccupancyQualificationError("M4.8R2 canonical ledger changed")
return M48StaticOccupancyQualificationResult(
root.name, root, manifest, report, cases, canonical
)
def _support_projection(value: Any) -> dict[str, object]:
depths = value.occupied_depths_m
return {
"qualified": bool(value.qualified),
"projected_point_count": int(value.projected_points_in_region),
"occupied_point_count": int(value.occupied_points_in_region),
"clustered_occupied_point_count": int(value.occupied_source_indices.size),
"nearest_depth_m": None if not depths.size else round(float(np.min(depths)), 6),
"median_depth_m": None if not depths.size else round(float(np.median(depths)), 6),
}
def _graph_component_matches(
*,
graph_row: dict[str, Any],
frame: Any,
bbox: tuple[float, float, float, float],
voxel_size_m: float,
) -> list[dict[str, object]]:
obstacle_map = _object(graph_row.get("obstacle_map"), "M4.8R2 obstacle map")
threats = {
str(row.get("component_id")): row
for row in graph_row.get("threats", [])
if isinstance(row, dict)
}
matches: list[dict[str, object]] = []
for obstacle in obstacle_map.get("occupied", []):
item = _object(obstacle, "M4.8R2 occupied component")
cells = item.get("cells")
if not isinstance(cells, list) or not cells:
continue
points = np.asarray(
[
[
(int(cell["x"]) + 0.5) * voxel_size_m,
(int(cell["y"]) + 0.5) * voxel_size_m,
(int(cell["z"]) + 0.5) * voxel_size_m,
]
for cell in cells
],
dtype=np.float64,
)
projected = project_map_points_kb4(
points,
position_map_xyz=frame.sensor_position_map,
orientation_map_from_lidar_xyzw=frame.sensor_orientation_xyzw,
profile=frame.projection,
)
depths = _depths_in_bbox(projected.pixels_xy, projected.depths_m, bbox)
if not depths.size:
continue
component_id = str(item.get("component_id"))
assessment = _object(threats.get(component_id), "M4.8R2 threat assessment")
matches.append(
{
"component_id": component_id,
"state": item.get("state"),
"decision": assessment.get("decision"),
"projected_cell_count": int(depths.size),
"nearest_depth_m": round(float(np.min(depths)), 6),
}
)
matches.sort(key=lambda row: (float(row["nearest_depth_m"]), str(row["component_id"])))
return matches
def _canonical_anchors(
report: dict[str, Any], selection: dict[str, Any]
) -> tuple[dict[str, Any], ...]:
metrics = _object(report.get("metrics"), "M4.7 visual metrics")
visual = _object(metrics.get("visual_evidence"), "M4.7 visual evidence")
rows: list[dict[str, Any]] = []
for sequence in selection.get("canonical_engineering_sequences", []):
regression = _object(
visual.get(f"frame_{sequence}_regression"),
"canonical regression",
)
for anchor in regression.get("engineering_anchors", []):
item = _object(anchor, "canonical anchor")
rows.append(
{
"schema_version": M48_STATIC_OCCUPANCY_CANONICAL_SCHEMA,
"sequence": int(sequence),
"anchor_id": item.get("anchor_id"),
"matched": item.get("matched") is True,
"decision": item.get("decision"),
"must_assert_threat": item.get("must_assert_threat") is True,
"authority": "camera-reviewed-engineering-anchor-not-truth",
}
)
return tuple(rows)
def _metrics(
cases: list[dict[str, Any]], canonical: tuple[dict[str, Any], ...]
) -> dict[str, object]:
def band_rows(name: str) -> list[dict[str, Any]]:
return [row for row in cases if row["distance_band"] == name]
def rate(rows: list[dict[str, Any]], key: str) -> float:
if not rows:
return 0.0
return sum(bool(row[key]) for row in rows) / len(rows)
near = band_rows("critical-near")
approach = band_rows("approach")
return {
"operator_static_anchor_count": len(cases),
"baseline_qualified_count": sum(bool(row["baseline_qualified"]) for row in cases),
"candidate_qualified_count": sum(bool(row["candidate_qualified"]) for row in cases),
"unresolved_unknown_count": sum(not bool(row["candidate_qualified"]) for row in cases),
"critical_near_anchor_count": len(near),
"critical_near_baseline_recall": rate(near, "baseline_qualified"),
"critical_near_candidate_recall": rate(near, "candidate_qualified"),
"approach_anchor_count": len(approach),
"approach_baseline_recall": rate(approach, "baseline_qualified"),
"approach_candidate_recall": rate(approach, "candidate_qualified"),
"canonical_engineering_anchor_count": len(canonical),
"canonical_engineering_recall": sum(bool(row["matched"]) for row in canonical)
/ len(canonical)
if canonical
else 0.0,
"false_free_count": sum(bool(row["accepted_graph"]["free_space_claimed"]) for row in cases),
"independent_truth": False,
}
def _selected_graph_frames(path: Path, sequences: set[int]) -> dict[int, dict[str, Any]]:
rows: dict[int, dict[str, Any]] = {}
with path.open("r", encoding="utf-8") as stream:
for line in stream:
row = _object(json.loads(line), "M4.8R2 graph frame")
sequence = row.get("sequence")
if isinstance(sequence, int) and sequence in sequences:
rows[sequence] = row
if len(rows) == len(sequences):
break
if set(rows) != sequences:
raise M48StaticOccupancyQualificationError("M4.8R2 graph frames are incomplete")
return rows
def _pixel_bbox(value: object, width: int, height: int) -> tuple[float, float, float, float]:
extent = value if isinstance(value, list) else None
if extent is None or len(extent) != 4:
raise M48StaticOccupancyQualificationError("M4.8R2 anchor extent is invalid")
return (
float(extent[0]) * width,
float(extent[1]) * height,
float(extent[2]) * width,
float(extent[3]) * height,
)
def _depths_in_bbox(
pixels: np.ndarray, depths: np.ndarray, bbox: tuple[float, float, float, float]
) -> np.ndarray:
if not pixels.size:
return np.empty(0, dtype=np.float64)
inside = (
(pixels[:, 0] >= bbox[0])
& (pixels[:, 0] <= bbox[2])
& (pixels[:, 1] >= bbox[1])
& (pixels[:, 1] <= bbox[3])
)
return depths[inside]
def _support_distance(*values: np.ndarray) -> float:
for value in values:
if value.size:
return round(float(np.median(value)), 6)
raise M48StaticOccupancyQualificationError("M4.8R2 anchor has no projected LiDAR depth")
def _distance_band(distance: float, bands: dict[str, Any]) -> str:
for key, label in (("critical_near", "critical-near"), ("approach", "approach")):
bounds = bands.get(key)
if (
isinstance(bounds, list)
and len(bounds) == 2
and float(bounds[0]) <= distance < float(bounds[1])
):
return label
return "outside-qualified-bands"
def _read_profile(path: Path) -> tuple[bytes, dict[str, Any]]:
encoded = path.resolve(strict=True).read_bytes()
profile = _object(json.loads(encoded), "M4.8R2 profile")
if (
profile.get("schema_version") != M48_STATIC_OCCUPANCY_PROFILE_SCHEMA
or profile.get("authority") != _AUTHORITY
):
raise M48StaticOccupancyQualificationError("M4.8R2 profile is invalid")
return encoded, profile
def _publish_result(
destination: Path,
identity: dict[str, Any],
created_at: str,
accepted: bool,
report: dict[str, Any],
cases: tuple[dict[str, Any], ...],
canonical: tuple[dict[str, Any], ...],
) -> None:
destination.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
staging = destination.parent / f".{destination.name}.{uuid.uuid4().hex}.tmp"
staging.mkdir(mode=0o700)
try:
_write_json(staging / "report.json", report)
_write_jsonl(staging / "cases.jsonl", cases)
_write_jsonl(staging / "canonical-anchors.jsonl", canonical)
artifacts = [
_artifact(staging / name, role)
for name, role in (
("cases.jsonl", "operator-static-anchor-comparisons"),
("canonical-anchors.jsonl", "accepted-canonical-engineering-anchors"),
("report.json", "m48-static-occupancy-report"),
)
]
manifest = {
"schema_version": M48_STATIC_OCCUPANCY_RESULT_SCHEMA,
"result_id": destination.name,
"identity_sha256": _canonical_sha256(identity),
"identity": identity,
"created_at_utc": created_at,
"accepted": accepted,
"ground_truth": False,
"authority": dict(_AUTHORITY),
"artifacts": artifacts,
}
_write_json(staging / "manifest.json", manifest)
if destination.exists():
existing = {
path.name: _file_sha256(path) for path in destination.iterdir() if path.is_file()
}
proposed = {
path.name: _file_sha256(path) for path in staging.iterdir() if path.is_file()
}
if existing != proposed:
raise M48StaticOccupancyQualificationError("immutable M4.8R2 identity collided")
shutil.rmtree(staging)
return
os.replace(staging, destination)
except BaseException:
shutil.rmtree(staging, ignore_errors=True)
raise
def _artifact(path: Path, role: str) -> dict[str, object]:
return {
"path": path.name,
"role": role,
"byte_length": path.stat().st_size,
"sha256": _file_sha256(path),
"media_type": "application/x-ndjson" if path.suffix == ".jsonl" else "application/json",
}
def _read_json(path: Path, *, maximum: int) -> dict[str, Any]:
if path.is_symlink() or not path.is_file() or path.stat().st_size > maximum:
raise M48StaticOccupancyQualificationError(f"{path.name} is unavailable")
return _object(json.loads(path.read_text("utf-8")), path.name)
def _read_jsonl(path: Path) -> list[dict[str, Any]]:
if path.is_symlink() or not path.is_file() or path.stat().st_size > 8 * 1024 * 1024:
raise M48StaticOccupancyQualificationError(f"{path.name} is unavailable")
return [
_object(json.loads(line), path.name)
for line in path.read_text("utf-8").splitlines()
if line.strip()
]
def _write_json(path: Path, value: object) -> None:
path.write_text(
json.dumps(value, ensure_ascii=False, sort_keys=True, indent=2) + "\n", encoding="utf-8"
)
def _write_jsonl(path: Path, rows: tuple[dict[str, Any], ...]) -> None:
path.write_text(
"".join(
json.dumps(row, ensure_ascii=False, sort_keys=True, separators=(",", ":")) + "\n"
for row in rows
),
encoding="utf-8",
)
def _file_sha256(path: Path) -> str:
digest = hashlib.sha256()
with path.open("rb") as stream:
for chunk in iter(lambda: stream.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def _canonical_sha256(value: object) -> str:
return hashlib.sha256(
json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode("utf-8")
).hexdigest()
def _object(value: object, label: str) -> dict[str, Any]:
if not isinstance(value, dict):
raise M48StaticOccupancyQualificationError(f"{label} is invalid")
return value
def _utc_timestamp(value: str) -> str:
parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
if parsed.tzinfo is None:
raise M48StaticOccupancyQualificationError("M4.8R2 creation time is invalid")
return parsed.astimezone(UTC).isoformat().replace("+00:00", "Z")
__all__ = [
"M48StaticOccupancyQualificationError",
"M48StaticOccupancyQualificationResult",
"build_m48_static_occupancy_qualification",
"read_m48_static_occupancy_qualification",
]
@@ -0,0 +1,471 @@
"""Seal native raw-fisheye M4.8Q risk review evidence as a terminal LAB phase."""
from __future__ import annotations
import hashlib
import json
import re
import shutil
import tempfile
from dataclasses import dataclass
from datetime import UTC, datetime
from pathlib import Path
from typing import Any, Final
from k1link.perception.fixed_class_detector_tournament import (
canonical_json,
false_authority,
sha256_path,
)
LAB_SCHEMA: Final = "missioncore.m48q-native-risk-quality-lab/v1"
REPORT_SCHEMA: Final = "missioncore.m48q-native-risk-quality-report/v1"
CATALOG_SCHEMA: Final = "missioncore.m48q-native-risk-review-catalog/v1"
CASE_SCHEMA: Final = "missioncore.m48q-native-risk-review-case/v1"
RESULT_PREFIX: Final = "m48q-native-risk-quality-lab-"
PROFILE_RELATIVE_PATH: Final = Path("config/perception/m48q-native-risk-case-mining-v1.json")
DETECTOR_PROFILE_RELATIVE_PATH: Final = Path(
"config/perception/rf-detr-large-native-kb4-risk-shadow-v0.json"
)
WORKER_RELATIVE_ROOT: Final = Path(
".runtime/worker-results/m48q-native-risk-case-mining/ravnoves00-native-raw-review-v3"
)
EXPECTED_PROFILE_SHA256: Final = "c455055e63578d505edc80b66d67e795916a3d0297cc18bfee5a6af7b032ceda"
EXPECTED_DETECTOR_PROFILE_SHA256: Final = (
"dbf4da5dbad6c3c22b1280b46ffcad81719bd183c81c263a4859847d829019b6"
)
EXPECTED_WORKER_RESULT_SHA256: Final = (
"a8f98d6d68abd6fd627caa05aaa3f048d69279a989b07fc2552b508af909a623"
)
EXPECTED_CASES_SHA256: Final = "9cea2a4a4558d761bc76b0d70474673ff07210473f53bd32cf178e8e0c8e179c"
EXPECTED_REPORT_IDENTITY_SHA256: Final = (
"b744775c0e08d18d728f04021cd2acf9b1ed6fcacf1520352ee04e06a6d5d324"
)
CASE_ID: Final = re.compile(r"^[0-9]{6}$")
class M48QNativeRiskQualityLabError(RuntimeError):
"""Raised when native M4.8Q evidence cannot be sealed honestly."""
@dataclass(frozen=True, slots=True)
class M48QNativeRiskQualityLabResult:
result_root: Path
result_id: str
manifest: dict[str, Any]
def build_m48q_native_risk_quality_lab(
*,
repository_root: Path,
output_root: Path,
) -> M48QNativeRiskQualityLabResult:
repository = repository_root.expanduser().resolve(strict=True)
profile_path = repository / PROFILE_RELATIVE_PATH
detector_profile_path = repository / DETECTOR_PROFILE_RELATIVE_PATH
worker_root = repository / WORKER_RELATIVE_ROOT
worker_result_path = worker_root / "result.json"
cases_path = worker_root / "cases.jsonl"
images_root = worker_root / "cases"
for path in (
profile_path,
detector_profile_path,
worker_result_path,
cases_path,
):
if path.is_symlink() or not path.is_file():
raise M48QNativeRiskQualityLabError(f"required M4.8Q evidence is missing: {path.name}")
if images_root.is_symlink() or not images_root.is_dir():
raise M48QNativeRiskQualityLabError("M4.8Q image evidence is missing")
expected_hashes = {
profile_path: EXPECTED_PROFILE_SHA256,
detector_profile_path: EXPECTED_DETECTOR_PROFILE_SHA256,
worker_result_path: EXPECTED_WORKER_RESULT_SHA256,
cases_path: EXPECTED_CASES_SHA256,
}
if any(sha256_path(path) != expected for path, expected in expected_hashes.items()):
raise M48QNativeRiskQualityLabError("M4.8Q source evidence identity changed")
profile = _read_object(profile_path)
detector_profile = _read_object(detector_profile_path)
worker_result = _read_object(worker_result_path)
cases = _read_cases(cases_path)
_validate_inputs(
profile=profile,
detector_profile=detector_profile,
worker_result=worker_result,
cases=cases,
images_root=images_root,
)
method = _method(profile, detector_profile, worker_result)
identity = {
"schema_version": LAB_SCHEMA,
"profile": {
"profile_id": profile["profile_id"],
"sha256": EXPECTED_PROFILE_SHA256,
},
"detector_profile": {
"profile_id": detector_profile["profile_id"],
"sha256": EXPECTED_DETECTOR_PROFILE_SHA256,
},
"source": {
"source_id": "RAVNOVES00",
"video_sha256": profile["source"]["video_sha256"],
"graph_result_sha256": worker_result["source"]["graph_result_sha256"],
"graph_frames_sha256": worker_result["source"]["graph_frames_sha256"],
"comparison_result_sha256": worker_result["source"]["comparison_result_sha256"],
"comparison_frames_sha256": worker_result["source"]["comparison_frames_sha256"],
"worker_result_sha256": EXPECTED_WORKER_RESULT_SHA256,
"cases_sha256": EXPECTED_CASES_SHA256,
},
"method": method,
"authority": false_authority(),
}
identity_sha256 = hashlib.sha256(canonical_json(identity)).hexdigest()
result_id = RESULT_PREFIX + identity_sha256
root = output_root.expanduser().absolute()
root.mkdir(mode=0o700, parents=True, exist_ok=True)
destination = root / result_id
if destination.exists():
manifest = _read_object(destination / "manifest.json")
if (
manifest.get("schema_version") != LAB_SCHEMA
or manifest.get("identity_sha256") != identity_sha256
or manifest.get("result_id") != result_id
):
raise M48QNativeRiskQualityLabError("existing M4.8Q LAB identity conflicts")
return M48QNativeRiskQualityLabResult(destination, result_id, manifest)
created_at_utc = datetime.now(UTC).isoformat(timespec="microseconds").replace("+00:00", "Z")
temporary = Path(tempfile.mkdtemp(prefix=".m48q-native-risk-lab-", dir=root))
try:
(temporary / "cases").mkdir(mode=0o700)
shutil.copyfile(profile_path, temporary / "profile.json")
shutil.copyfile(detector_profile_path, temporary / "detector-profile.json")
shutil.copyfile(worker_result_path, temporary / "worker-result.json")
shutil.copyfile(cases_path, temporary / "cases.jsonl")
catalog_cases: list[dict[str, object]] = []
for case in cases:
image = case["image"]
source_image = worker_root / image["path"]
destination_image = temporary / image["path"]
shutil.copyfile(source_image, destination_image)
catalog_cases.append(
{
"case_id": case["case_id"],
"sequence": case["sequence"],
"frame_id": case["frame_id"],
"evidence_time_ns": case["evidence_time_ns"],
"path": image["path"],
"media_type": "image/jpeg",
"width": 800,
"height": 600,
"byte_length": destination_image.stat().st_size,
"sha256": sha256_path(destination_image),
"geometric_resampling": False,
"selection_buckets": case["selection_buckets"],
"comparison": case["comparison"],
"proposals": case["proposals"],
}
)
catalog = {
"schema_version": CATALOG_SCHEMA,
"result_id": result_id,
"case_count": len(catalog_cases),
"source_raster": {"width": 800, "height": 600},
"overlay": {
"client_rendered": True,
"toggleable": True,
"box_coordinates": "source-pixel-xyxy",
"class_names": True,
"scores": True,
},
"ground_truth": False,
"cases": catalog_cases,
}
catalog_path = temporary / "catalog.json"
catalog_path.write_bytes(canonical_json(catalog) + b"\n")
graph_qualification = detector_profile["qualification"][
"full_ravnoves00_integrated_reference_graph"
]
decision = {
"review_ready": True,
"quality_evaluated": False,
"ground_truth": False,
"candidate_accepted": False,
"production_accepted": False,
"next_action": "operator-adjudication-in-existing-m48-review-instrument",
}
report = {
"schema_version": REPORT_SCHEMA,
"result_id": result_id,
"source": {
**profile["source"],
"graph_result_sha256": worker_result["source"]["graph_result_sha256"],
"graph_frames_sha256": worker_result["source"]["graph_frames_sha256"],
"independent_route_truth_available": False,
},
"configuration": {
"candidate": profile["candidate"],
"selection": profile["selection"],
},
"method": method,
"execution": {
"worker": worker_result["worker"],
"full_graph_frames": graph_qualification["frame_count"],
"requested_source_rate_hz": graph_qualification["requested_source_rate_hz"],
"effective_world_state_fps": graph_qualification["effective_world_state_fps"],
"world_state_completion_p95_ms": graph_qualification[
"world_state_completion_p95_ms"
],
"detector_total_p95_ms": graph_qualification["detector_total_p95_ms"],
"gpu_utilization_p95_percent": graph_qualification["gpu_utilization_p95_percent"],
"gpu_memory_used_maximum_mib": graph_qualification["gpu_memory_used_maximum_mib"],
"additional_inference_passes": 0,
},
"metrics": {
"selection": worker_result["selection"],
"runtime": {
"delivery_ratio": graph_qualification["delivery_ratio"],
"integrated_runtime_gate_passed": graph_qualification[
"integrated_runtime_gate_passed"
],
"operating_target_gate_passed": graph_qualification[
"operating_target_gate_passed"
],
},
"native_tensor_parity": detector_profile["qualification"][
"native_pytorch_tensorrt_parity"
],
"native_vs_legacy_704": detector_profile["qualification"][
"full_ravnoves00_native_vs_legacy_704"
],
},
"acceptance": {
"review_ready": True,
"integrated_runtime_gate_passed": True,
"independent_quality_evaluated": False,
"semantic_candidate_accepted": False,
},
"decision": decision,
"limitations": worker_result["limitations"],
"authority": false_authority(),
"visual_evidence": {
"kind": "native-raw-fisheye-risk-case-review",
"case_count": 24,
"source_raster": "800x600",
"geometric_resampling": False,
"boxes_baked_into_images": False,
"ground_truth": False,
},
}
report_path = temporary / "report.json"
report_path.write_bytes(canonical_json(report) + b"\n")
artifacts = _artifact_manifest(temporary)
manifest = {
"schema_version": LAB_SCHEMA,
"result_id": result_id,
"identity_sha256": identity_sha256,
"identity": identity,
"created_at_utc": created_at_utc,
"status": "complete-review-ready-quality-not-adjudicated",
"completed": True,
"bounded_question_accepted": True,
"ground_truth": False,
"method": method,
"metrics": report["metrics"],
"decision": decision,
"limitations": worker_result["limitations"],
"authority": false_authority(),
"artifacts": artifacts,
}
(temporary / "manifest.json").write_bytes(canonical_json(manifest) + b"\n")
temporary.replace(destination)
except BaseException:
shutil.rmtree(temporary, ignore_errors=True)
raise
return M48QNativeRiskQualityLabResult(destination, result_id, manifest)
def _validate_inputs(
*,
profile: dict[str, Any],
detector_profile: dict[str, Any],
worker_result: dict[str, Any],
cases: list[dict[str, Any]],
images_root: Path,
) -> None:
if (
profile.get("schema_version") != "missioncore.m48q-native-risk-case-mining-profile/v1"
or profile.get("source", {}).get("geometric_resampling") is not False
or profile.get("source", {}).get("raster_width") != 800
or profile.get("source", {}).get("raster_height") != 600
or profile.get("authority") != false_authority()
or detector_profile.get("schema_version")
!= "missioncore.rf-detr-native-risk-shadow-profile/v0"
or detector_profile.get("preprocessing", {}).get("resize") is not False
or detector_profile.get("preprocessing", {}).get("geometric_resampling") is not False
or detector_profile.get("status", {}).get("integrated_world_state_gate_passed") is not True
or worker_result.get("schema_version")
!= "missioncore.m48q-native-risk-case-mining-result/v1"
or worker_result.get("status") != "complete-review-ready-quality-not-adjudicated"
or worker_result.get("completed") is not True
or worker_result.get("report_identity_sha256") != EXPECTED_REPORT_IDENTITY_SHA256
or worker_result.get("artifacts", {}).get("cases", {}).get("sha256")
!= EXPECTED_CASES_SHA256
or worker_result.get("selection", {}).get("case_count") != 24
or worker_result.get("decision", {}).get("quality_evaluated") is not False
or worker_result.get("authority") != false_authority()
or len(cases) != 24
or len({case.get("case_id") for case in cases}) != 24
):
raise M48QNativeRiskQualityLabError("M4.8Q evidence contract changed")
for case in cases:
image = case.get("image")
proposals = case.get("proposals")
if (
case.get("schema_version") != CASE_SCHEMA
or not isinstance(case.get("case_id"), str)
or CASE_ID.fullmatch(case["case_id"]) is None
or case.get("case_id") != f"{case.get('sequence'):06d}"
or case.get("frame_id") != f"frame-{case.get('sequence'):06d}"
or case.get("ground_truth") is not False
or case.get("quality_evaluated") is not False
or case.get("authority") != false_authority()
or not isinstance(image, dict)
or image.get("path") != f"cases/frame-{case['case_id']}.jpg"
or image.get("width") != 800
or image.get("height") != 600
or image.get("geometric_resampling") is not False
or not isinstance(proposals, list)
or not proposals
):
raise M48QNativeRiskQualityLabError("M4.8Q review case contract changed")
image_path = images_root.parent / image["path"]
if (
image_path.is_symlink()
or not image_path.is_file()
or image_path.stat().st_size != image.get("byte_length")
or sha256_path(image_path) != image.get("sha256")
):
raise M48QNativeRiskQualityLabError("M4.8Q review image proof changed")
def _method(
profile: dict[str, Any],
detector_profile: dict[str, Any],
worker_result: dict[str, Any],
) -> dict[str, object]:
return {
"schema_version": "missioncore.laboratory-method/v1",
"completeness": "complete",
"execution_class": "hybrid",
"pipeline_id": "m48q-native-raw-fisheye-risk-case-review/v1",
"components": [
{
"kind": "source",
"name": "RAVNOVES00 raw KB4 video",
"version": "800x600 immutable recording",
"role": "unrectified review raster",
"identity_sha256": profile["source"]["video_sha256"],
},
{
"kind": "model",
"name": "RF-DETR-L native KB4 TensorRT",
"version": profile["candidate"]["model_id"],
"role": "fixed-class behavior-risk shadow proposals",
"identity_sha256": profile["candidate"]["engine_sha256"],
},
{
"kind": "runtime",
"name": "M4.7 native reference graph",
"version": "full RAVNOVES00 at recorded 12 FPS",
"role": "proposal and realtime evidence source",
"identity_sha256": worker_result["source"]["graph_result_sha256"],
},
{
"kind": "algorithm",
"name": "bounded diagnostic case miner",
"version": profile["profile_id"],
"role": "deterministic risk-family and edge-case sampling",
"identity_sha256": worker_result["identity"]["runner_sha256"],
},
{
"kind": "tool",
"name": "M4.8 existing image-case review instrument",
"version": "client-rendered source-pixel overlay/v1",
"role": "operator review without baked boxes",
"identity_sha256": EXPECTED_CASES_SHA256,
},
],
}
def _artifact_manifest(root: Path) -> list[dict[str, object]]:
artifacts: list[dict[str, object]] = []
for path in sorted(item for item in root.rglob("*") if item.is_file()):
relative = path.relative_to(root).as_posix()
if relative == "manifest.json":
continue
media_type = "application/json"
schema_version: str | None = None
role = "supporting-evidence"
if relative == "report.json":
role = "laboratory-report"
schema_version = REPORT_SCHEMA
elif relative == "catalog.json":
role = "visual-evidence-catalog"
schema_version = CATALOG_SCHEMA
elif relative == "profile.json":
role = "predeclared-native-risk-review-profile"
schema_version = "missioncore.m48q-native-risk-case-mining-profile/v1"
elif relative == "detector-profile.json":
role = "qualified-native-detector-profile"
schema_version = "missioncore.rf-detr-native-risk-shadow-profile/v0"
elif relative == "worker-result.json":
role = "upstream-worker-case-mining-result"
schema_version = "missioncore.m48q-native-risk-case-mining-result/v1"
elif relative == "cases.jsonl":
media_type = "application/x-ndjson"
role = "native-risk-review-case-ledger"
schema_version = CASE_SCHEMA
elif relative.endswith(".jpg"):
media_type = "image/jpeg"
role = "visual-evidence-native-raw-fisheye-frame"
artifacts.append(
{
"role": role,
"path": relative,
"byte_length": path.stat().st_size,
"sha256": sha256_path(path),
"media_type": media_type,
"schema_version": schema_version,
}
)
return artifacts
def _read_object(path: Path) -> dict[str, Any]:
try:
value: object = json.loads(path.read_text("utf-8"))
except (OSError, json.JSONDecodeError) as exc:
raise M48QNativeRiskQualityLabError(f"invalid JSON evidence: {path.name}") from exc
if not isinstance(value, dict):
raise M48QNativeRiskQualityLabError(f"JSON evidence must be an object: {path.name}")
return value
def _read_cases(path: Path) -> list[dict[str, Any]]:
cases: list[dict[str, Any]] = []
try:
with path.open("r", encoding="utf-8") as stream:
for line in stream:
value: object = json.loads(line)
if not isinstance(value, dict):
raise M48QNativeRiskQualityLabError("M4.8Q case ledger row is not an object")
cases.append(value)
except (OSError, json.JSONDecodeError) as exc:
raise M48QNativeRiskQualityLabError("M4.8Q case ledger cannot be read") from exc
return cases
+22
View File
@@ -344,6 +344,28 @@ class RecordedGeometryStore:
points.setflags(write=False)
return points
def point_step_candidates_for_frame(self, frame_index: int) -> UInt8Array | None:
"""Expose the sealed low-step diagnostic in the source point index space.
The array is evidence only: a non-zero value may add conservative
occupied/unknown support, but it never clears a cell or claims free
space. Unavailable and surface-invalid frames remain unavailable.
"""
frame = self.frame_for_index(frame_index)
if frame is None or not frame.surface_valid:
return None
offsets = self._source["cloud_offsets"]
start, end = int(offsets[frame_index]), int(offsets[frame_index + 1])
values = np.asarray(
self._surface["point_step_candidate"][start:end],
dtype=np.uint8,
)
if values.shape != (frame.source_point_count,):
raise GeometryProviderError("local-surface step evidence changed")
values.setflags(write=False)
return values
@property
def maximum_current_point_count(self) -> int:
"""Return the immutable source-pack upper bound for one recorded increment."""
+15 -1
View File
@@ -153,8 +153,8 @@ from k1link.web.runtime_readiness import (
build_runtime_readiness,
)
from k1link.web.session_api import build_session_router
from k1link.web.simulation_world_provider_api import build_simulation_world_provider_router
from k1link.web.simulation_projects_api import build_simulation_projects_router
from k1link.web.simulation_world_provider_api import build_simulation_world_provider_router
from k1link.web.system_telemetry_api import build_system_telemetry_router
from k1link.web.viewer_diagnostics_api import build_viewer_diagnostics_router
@@ -934,6 +934,13 @@ app.include_router(
/ "m48"
/ "small-static-passage-regression-results"
),
static_occupancy_result_root_provider=lambda: (
REPOSITORY_ROOT
/ ".runtime"
/ "compute-experiments"
/ "m48"
/ "static-occupancy-qualification-results"
),
camera_frame_provider=(
session_recorded_camera_frame_service.extract
if session_recorded_camera_frame_service is not None
@@ -980,6 +987,13 @@ app.include_router(
/ "m48t-risk-quality"
/ "lab-results"
),
native_root_provider=lambda: (
REPOSITORY_ROOT
/ ".runtime"
/ "compute-experiments"
/ "m48t-risk-quality"
/ "native-lab-results"
),
)
)
app.include_router(
+86
View File
@@ -48,6 +48,11 @@ from k1link.laboratory.m48_small_static_regression import (
M48SmallStaticRegressionResult,
read_m48_small_static_passage_regression,
)
from k1link.laboratory.m48_static_occupancy_qualification import (
M48StaticOccupancyQualificationError,
M48StaticOccupancyQualificationResult,
read_m48_static_occupancy_qualification,
)
from k1link.sessions import RecordedCameraPlaybackSource
_PACK_ID = re.compile(r"^m48-object-quality-pack-[a-f0-9]{64}$")
@@ -57,6 +62,9 @@ _SMALL_STATIC_RESULT_ID = re.compile(
r"^m48-small-static-passage-regression-[a-f0-9]{64}$"
)
_SMALL_STATIC_ANCHOR_ID = re.compile(r"^anchor-[a-f0-9]{24}$")
_STATIC_OCCUPANCY_RESULT_ID = re.compile(
r"^m48-static-occupancy-qualification-[a-f0-9]{64}$"
)
_M47_LAB_RESULT_ID = re.compile(r"^m47-reference-graph-lab-[a-f0-9]{64}$")
_FAILURE_ID = re.compile(r"^m48-failure-[a-f0-9]{64}$")
_REVIEW_SESSION_ID = re.compile(r"^m48-review-session-[a-f0-9]{64}$")
@@ -93,6 +101,12 @@ _SMALL_STATIC_CASE_CATALOG_SCHEMA: Final = (
_SMALL_STATIC_CASE_VIEW_SCHEMA: Final = (
"missioncore.m48-small-static-passage-regression-case-view/v1"
)
_STATIC_OCCUPANCY_RESULT_VIEW_SCHEMA: Final = (
"missioncore.m48-static-occupancy-qualification-result-view/v1"
)
_STATIC_OCCUPANCY_CASE_CATALOG_SCHEMA: Final = (
"missioncore.m48-static-occupancy-case-catalog/v1"
)
_FAILURE_ATLAS_VIEW_SCHEMA: Final = "missioncore.m48-object-quality-failure-atlas-view/v1"
_FAILURE_CASE_VIEW_SCHEMA: Final = "missioncore.m48-object-quality-failure-case-view/v1"
_REVIEW_CAPABILITY_HEADER: Final = "X-M48-Review-Capability"
@@ -438,6 +452,7 @@ def build_m48_object_quality_router(
truth_root_provider: RootProvider = lambda: None,
result_root_provider: RootProvider = lambda: None,
small_static_result_root_provider: RootProvider = lambda: None,
static_occupancy_result_root_provider: RootProvider = lambda: None,
camera_frame_provider: CameraFrameProvider | None = None,
camera_playback_provider: CameraPlaybackProvider | None = None,
spatial_evidence_provider: SpatialEvidenceProvider | None = None,
@@ -1593,6 +1608,56 @@ def build_m48_object_quality_router(
"access": "assisted-development-regression-case-read-only",
}
@router.get("/regressions/static-occupancy/{result_id}")
def get_static_occupancy_qualification(
result_id: Annotated[str, ApiPath(pattern=_STATIC_OCCUPANCY_RESULT_ID.pattern)],
) -> dict[str, object]:
result = _resolve_static_occupancy_result(
static_occupancy_result_root_provider,
result_id,
)
source = _object(result.report.get("source"), "M4.8R2 source")
configuration = _object(
result.report.get("configuration"),
"M4.8R2 configuration",
)
return {
"schema_version": _STATIC_OCCUPANCY_RESULT_VIEW_SCHEMA,
"result_id": result.result_id,
"created_at_utc": result.manifest.get("created_at_utc"),
"reference_graph_lab_result_id": source.get("m47_lab_result_id"),
"small_static_result_id": source.get("small_static_result_id"),
"run_label": configuration.get("run_label"),
"pipeline_id": configuration.get("pipeline_id"),
"experiment_id": configuration.get("experiment_id"),
"accepted": result.manifest.get("accepted"),
"metrics": copy.deepcopy(result.report.get("metrics")),
"gates": copy.deepcopy(result.report.get("gates")),
"decision": copy.deepcopy(result.report.get("decision")),
"ground_truth": False,
"independent_truth": False,
"authority": dict(_AUTHORITY),
"access": "static-occupancy-qualification-read-only",
}
@router.get("/regressions/static-occupancy/{result_id}/cases")
def get_static_occupancy_qualification_cases(
result_id: Annotated[str, ApiPath(pattern=_STATIC_OCCUPANCY_RESULT_ID.pattern)],
) -> dict[str, object]:
result = _resolve_static_occupancy_result(
static_occupancy_result_root_provider,
result_id,
)
return {
"schema_version": _STATIC_OCCUPANCY_CASE_CATALOG_SCHEMA,
"result_id": result.result_id,
"cases": copy.deepcopy(result.cases),
"case_count": len(result.cases),
"ground_truth": False,
"authority": dict(_AUTHORITY),
"access": "static-occupancy-qualification-read-only",
}
return router
@@ -1691,6 +1756,27 @@ def _resolve_small_static_result(
) from None
def _resolve_static_occupancy_result(
provider: RootProvider,
result_id: str,
) -> M48StaticOccupancyQualificationResult:
if _STATIC_OCCUPANCY_RESULT_ID.fullmatch(result_id) is None:
raise HTTPException(status_code=404, detail="M4.8R2 result was not found")
root = _configured_root(provider)
if root is None:
raise HTTPException(status_code=404, detail="M4.8R2 result was not found")
path = root / result_id
if path.is_symlink() or not path.is_dir():
raise HTTPException(status_code=404, detail="M4.8R2 result was not found")
try:
resolved = path.resolve(strict=True)
if resolved.parent != root:
raise OSError("M4.8R2 result escaped root")
return read_m48_static_occupancy_qualification(resolved)
except (M48StaticOccupancyQualificationError, OSError, TypeError, ValueError):
raise HTTPException(status_code=404, detail="M4.8R2 result was not found") from None
def _result_sources(
result: M48ObjectQualityResult,
*,
+290 -66
View File
@@ -1,4 +1,4 @@
"""Read-only API for the sealed M4.8T quality and temporal LAB."""
"""Read-only API for the M4.8T legacy quality and M4.8Q native review lifecycle."""
from __future__ import annotations
@@ -8,7 +8,7 @@ import json
import re
from collections.abc import Callable
from pathlib import Path, PurePosixPath
from typing import Any, Final
from typing import Any, Final, Literal
from fastapi import APIRouter, HTTPException, Query
from fastapi.responses import FileResponse
@@ -18,30 +18,61 @@ from k1link.laboratory.evidence_report import (
LaboratoryEvidenceReportError,
verify_laboratory_evidence_result,
)
from k1link.laboratory.m48q_native_risk_quality_lab import (
CATALOG_SCHEMA as NATIVE_CATALOG_SCHEMA,
)
from k1link.laboratory.m48q_native_risk_quality_lab import (
LAB_SCHEMA as NATIVE_LAB_SCHEMA,
)
from k1link.laboratory.m48q_native_risk_quality_lab import (
REPORT_SCHEMA as NATIVE_REPORT_SCHEMA,
)
from k1link.laboratory.m48q_native_risk_quality_lab import (
RESULT_PREFIX as NATIVE_RESULT_PREFIX,
)
from k1link.laboratory.m48t_risk_quality_lab import (
CATALOG_SCHEMA,
LAB_SCHEMA,
REPORT_SCHEMA,
RESULT_PREFIX,
CATALOG_SCHEMA as LEGACY_CATALOG_SCHEMA,
)
from k1link.laboratory.m48t_risk_quality_lab import (
LAB_SCHEMA as LEGACY_LAB_SCHEMA,
)
from k1link.laboratory.m48t_risk_quality_lab import (
REPORT_SCHEMA as LEGACY_REPORT_SCHEMA,
)
from k1link.laboratory.m48t_risk_quality_lab import (
RESULT_PREFIX as LEGACY_RESULT_PREFIX,
)
from k1link.perception.fixed_class_detector_tournament import false_authority
RootProvider = Callable[[], Path | None]
RESULT_ID: Final = re.compile(rf"^{re.escape(RESULT_PREFIX)}[a-f0-9]{{64}}$")
CASE_ID: Final = re.compile(r"^[0-9]{12}$")
VIEW_SCHEMA: Final = "missioncore.m48t-risk-quality-temporal-view/v1"
CATALOG_VIEW_SCHEMA: Final = "missioncore.m48t-risk-quality-temporal-catalog/v1"
_DEFINITION: Final = LaboratoryEvidenceDefinition(
Variant = Literal["legacy", "native"]
LEGACY_RESULT_ID: Final = re.compile(rf"^{re.escape(LEGACY_RESULT_PREFIX)}[a-f0-9]{{64}}$")
NATIVE_RESULT_ID: Final = re.compile(rf"^{re.escape(NATIVE_RESULT_PREFIX)}[a-f0-9]{{64}}$")
LEGACY_CASE_ID: Final = re.compile(r"^[0-9]{12}$")
NATIVE_CASE_ID: Final = re.compile(r"^[0-9]{6}$")
LEGACY_VIEW_SCHEMA: Final = "missioncore.m48t-risk-quality-temporal-view/v1"
NATIVE_VIEW_SCHEMA: Final = "missioncore.m48q-native-risk-quality-view/v1"
CATALOG_VIEW_SCHEMA: Final = "missioncore.m48t-risk-quality-lifecycle-catalog/v1"
_LEGACY_DEFINITION: Final = LaboratoryEvidenceDefinition(
work_id="m48t-risk-quality-temporal",
runtime_relative_root=PurePosixPath("m48t-risk-quality/lab-results"),
result_id_prefix="m48t-risk-quality-temporal-lab",
document_name="manifest.json",
result_schema_version=LAB_SCHEMA,
result_schema_version=LEGACY_LAB_SCHEMA,
)
_NATIVE_DEFINITION: Final = LaboratoryEvidenceDefinition(
work_id="m48t-risk-quality-temporal",
runtime_relative_root=PurePosixPath("m48t-risk-quality/native-lab-results"),
result_id_prefix="m48q-native-risk-quality-lab",
document_name="manifest.json",
result_schema_version=NATIVE_LAB_SCHEMA,
)
def build_m48t_risk_quality_lab_router(
*, root_provider: RootProvider = lambda: None
*,
root_provider: RootProvider = lambda: None,
native_root_provider: RootProvider = lambda: None,
) -> APIRouter:
router = APIRouter(
prefix="/api/v1/laboratory/m48t/risk-quality",
@@ -50,15 +81,23 @@ def build_m48t_risk_quality_lab_router(
@router.get("/results")
def list_results(limit: int = Query(default=1, ge=1, le=10)) -> dict[str, object]:
root = _configured_root(root_provider)
if root is None:
return _empty_catalog(False)
candidates = _candidates(root)
configured = False
candidates: list[tuple[Path, Variant]] = []
providers: tuple[tuple[RootProvider, Variant, re.Pattern[str]], ...] = (
(root_provider, "legacy", LEGACY_RESULT_ID),
(native_root_provider, "native", NATIVE_RESULT_ID),
)
for provider, variant, pattern in providers:
root = _configured_root(provider)
if root is None:
continue
configured = True
candidates.extend((item, variant) for item in _candidates(root, pattern))
items: list[dict[str, object]] = []
invalid_total = 0
for candidate in candidates:
for candidate, variant in candidates:
try:
items.append(_project_result(candidate))
items.append(_project_result(candidate, variant))
except RuntimeError:
invalid_total += 1
items.sort(
@@ -67,7 +106,7 @@ def build_m48t_risk_quality_lab_router(
)
return {
"schema_version": CATALOG_VIEW_SCHEMA,
"configured": True,
"configured": configured,
"items": items[:limit],
"candidate_total": len(candidates),
"invalid_total": invalid_total,
@@ -77,18 +116,37 @@ def build_m48t_risk_quality_lab_router(
@router.get("/results/{result_id}")
def get_result(result_id: str) -> dict[str, object]:
try:
return _project_result(_resolve_candidate(root_provider, result_id))
candidate, variant = _resolve_candidate(
root_provider,
native_root_provider,
result_id,
)
return _project_result(candidate, variant)
except RuntimeError:
raise HTTPException(status_code=404, detail="M4.8T result not found") from None
raise HTTPException(
status_code=404,
detail="M4.8T/M4.8Q result not found",
) from None
@router.get("/results/{result_id}/review/{case_id}.jpg")
def get_review_image(result_id: str, case_id: str) -> FileResponse:
if CASE_ID.fullmatch(case_id) is None:
raise HTTPException(status_code=404, detail="M4.8T review case not found")
try:
loaded = _load_result(_resolve_candidate(root_provider, result_id))
candidate, variant = _resolve_candidate(
root_provider,
native_root_provider,
result_id,
)
invalid_case = (variant == "legacy" and LEGACY_CASE_ID.fullmatch(case_id) is None) or (
variant == "native" and NATIVE_CASE_ID.fullmatch(case_id) is None
)
if invalid_case:
raise RuntimeError("case identity is invalid")
loaded = _load_result(candidate, variant)
except RuntimeError:
raise HTTPException(status_code=404, detail="M4.8T result not found") from None
raise HTTPException(
status_code=404,
detail="M4.8T/M4.8Q review case not found",
) from None
descriptor = next(
(
item
@@ -98,8 +156,10 @@ def build_m48t_risk_quality_lab_router(
None,
)
if not isinstance(descriptor, dict):
raise HTTPException(status_code=404, detail="M4.8T review case not found")
candidate = loaded["root"]
raise HTTPException(
status_code=404,
detail="M4.8T/M4.8Q review case not found",
)
path = (candidate / str(descriptor["path"])).resolve()
if (
not path.is_relative_to(candidate)
@@ -108,7 +168,10 @@ def build_m48t_risk_quality_lab_router(
or descriptor.get("byte_length") != path.stat().st_size
or descriptor.get("sha256") != _sha256(path)
):
raise HTTPException(status_code=404, detail="M4.8T review case not found")
raise HTTPException(
status_code=404,
detail="M4.8T/M4.8Q review case not found",
)
return FileResponse(
path,
media_type="image/jpeg",
@@ -122,8 +185,12 @@ def build_m48t_risk_quality_lab_router(
return router
def _project_result(candidate: Path) -> dict[str, object]:
loaded = _load_result(candidate)
def _project_result(candidate: Path, variant: Variant) -> dict[str, object]:
loaded = _load_result(candidate, variant)
return _project_native(loaded) if variant == "native" else _project_legacy(loaded)
def _project_legacy(loaded: dict[str, Any]) -> dict[str, object]:
manifest = loaded["manifest"]
report = loaded["report"]
catalog = loaded["catalog"]
@@ -143,7 +210,8 @@ def _project_result(candidate: Path) -> dict[str, object]:
for item in catalog["cases"]
]
return {
"schema_version": VIEW_SCHEMA,
"schema_version": LEGACY_VIEW_SCHEMA,
"variant": "legacy-coco-quality",
"result_id": result_id,
"created_at_utc": manifest["created_at_utc"],
"status": manifest["status"],
@@ -165,26 +233,97 @@ def _project_result(candidate: Path) -> dict[str, object]:
}
def _load_result(candidate: Path) -> dict[str, Any]:
def _project_native(loaded: dict[str, Any]) -> dict[str, object]:
manifest = loaded["manifest"]
report = loaded["report"]
catalog = loaded["catalog"]
result_id = str(manifest["result_id"])
review_cases = [
{
"case_id": item["case_id"],
"sequence": item["sequence"],
"frame_id": item["frame_id"],
"evidence_time_ns": item["evidence_time_ns"],
"image_url": (
f"/api/v1/laboratory/m48t/risk-quality/results/{result_id}"
f"/review/{item['case_id']}.jpg"
),
"media_type": item["media_type"],
"width": item["width"],
"height": item["height"],
"byte_length": item["byte_length"],
"sha256": item["sha256"],
"geometric_resampling": item["geometric_resampling"],
"selection_buckets": copy.deepcopy(item["selection_buckets"]),
"comparison": copy.deepcopy(item["comparison"]),
"proposals": copy.deepcopy(item["proposals"]),
}
for item in catalog["cases"]
]
return {
"schema_version": NATIVE_VIEW_SCHEMA,
"variant": "native-risk-review",
"result_id": result_id,
"created_at_utc": manifest["created_at_utc"],
"status": manifest["status"],
"source": copy.deepcopy(report["source"]),
"configuration": copy.deepcopy(report["configuration"]),
"method": copy.deepcopy(report["method"]),
"execution": copy.deepcopy(report["execution"]),
"metrics": copy.deepcopy(report["metrics"]),
"acceptance": copy.deepcopy(report["acceptance"]),
"decision": copy.deepcopy(report["decision"]),
"limitations": copy.deepcopy(report["limitations"]),
"review": {
"source_raster": copy.deepcopy(catalog["source_raster"]),
"overlay": copy.deepcopy(catalog["overlay"]),
"cases": review_cases,
},
"ground_truth": False,
"authority": copy.deepcopy(report["authority"]),
"access": "read-only",
}
def _load_result(candidate: Path, variant: Variant) -> dict[str, Any]:
pattern = NATIVE_RESULT_ID if variant == "native" else LEGACY_RESULT_ID
definition = _NATIVE_DEFINITION if variant == "native" else _LEGACY_DEFINITION
if (
not candidate.is_dir()
or candidate.is_symlink()
or RESULT_ID.fullmatch(candidate.name) is None
or pattern.fullmatch(candidate.name) is None
):
raise RuntimeError("M4.8T result candidate is invalid")
raise RuntimeError("M4.8 result candidate is invalid")
try:
verify_laboratory_evidence_result(_DEFINITION, candidate)
verify_laboratory_evidence_result(definition, candidate)
manifest = _read_object(candidate / "manifest.json")
report = _read_object(candidate / "report.json")
catalog = _read_object(candidate / "catalog.json")
except (LaboratoryEvidenceReportError, OSError, ValueError) as exc:
raise RuntimeError("M4.8T result integrity failed") from exc
raise RuntimeError("M4.8 result integrity failed") from exc
if variant == "native":
_validate_native(candidate, manifest, report, catalog)
else:
_validate_legacy(candidate, manifest, report, catalog)
return {
"root": candidate,
"manifest": manifest,
"report": report,
"catalog": catalog,
}
def _validate_legacy(
candidate: Path,
manifest: dict[str, Any],
report: dict[str, Any],
catalog: dict[str, Any],
) -> None:
identity = manifest.get("identity")
if (
manifest.get("schema_version") != LAB_SCHEMA
manifest.get("schema_version") != LEGACY_LAB_SCHEMA
or manifest.get("result_id") != candidate.name
or manifest.get("status")
!= "complete-quality-gate-failed-temporal-invariant-passed"
or manifest.get("status") != "complete-quality-gate-failed-temporal-invariant-passed"
or manifest.get("completed") is not True
or manifest.get("bounded_question_accepted") is not False
or manifest.get("ground_truth") is not False
@@ -194,47 +333,143 @@ def _load_result(candidate: Path) -> dict[str, Any]:
or not candidate.name.endswith(str(manifest.get("identity_sha256")))
or identity.get("authority") != false_authority()
or manifest.get("authority") != false_authority()
or report.get("schema_version") != REPORT_SCHEMA
or report.get("schema_version") != LEGACY_REPORT_SCHEMA
or report.get("result_id") != candidate.name
or report.get("authority") != false_authority()
or report.get("decision", {}).get("quality_accepted") is not False
or report.get("decision", {}).get("temporal_invariant_passed") is not True
or catalog.get("schema_version") != CATALOG_SCHEMA
or catalog.get("schema_version") != LEGACY_CATALOG_SCHEMA
or catalog.get("result_id") != candidate.name
or catalog.get("case_count") != 16
or not isinstance(catalog.get("cases"), list)
or len(catalog["cases"]) != 16
or any(not _valid_case(item) for item in catalog["cases"])
or any(not _valid_legacy_case(item) for item in catalog["cases"])
):
raise RuntimeError("M4.8T result contract changed")
return {"root": candidate, "manifest": manifest, "report": report, "catalog": catalog}
def _valid_case(value: object) -> bool:
def _validate_native(
candidate: Path,
manifest: dict[str, Any],
report: dict[str, Any],
catalog: dict[str, Any],
) -> None:
identity = manifest.get("identity")
cases = catalog.get("cases")
if (
manifest.get("schema_version") != NATIVE_LAB_SCHEMA
or manifest.get("result_id") != candidate.name
or manifest.get("status") != "complete-review-ready-quality-not-adjudicated"
or manifest.get("completed") is not True
or manifest.get("bounded_question_accepted") is not True
or manifest.get("ground_truth") is not False
or not isinstance(manifest.get("created_at_utc"), str)
or not isinstance(identity, dict)
or manifest.get("identity_sha256") != _canonical_sha256(identity)
or not candidate.name.endswith(str(manifest.get("identity_sha256")))
or identity.get("authority") != false_authority()
or manifest.get("authority") != false_authority()
or report.get("schema_version") != NATIVE_REPORT_SCHEMA
or report.get("result_id") != candidate.name
or report.get("authority") != false_authority()
or report.get("decision", {}).get("review_ready") is not True
or report.get("decision", {}).get("quality_evaluated") is not False
or report.get("decision", {}).get("candidate_accepted") is not False
or catalog.get("schema_version") != NATIVE_CATALOG_SCHEMA
or catalog.get("result_id") != candidate.name
or catalog.get("case_count") != 24
or catalog.get("ground_truth") is not False
or not isinstance(cases, list)
or len(cases) != 24
or any(not _valid_native_case(item) for item in cases)
):
raise RuntimeError("M4.8Q result contract changed")
def _valid_legacy_case(value: object) -> bool:
return (
isinstance(value, dict)
and isinstance(value.get("case_id"), str)
and CASE_ID.fullmatch(value["case_id"]) is not None
and LEGACY_CASE_ID.fullmatch(value["case_id"]) is not None
and value.get("image_id") == int(value["case_id"])
and value.get("path") == f"review/review-{value['case_id']}.jpg"
and value.get("media_type") == "image/jpeg"
and isinstance(value.get("byte_length"), int)
and _valid_file_proof(value)
)
def _valid_native_case(value: object) -> bool:
if not isinstance(value, dict) or not isinstance(value.get("case_id"), str):
return False
case_id = value["case_id"]
proposals = value.get("proposals")
return (
NATIVE_CASE_ID.fullmatch(case_id) is not None
and value.get("sequence") == int(case_id)
and value.get("frame_id") == f"frame-{case_id}"
and isinstance(value.get("evidence_time_ns"), int)
and value.get("path") == f"cases/frame-{case_id}.jpg"
and value.get("media_type") == "image/jpeg"
and value.get("width") == 800
and value.get("height") == 600
and value.get("geometric_resampling") is False
and isinstance(value.get("selection_buckets"), list)
and isinstance(value.get("comparison"), dict)
and isinstance(proposals, list)
and len(proposals) > 0
and all(_valid_native_proposal(item) for item in proposals)
and _valid_file_proof(value)
)
def _valid_native_proposal(value: object) -> bool:
if not isinstance(value, dict):
return False
box = value.get("box_xyxy")
return (
isinstance(value.get("proposal_id"), str)
and isinstance(value.get("class_name"), str)
and isinstance(value.get("risk_family"), str)
and isinstance(value.get("score"), (int, float))
and not isinstance(value.get("score"), bool)
and 0.25 <= value["score"] <= 1
and isinstance(box, list)
and len(box) == 4
and all(isinstance(item, (int, float)) and not isinstance(item, bool) for item in box)
and 0 <= box[0] < box[2] <= 800
and 0 <= box[1] < box[3] <= 600
)
def _valid_file_proof(value: dict[str, Any]) -> bool:
return (
isinstance(value.get("byte_length"), int)
and value["byte_length"] > 0
and isinstance(value.get("sha256"), str)
and re.fullmatch(r"[a-f0-9]{64}", value["sha256"]) is not None
)
def _resolve_candidate(provider: RootProvider, result_id: str) -> Path:
if RESULT_ID.fullmatch(result_id) is None:
raise HTTPException(status_code=404, detail="M4.8T result not found")
def _resolve_candidate(
legacy_provider: RootProvider,
native_provider: RootProvider,
result_id: str,
) -> tuple[Path, Variant]:
provider: RootProvider
variant: Variant
if NATIVE_RESULT_ID.fullmatch(result_id) is not None:
provider, variant = native_provider, "native"
elif LEGACY_RESULT_ID.fullmatch(result_id) is not None:
provider, variant = legacy_provider, "legacy"
else:
raise HTTPException(status_code=404, detail="M4.8 result not found")
root = _configured_root(provider)
if root is None:
raise HTTPException(status_code=404, detail="M4.8T result not found")
raise HTTPException(status_code=404, detail="M4.8 result not found")
candidate = (root / result_id).resolve()
if candidate.parent != root or candidate.is_symlink() or not candidate.is_dir():
raise HTTPException(status_code=404, detail="M4.8T result not found")
return candidate
raise HTTPException(status_code=404, detail="M4.8 result not found")
return candidate, variant
def _configured_root(provider: RootProvider) -> Path | None:
@@ -251,29 +486,18 @@ def _configured_root(provider: RootProvider) -> Path | None:
return root if root.is_dir() else None
def _candidates(root: Path) -> list[Path]:
def _candidates(root: Path, pattern: re.Pattern[str]) -> list[Path]:
return sorted(
(
item
for item in root.iterdir()
if item.is_dir() and not item.is_symlink() and RESULT_ID.fullmatch(item.name)
if item.is_dir() and not item.is_symlink() and pattern.fullmatch(item.name)
),
key=lambda item: item.stat().st_mtime_ns,
reverse=True,
)
def _empty_catalog(configured: bool) -> dict[str, object]:
return {
"schema_version": CATALOG_VIEW_SCHEMA,
"configured": configured,
"items": [],
"candidate_total": 0,
"invalid_total": 0,
"access": "read-only",
}
def _read_object(path: Path) -> dict[str, Any]:
value = json.loads(path.read_text("utf-8"))
if not isinstance(value, dict):
@@ -152,6 +152,15 @@ def test_profile_is_strict_digest_bound_and_store_accepts_exact_evidence() -> No
assert store.profile.local_surface_sha256 == (
"f57eb2485b6cef47f2a97a2d9ff1aa9fd9265fe1eb69cd5852d12f39e13b8bc6"
)
step_candidates = store.point_step_candidates_for_frame(0)
assert step_candidates is not None
assert step_candidates.shape == (2389,)
assert step_candidates.dtype == np.uint8
assert step_candidates.flags.writeable is False
with pytest.raises(ValueError):
step_candidates[0] = 0
with pytest.raises(GeometryProviderError, match="frame index"):
store.point_step_candidates_for_frame(True)
def test_provider_arbitrates_points_and_publishes_classless_geometry_only() -> None:
+14 -3
View File
@@ -127,7 +127,7 @@ def test_product_registry_declares_every_advanced_evidence_source() -> None:
repository_root / "config" / "laboratories"
)
assert len(registry.definitions) == 38
assert len(registry.definitions) == 39
assert {item.work_id for item in registry.definitions} >= {
"e31-source-binding",
"e46j-raw-fisheye-realtime",
@@ -141,15 +141,26 @@ def test_product_registry_declares_every_advanced_evidence_source() -> None:
"m47-reference-graph-shadow",
"m48-object-centric-quality",
"m48-small-static-passage-regression",
"m48-static-occupancy-qualification",
"m48s-fixed-class-detector",
"m48t-risk-quality-temporal",
}
m48 = next(
item for item in registry.definitions
if item.work_id == "m48-object-centric-quality"
item for item in registry.definitions if item.work_id == "m48-object-centric-quality"
)
assert [variant.phase for variant in m48.evidence_variants] == ["review", "result"]
assert [variant.result_id_prefix for variant in m48.evidence_variants] == [
"m48-object-quality-pack",
"m48-object-quality-result",
]
m48t = next(
item for item in registry.definitions if item.work_id == "m48t-risk-quality-temporal"
)
assert [variant.phase for variant in m48t.evidence_variants] == [
"legacy-quality",
"result",
]
assert [variant.result_id_prefix for variant in m48t.evidence_variants] == [
"m48t-risk-quality-temporal-lab",
"m48q-native-risk-quality-lab",
]
+4
View File
@@ -92,6 +92,7 @@ def test_repository_registry_classifies_every_evidence_definition() -> None:
assert {row.work_id for row in execution.definitions} == {
"m48-small-static-passage-regression",
"m48-static-occupancy-qualification",
"m48-object-centric-quality",
"m4-replay-threat",
"e33-worker-shadow",
@@ -108,6 +109,9 @@ def test_repository_registry_classifies_every_evidence_definition() -> None:
assert by_work_id["m48-object-centric-quality"].evidence_contract == (
"missioncore.m48-object-centric-quality-result/v1"
)
assert by_work_id["m48-static-occupancy-qualification"].evidence_contract == (
"missioncore.m48-static-occupancy-qualification-result/v1"
)
assert by_work_id["e47-semantic-slam-shadow"].lifecycle == "experimental"
assert by_work_id["e47-semantic-slam-shadow"].isolation == "bounded-adapter"
assert by_work_id["m48s-fixed-class-detector"].lifecycle == "experimental"
@@ -80,7 +80,7 @@ def test_product_value_review_registry_covers_reviewed_laboratory_families() ->
root / "config" / "laboratory-value-review.json"
)
assert len(registry.entries) == 37
assert len(registry.entries) == 38
assert {entry.catalog_id for entry in registry.entries} >= {
"e28-local-surface",
"e46d-temporal-failure-audit",
@@ -88,6 +88,7 @@ def test_product_value_review_registry_covers_reviewed_laboratory_families() ->
"l31-pointpillars-ravnoves",
"l34f-adjudicated-reference",
"m4-replay-threat",
"m48-static-occupancy-qualification",
"m48s-fixed-class-detector",
"m48t-risk-quality-temporal",
}
+105
View File
@@ -217,6 +217,82 @@ def _fixture(
lambda _: regression_result,
)
static_occupancy_result_id = f"m48-static-occupancy-qualification-{'e' * 64}"
static_occupancy_root = tmp_path / "static-occupancy" / static_occupancy_result_id
static_occupancy_root.mkdir(parents=True)
static_occupancy_result = SimpleNamespace(
result_id=static_occupancy_result_id,
result_root=static_occupancy_root,
manifest={
"created_at_utc": "2026-08-26T12:00:00Z",
"accepted": False,
},
report={
"source": {
"m47_lab_result_id": f"m47-reference-graph-lab-{'c' * 64}",
"small_static_result_id": regression_result_id,
},
"configuration": {
"run_label": "M4.8R2",
"pipeline_id": "m4-current-rolling-plus-step-static-occupancy/v1",
"experiment_id": "m48-static-occupancy-qualification/v1",
},
"metrics": {
"operator_static_anchor_count": 1,
"baseline_qualified_count": 0,
"candidate_qualified_count": 1,
"unresolved_unknown_count": 0,
"critical_near_anchor_count": 1,
"critical_near_baseline_recall": 0.0,
"critical_near_candidate_recall": 1.0,
"approach_anchor_count": 0,
"approach_baseline_recall": 0.0,
"approach_candidate_recall": 0.0,
"canonical_engineering_anchor_count": 4,
"canonical_engineering_recall": 1.0,
"false_free_count": 0,
},
"gates": {
"critical_near_candidate_recall": True,
"approach_candidate_recall": False,
"canonical_engineering_recall": True,
"zero_false_free": True,
"independent_truth_available": False,
},
"decision": {
"state": "partial-static-occupancy-qualification",
"critical_near_candidate_ready_for_shadow": True,
"production_accepted": False,
"summary": "fixture",
"next_action": "worker shadow",
},
},
cases=(
{
"anchor_id": regression_anchor_id,
"clip_id": "neutral-clip-01",
"sequence": 1,
"extent_xyxy": [0.2, 0.2, 0.3, 0.4],
"distance_m": 3.0,
"distance_band": "critical-near",
"accepted_graph": {
"matched": False,
"component_count": 0,
"components": [],
"free_space_claimed": False,
},
"baseline_qualified": False,
"candidate_qualified": True,
"outcome": "candidate-qualified",
},
),
)
monkeypatch.setattr(
api,
"read_m48_static_occupancy_qualification",
lambda _: static_occupancy_result,
)
observations: dict[str, list[dict[str, Any]]] = {
"reviews": [],
"adjudications": [],
@@ -444,6 +520,7 @@ def _fixture(
truth_root_provider=lambda: tmp_path / "truth",
result_root_provider=lambda: tmp_path / "results",
small_static_result_root_provider=lambda: tmp_path / "small-static",
static_occupancy_result_root_provider=lambda: tmp_path / "static-occupancy",
camera_frame_provider=camera,
camera_playback_provider=camera_playback, # type: ignore[arg-type]
spatial_evidence_provider=spatial_frame if spatial else None,
@@ -1128,3 +1205,31 @@ def test_m48_small_static_regression_is_separate_read_only_assisted_evidence(
assert body["ground_truth"] is False
assert body["camera_url"].endswith("/frames/1/camera")
assert body["spatial_url"].endswith("/frames/1/spatial")
def test_m48_static_occupancy_qualification_is_read_only_bounded_evidence(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
client, _, _ = _fixture(tmp_path, monkeypatch, spatial=True)
result_id = f"m48-static-occupancy-qualification-{'e' * 64}"
summary = client.get(
f"/api/v1/laboratory/m48/regressions/static-occupancy/{result_id}"
)
assert summary.status_code == 200
assert summary.headers["cache-control"] == "no-store"
assert summary.json()["run_label"] == "M4.8R2"
assert summary.json()["accepted"] is False
assert summary.json()["ground_truth"] is False
assert summary.json()["independent_truth"] is False
assert summary.json()["metrics"]["critical_near_candidate_recall"] == 1.0
assert summary.json()["decision"]["production_accepted"] is False
catalog = client.get(
f"/api/v1/laboratory/m48/regressions/static-occupancy/{result_id}/cases"
)
assert catalog.status_code == 200
assert catalog.json()["case_count"] == 1
assert catalog.json()["cases"][0]["outcome"] == "candidate-qualified"
assert catalog.json()["cases"][0]["accepted_graph"]["free_space_claimed"] is False
@@ -0,0 +1,106 @@
from __future__ import annotations
from pathlib import Path
import pytest
import k1link.laboratory.m48_static_occupancy_qualification as qualification
from k1link.laboratory.evidence_registry import LaboratoryEvidenceRegistry
from k1link.laboratory.evidence_report import verify_laboratory_evidence_result
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
AUTHORITY = {
"mode": "replay-simulated",
"physical_live": False,
"commands_enabled": False,
"actuation_allowed": False,
"navigation_or_safety_accepted": False,
}
def _sealed_result(tmp_path: Path) -> qualification.M48StaticOccupancyQualificationResult:
identity = {
"schema_version": qualification.M48_STATIC_OCCUPANCY_RESULT_SCHEMA,
"human_lab_id": "M4.8R2",
"run_label": "fixture",
"run_created_at_utc": "2026-08-26T12:00:00Z",
"authority": AUTHORITY,
}
result_id = qualification.M48_STATIC_OCCUPANCY_PREFIX + qualification._canonical_sha256(
identity
)
report = {
"schema_version": qualification.M48_STATIC_OCCUPANCY_REPORT_SCHEMA,
"result_id": result_id,
"metrics": {
"operator_static_anchor_count": 1,
"candidate_qualified_count": 1,
},
"decision": {"production_accepted": False},
"authority": AUTHORITY,
}
cases = (
{
"schema_version": qualification.M48_STATIC_OCCUPANCY_CASE_SCHEMA,
"anchor_id": "anchor-" + "a" * 24,
"sequence": 10,
"baseline_qualified": False,
"candidate_qualified": True,
"outcome": "candidate-qualified",
},
)
canonical = (
{
"schema_version": qualification.M48_STATIC_OCCUPANCY_CANONICAL_SCHEMA,
"anchor_id": "hemisphere-01",
"sequence": 1880,
"matched": True,
},
)
destination = tmp_path / "results" / result_id
qualification._publish_result(
destination,
identity,
"2026-08-26T12:00:00Z",
False,
report,
cases,
canonical,
)
return qualification.read_m48_static_occupancy_qualification(destination)
def test_seals_bounded_static_occupancy_evidence_without_production_authority(
tmp_path: Path,
) -> None:
result = _sealed_result(tmp_path)
assert result.manifest["accepted"] is False
assert result.manifest["ground_truth"] is False
assert result.manifest["authority"] == AUTHORITY
assert result.report["decision"]["production_accepted"] is False
assert result.cases[0]["outcome"] == "candidate-qualified"
registry = LaboratoryEvidenceRegistry.from_directory(
REPOSITORY_ROOT / "config/laboratories"
)
definition = next(
row
for row in registry.definitions
if row.work_id == "m48-static-occupancy-qualification"
)
proof = verify_laboratory_evidence_result(definition, result.result_root)
assert proof["result_id"] == result.result_id
assert proof["artifact_count"] == 3
def test_reader_rejects_changed_static_occupancy_case_ledger(tmp_path: Path) -> None:
result = _sealed_result(tmp_path)
cases_path = result.result_root / "cases.jsonl"
cases_path.write_bytes(cases_path.read_bytes() + b"{}\n")
with pytest.raises(
qualification.M48StaticOccupancyQualificationError,
match="artifact proof",
):
qualification.read_m48_static_occupancy_qualification(result.result_root)
@@ -0,0 +1,90 @@
from __future__ import annotations
import importlib.util
import sys
from pathlib import Path
import pytest
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
RUNNER_PATH = (
REPOSITORY_ROOT / "experiments" / "perception" / "run_m48q_native_risk_case_mining_worker.py"
)
SPEC = importlib.util.spec_from_file_location("m48q_case_mining", RUNNER_PATH)
assert SPEC is not None and SPEC.loader is not None
MODULE = importlib.util.module_from_spec(SPEC)
sys.modules[SPEC.name] = MODULE
SPEC.loader.exec_module(MODULE)
def candidate(sequence: int, *buckets: str):
return MODULE.FrameCandidate(
sequence=sequence,
frame_id=f"frame-{sequence:06d}",
evidence_time_ns=sequence * 1_000_000,
proposals=(),
native_count=0,
legacy_count=0,
matched_count=0,
buckets=frozenset(buckets),
)
def test_selection_is_deterministic_balanced_and_separated() -> None:
candidates = [
candidate(sequence, "person" if sequence % 2 == 0 else "vehicle")
for sequence in range(0, 400, 5)
]
quotas = {"person": 3, "vehicle": 3}
first = MODULE.select_cases(
candidates,
bucket_quotas=quotas,
minimum_sequence_separation=10,
)
second = MODULE.select_cases(
candidates,
bucket_quotas=quotas,
minimum_sequence_separation=10,
)
assert [item.sequence for item in first] == [item.sequence for item in second]
assert len(first) == 6
assert all(
abs(left.sequence - right.sequence) >= 10
for index, left in enumerate(first)
for right in first[index + 1 :]
)
def test_selection_refuses_missing_bucket_coverage() -> None:
with pytest.raises(MODULE.M48QCaseMiningError, match="animal produced 0/1"):
MODULE.select_cases(
[candidate(0, "person")],
bucket_quotas={"animal": 1},
minimum_sequence_separation=1,
)
def test_profile_freezes_raw_raster_and_false_authority() -> None:
import json
profile = json.loads(
(
REPOSITORY_ROOT / "config" / "perception" / "m48q-native-risk-case-mining-v1.json"
).read_text("utf-8")
)
assert profile["source"] == {
"source_id": "RAVNOVES00",
"frame_count": 4489,
"raster_width": 800,
"raster_height": 600,
"video_sha256": "cadd1696ff000904eb78633a0a8418104b8024f178b91f3421789021ccb160e8",
"geometric_resampling": False,
"rectification": False,
"warp": False,
}
assert sum(profile["selection"]["bucket_quotas"].values()) == 24
assert profile["scope"]["quality_evaluated"] is False
assert profile["authority"] == MODULE.FALSE_AUTHORITY
+138
View File
@@ -6,6 +6,18 @@ from pathlib import Path
from fastapi import FastAPI
from fastapi.testclient import TestClient
from k1link.laboratory.m48q_native_risk_quality_lab import (
CATALOG_SCHEMA as NATIVE_CATALOG_SCHEMA,
)
from k1link.laboratory.m48q_native_risk_quality_lab import (
LAB_SCHEMA as NATIVE_LAB_SCHEMA,
)
from k1link.laboratory.m48q_native_risk_quality_lab import (
REPORT_SCHEMA as NATIVE_REPORT_SCHEMA,
)
from k1link.laboratory.m48q_native_risk_quality_lab import (
RESULT_PREFIX as NATIVE_RESULT_PREFIX,
)
from k1link.laboratory.m48t_risk_quality_lab import (
CATALOG_SCHEMA,
LAB_SCHEMA,
@@ -150,3 +162,129 @@ def test_m48t_lab_api_fails_closed_after_visual_tamper(tmp_path: Path) -> None:
catalog = client.get("/api/v1/laboratory/m48t/risk-quality/results")
assert catalog.json()["items"] == []
assert catalog.json()["invalid_total"] == 1
def _native_fixture(tmp_path: Path) -> tuple[TestClient, Path, str]:
root = tmp_path / "native-results"
root.mkdir()
identity = {"schema_version": NATIVE_LAB_SCHEMA, "authority": false_authority()}
identity_sha256 = hashlib.sha256(canonical_json(identity)).hexdigest()
result_id = NATIVE_RESULT_PREFIX + identity_sha256
result_root = root / result_id
cases_root = result_root / "cases"
cases_root.mkdir(parents=True)
cases = []
image_paths = []
for index in range(24):
case_id = f"{index * 20 + 12:06d}"
image_path = cases_root / f"frame-{case_id}.jpg"
image_path.write_bytes(b"native-jpeg" + bytes([index]))
image_paths.append(image_path)
cases.append(
{
"case_id": case_id,
"sequence": int(case_id),
"frame_id": f"frame-{case_id}",
"evidence_time_ns": 35_000_000_000 + index * 1_000_000,
"path": f"cases/{image_path.name}",
"media_type": "image/jpeg",
"width": 800,
"height": 600,
"byte_length": image_path.stat().st_size,
"sha256": hashlib.sha256(image_path.read_bytes()).hexdigest(),
"geometric_resampling": False,
"selection_buckets": ["person"],
"comparison": {
"native_detection_count": 1,
"legacy_704_detection_count": 1,
"matched_detection_count_iou_at_least_0_5": 1,
},
"proposals": [
{
"proposal_id": f"proposal-{index}-0",
"class_name": "person",
"risk_family": "person",
"score": 0.75,
"box_xyxy": [10.0, 20.0, 100.0, 200.0],
}
],
}
)
catalog = {
"schema_version": NATIVE_CATALOG_SCHEMA,
"result_id": result_id,
"case_count": 24,
"source_raster": {"width": 800, "height": 600},
"overlay": {"client_rendered": True, "toggleable": True},
"ground_truth": False,
"cases": cases,
}
report = {
"schema_version": NATIVE_REPORT_SCHEMA,
"result_id": result_id,
"source": {},
"configuration": {},
"method": {},
"execution": {},
"metrics": {},
"acceptance": {},
"decision": {
"review_ready": True,
"quality_evaluated": False,
"candidate_accepted": False,
},
"limitations": [],
"authority": false_authority(),
}
catalog_path = result_root / "catalog.json"
report_path = result_root / "report.json"
_write_json(catalog_path, catalog)
_write_json(report_path, report)
artifacts = [
_descriptor(catalog_path, result_root, "visual-evidence-catalog", "application/json"),
_descriptor(report_path, result_root, "laboratory-report", "application/json"),
*[
_descriptor(path, result_root, "visual-evidence-native-raw-fisheye-frame", "image/jpeg")
for path in image_paths
],
]
manifest = {
"schema_version": NATIVE_LAB_SCHEMA,
"result_id": result_id,
"identity_sha256": identity_sha256,
"identity": identity,
"created_at_utc": "2026-08-26T09:45:15.574709Z",
"status": "complete-review-ready-quality-not-adjudicated",
"completed": True,
"bounded_question_accepted": True,
"ground_truth": False,
"authority": false_authority(),
"artifacts": artifacts,
}
_write_json(result_root / "manifest.json", manifest)
app = FastAPI()
app.include_router(build_m48t_risk_quality_lab_router(native_root_provider=lambda: root))
return TestClient(app), result_root, result_id
def test_m48q_lab_api_projects_native_raw_cases_without_quality_promotion(
tmp_path: Path,
) -> None:
client, result_root, result_id = _native_fixture(tmp_path)
catalog = client.get("/api/v1/laboratory/m48t/risk-quality/results")
assert catalog.status_code == 200
assert catalog.json()["items"][0]["variant"] == "native-risk-review"
result = client.get(f"/api/v1/laboratory/m48t/risk-quality/results/{result_id}")
assert result.status_code == 200
assert result.json()["ground_truth"] is False
assert result.json()["decision"]["quality_evaluated"] is False
assert len(result.json()["review"]["cases"]) == 24
assert result.json()["review"]["cases"][0]["geometric_resampling"] is False
case_id = "000012"
image = client.get(
f"/api/v1/laboratory/m48t/risk-quality/results/{result_id}/review/{case_id}.jpg"
)
assert image.status_code == 200
assert image.content == (result_root / f"cases/frame-{case_id}.jpg").read_bytes()