feat(lab): seal native risk review evidence
This commit is contained in:
@@ -145,11 +145,21 @@ def test_product_registry_declares_every_advanced_evidence_source() -> None:
|
||||
"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",
|
||||
]
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user