feat(observatory): admit canonical recorded replay

This commit is contained in:
DCCONSTRUCTIONS
2026-08-30 19:21:27 +03:00
parent e6a9846167
commit 023151c186
32 changed files with 4069 additions and 342 deletions
+546
View File
@@ -0,0 +1,546 @@
from __future__ import annotations
import hashlib
import json
import struct
from pathlib import Path
from types import SimpleNamespace
from typing import Any
import pytest
import k1link.laboratory.canonical_recorded_catalog as canonical_catalog
from k1link.laboratory.canonical_recorded_catalog import (
CANONICAL_REPLAY_CAPABILITY_SCHEMA,
CanonicalRecordedCatalogError,
publish_canonical_recorded_vegetation_result,
)
class CapturingStore:
def __init__(self, *, source_label: str = "RAVNOVES004TREE") -> None:
self.parameters: dict[str, Any] | None = None
self.source_label = source_label
def publish_lab_instance(self, **parameters: Any) -> dict[str, Any]:
self.parameters = parameters
return parameters
def get_session_with_catalog_snapshot(
self,
session_id: str,
) -> tuple[SimpleNamespace, str]:
assert session_id == "20260828T130511Z_viewer_live"
summary = SimpleNamespace(
session_id=session_id,
display_name=self.source_label,
status="ready",
started_at_utc="2026-08-28T13:05:16.249Z",
completed_at_utc="2026-08-28T13:18:45.030Z",
duration_seconds=808.779495667,
modalities=("point-cloud", "trajectory", "video"),
source_count=3,
total_bytes=799_020_963,
replayable=True,
lab=None,
)
sources = tuple(
SimpleNamespace(
source_id=source_id,
semantic_channel_id=semantic_channel_id,
modality=modality,
status="recorded",
seekable=True,
artifact_id=artifact_id,
)
for source_id, semantic_channel_id, modality, artifact_id in (
(
"sensor.camera.right",
"camera.video.recorded",
"video",
"recorded-video-6a3945242828a038",
),
(
"sensor.lidar.primary",
"spatial.point-cloud.recorded",
"point-cloud",
"raw-transport-primary",
),
(
"spatial.trajectory",
"spatial.pose.recorded",
"trajectory",
"raw-transport-primary",
),
)
)
artifacts = (
SimpleNamespace(
artifact_id="raw-transport-clock",
kind="raw-transport-clock",
media_type="application/json",
byte_length=189,
sha256="1" * 64,
integrity_status="verified",
),
SimpleNamespace(
artifact_id="raw-transport-clock-origin",
kind="raw-transport-clock-origin",
media_type="application/json",
byte_length=103,
sha256="2" * 64,
integrity_status="verified",
),
SimpleNamespace(
artifact_id="raw-transport-index",
kind="raw-transport-index",
media_type="application/x-ndjson",
byte_length=7_679_275,
sha256=None,
integrity_status="verified",
),
SimpleNamespace(
artifact_id="raw-transport-primary",
kind="raw-transport",
media_type="application/x-nodedc-k1mqtt",
byte_length=245_183_013,
sha256="20c789eff922a6bbb53592f86614abc0729a30544df29e740e7a378d12af85c2",
integrity_status="verified",
),
SimpleNamespace(
artifact_id="recorded-video-6a3945242828a038",
kind="recorded-video",
media_type="video/mp4",
byte_length=553_837_950,
sha256=None,
integrity_status="validated-structure",
),
)
return (
SimpleNamespace(
summary=summary,
sources=sources,
artifacts=artifacts,
plugin_id="nodedc.device.xgrids-lixelkity-k1",
archive_id="xgrids-k1.viewer-live.evidence",
),
"a" * 64,
)
def _canonical_sha256(value: object) -> str:
encoded = json.dumps(
value,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
).encode("utf-8")
return hashlib.sha256(encoded).hexdigest()
def _sealed_result(runtime_root: Path) -> Path:
authority = {
"commands_enabled": False,
"navigation_or_safety_accepted": False,
"actuation_accepted": False,
"camera_semantics_can_clear_rigid_geometry": False,
}
timeline_payload = struct.pack(
"<6830Q",
*(39_250_000_000 + index * 100_000_000 for index in range(6830)),
)
artifact_payloads = {
"video/eomt-semantic-masks.zip": b"fixture-city-mask-archive",
"video/ddrnet-semantic-masks.zip": b"fixture-vegetation-mask-archive",
"video/frame-source-times-ns.bin": timeline_payload,
"proofs/job.json": b'{"fixture":"job"}',
"proofs/decode_repair.json": b'{"fixture":"decode"}',
"proofs/ddrnet_decode_repair.json": b'{"fixture":"decode"}',
}
def proof(path: str) -> dict[str, object]:
payload = artifact_payloads[path]
return {
"path": path,
"sha256": hashlib.sha256(payload).hexdigest(),
"byte_length": len(payload),
}
def taxonomy(schema: str, count: int) -> dict[str, object]:
return {
"schema_version": schema,
"classes": [
{
"class_id": index,
"label": f"class-{index}",
"color_rgb": [index % 256, (index * 2) % 256, (index * 3) % 256],
"disposition": "undefined" if index == 0 else "prediction",
}
for index in range(count)
],
}
review = {
"source_id": "RAVNOVES004TREE",
"session_id": "20260828T130511Z_viewer_live",
"source_job_id": "recorded-camera-eb2783c5480d56bda07c8af0",
"source_job_input_sha256": (
"eb2783c5480d56bda07c8af008dff5344d19dc550ef70fe2075d6f098f7cc715"
),
"source_stream_sha256": (
"e5eb017e2cc0f546736eda5235ca157b501913093cb64af5e548e335417e1bac"
),
"recorded_media_source_id": "recorded.camera.6a3945242828a038",
"recorded_media_generation_sha256": (
"b073ea1e7babf1c77a664e1a5b95e3702d0e05b0e34c1e85a7c67a6f8b392ded"
),
"linked_route_review_result_id": (
"lab-v1-vegetation-shadow-" + "9" * 64
),
"frame_count": 6830,
"width": 800,
"height": 600,
"ground_truth": False,
"timeline_start_seconds": 39.25,
"timeline_end_seconds": 757.25,
"timeline": {
**proof("video/frame-source-times-ns.bin"),
"encoding": "uint64-le-nanoseconds",
"frame_count": 6830,
},
"decode_repair": {
"repaired_frame_count": 1,
"sequence": 6092,
"method": "duplicate-previous-decoded-frame",
"proofs": {
"eomt": proof("proofs/decode_repair.json"),
"ddrnet": proof("proofs/ddrnet_decode_repair.json"),
},
},
"proofs": {"job": proof("proofs/job.json")},
"layers": {
"city": {
"name": "EoMT Cityscapes",
"result_id": "result-" + "1" * 64,
"frame_count": 6830,
"taxonomy": taxonomy(
"missioncore.recorded-eomt-taxonomy/v1",
16,
),
"mask_archive": proof("video/eomt-semantic-masks.zip"),
"inference_fps": 3.0,
"latency_p95_ms": 361.0,
"peak_reserved_vram_bytes": 2_977_955_840,
},
"vegetation": {
"name": "ddrnet_39",
"result_id": "lab-v1-ravnoves-video-ddrnet-" + "2" * 64,
"frame_count": 6830,
"taxonomy": taxonomy(
"missioncore.lab-v1-vegetation-taxonomy/v1",
64,
),
"mask_archive": proof("video/ddrnet-semantic-masks.zip"),
"inference_fps": 52.0,
"latency_p95_ms": 27.0,
"peak_reserved_vram_bytes": 331_350_016,
},
},
}
candidates = {
candidate: {
"loaded_model_name": candidate,
"checkpoint_sha256": str(index) * 64,
"validation_metrics": {
"mean_iou_percent": 70.0,
"published_mean_iou_percent": 69.0,
"vegetation_mean_iou": 0.7,
},
"validation_timing": {
"latency_ms_p95": 20.0,
"throughput_fps_from_mean_inference": 50.0,
},
"shadow_timing": {
"latency_ms_p95": 21.0,
"throughput_fps_from_mean_inference": 49.0,
"prewarm_latency_ms": 100.0,
},
"resource": {
"peak_reserved_vram_bytes": 1024,
"gpu_name": "fixture-gpu",
},
}
for index, candidate in enumerate(("ddrnet", "ppliteseg"), start=3)
}
source = {
"shadow_session": "RAVNOVES004TREE",
"shadow_camera": "sensor.camera.right",
"shadow_frame_count": 6830,
"video_shadow_frame_count": 6830,
}
identity = {
"authority": authority,
"base_result_id": "lab-v1-vegetation-shadow-" + "9" * 64,
"route_full_review": review,
"selected_candidate": "ddrnet",
"candidate_metrics": candidates,
"source": source,
}
identity_sha256 = _canonical_sha256(identity)
result_id = f"lab-v1-vegetation-shadow-{identity_sha256}"
result_root = runtime_root / "lab-v1-vegetation" / "results" / result_id
result_root.mkdir(parents=True)
document = {
"schema_version": "missioncore.lab-v1-vegetation-shadow/v1",
"result_id": result_id,
"identity": identity,
"identity_sha256": identity_sha256,
"created_at_utc": "2026-08-29T18:05:11.329061+00:00",
"ground_truth": False,
"status": "visual-shadow-ready-policy-not-authorized",
"authority": dict(authority),
"source": source,
"route_video": None,
"route_review": None,
"route_full_review": dict(review),
"method": {
"completeness": "complete",
"execution_class": "ai-inference",
"pipeline_id": "ravnoves004tree-full-eomt-ddrnet-recorded-review/v1",
},
"metrics": {"candidates": candidates},
"decision": {
"selected_candidate": "ddrnet",
"visual_shadow_ready": True,
"mission_policy_ready_for_configuration": True,
"navigation_accepted": False,
"production_accepted": False,
},
"limitations": ["fixture is observation-only"],
"catalogs": {"goose": [], "ravnoves": []},
"artifacts": [
{
**proof(path),
"role": "fixture",
"media_type": (
"application/zip"
if path.endswith(".zip")
else "application/octet-stream"
if path.endswith(".bin")
else "application/json"
),
}
for path in artifact_payloads
],
}
for relative, payload in artifact_payloads.items():
path = result_root / relative
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(payload)
(result_root / "result.json").write_text(
json.dumps(document, ensure_ascii=False, sort_keys=True),
encoding="utf-8",
)
return result_root
def test_canonical_recorded_projection_uses_exact_session_binding_without_compute(
tmp_path: Path,
) -> None:
runtime_root = tmp_path / "runtime"
runtime_root.mkdir()
result_root = _sealed_result(runtime_root)
store = CapturingStore()
published = publish_canonical_recorded_vegetation_result(
store=store, # type: ignore[arg-type]
runtime_root=runtime_root,
result_root=result_root,
)
assert published["session_id"] == result_root.name
assert published["source_session_id"] == "20260828T130511Z_viewer_live"
assert published["source_result_id"] == "lab-v1-vegetation-shadow-" + "9" * 64
assert published["config_sha256"] is None
assert published["duration_seconds"] == pytest.approx(718.0)
assert published["include_recorded_media"] is False
assert published["expected_source_catalog_sha256"] == "a" * 64
capability = published["replay_capability"]
assert capability.as_dict() == {
"schema_version": CANONICAL_REPLAY_CAPABILITY_SCHEMA,
"kind": "canonical-recorded-rerun",
"viewer_profile": "recorded-session",
"timeline": "session_time",
"activation": "explicit",
"commands_enabled": False,
}
assert published["provenance"]["replay_capability"] == capability.as_dict()
assert published["provenance"]["method"]["completeness"] == "legacy-partial"
def test_canonical_recorded_projection_rejects_authority_and_unregistered_root(
tmp_path: Path,
) -> None:
runtime_root = tmp_path / "runtime"
runtime_root.mkdir()
result_root = _sealed_result(runtime_root)
document_path = result_root / "result.json"
document = json.loads(document_path.read_text(encoding="utf-8"))
document["authority"]["commands_enabled"] = True
document_path.write_text(json.dumps(document, sort_keys=True), encoding="utf-8")
with pytest.raises(CanonicalRecordedCatalogError, match="control authority"):
publish_canonical_recorded_vegetation_result(
store=CapturingStore(), # type: ignore[arg-type]
runtime_root=runtime_root,
result_root=result_root,
)
document["authority"]["commands_enabled"] = False
document_path.write_text(json.dumps(document, sort_keys=True), encoding="utf-8")
outside = tmp_path / result_root.name
outside.mkdir()
(outside / "result.json").write_text(
document_path.read_text(encoding="utf-8"),
encoding="utf-8",
)
with pytest.raises(CanonicalRecordedCatalogError, match="registered root"):
publish_canonical_recorded_vegetation_result(
store=CapturingStore(), # type: ignore[arg-type]
runtime_root=runtime_root,
result_root=outside,
)
def test_canonical_recorded_projection_rejects_non_boolean_authority(
tmp_path: Path,
) -> None:
runtime_root = tmp_path / "runtime"
runtime_root.mkdir()
result_root = _sealed_result(runtime_root)
document_path = result_root / "result.json"
document = json.loads(document_path.read_text(encoding="utf-8"))
document["authority"]["commands_enabled"] = 0
document_path.write_text(json.dumps(document, sort_keys=True), encoding="utf-8")
with pytest.raises(CanonicalRecordedCatalogError, match="control authority"):
publish_canonical_recorded_vegetation_result(
store=CapturingStore(), # type: ignore[arg-type]
runtime_root=runtime_root,
result_root=result_root,
)
def test_canonical_recorded_projection_rejects_viewer_incomplete_result(
tmp_path: Path,
) -> None:
runtime_root = tmp_path / "runtime"
runtime_root.mkdir()
result_root = _sealed_result(runtime_root)
document_path = result_root / "result.json"
document = json.loads(document_path.read_text(encoding="utf-8"))
document.pop("metrics")
document_path.write_text(json.dumps(document, sort_keys=True), encoding="utf-8")
store = CapturingStore()
with pytest.raises(CanonicalRecordedCatalogError, match="result metrics"):
publish_canonical_recorded_vegetation_result(
store=store, # type: ignore[arg-type]
runtime_root=runtime_root,
result_root=result_root,
)
assert store.parameters is None
def test_canonical_recorded_projection_rejects_unbound_display_metrics(
tmp_path: Path,
) -> None:
runtime_root = tmp_path / "runtime"
runtime_root.mkdir()
result_root = _sealed_result(runtime_root)
document_path = result_root / "result.json"
document = json.loads(document_path.read_text(encoding="utf-8"))
document["metrics"]["candidates"]["ddrnet"]["loaded_model_name"] = "tampered"
document_path.write_text(json.dumps(document, sort_keys=True), encoding="utf-8")
with pytest.raises(CanonicalRecordedCatalogError, match="identity-bound"):
publish_canonical_recorded_vegetation_result(
store=CapturingStore(), # type: ignore[arg-type]
runtime_root=runtime_root,
result_root=result_root,
)
def test_canonical_recorded_projection_rejects_wrong_source_catalog_identity(
tmp_path: Path,
) -> None:
runtime_root = tmp_path / "runtime"
runtime_root.mkdir()
result_root = _sealed_result(runtime_root)
with pytest.raises(CanonicalRecordedCatalogError, match="source catalog identity"):
publish_canonical_recorded_vegetation_result(
store=CapturingStore(source_label="different source"), # type: ignore[arg-type]
runtime_root=runtime_root,
result_root=result_root,
)
def test_canonical_recorded_projection_rejects_intermediate_symlink_escape(
tmp_path: Path,
) -> None:
runtime_root = tmp_path / "runtime"
runtime_root.mkdir()
outside_runtime = tmp_path / "outside-runtime"
outside_runtime.mkdir()
actual_result = _sealed_result(outside_runtime)
(runtime_root / "lab-v1-vegetation").symlink_to(
outside_runtime / "lab-v1-vegetation",
target_is_directory=True,
)
escaped_result = (
runtime_root
/ "lab-v1-vegetation"
/ "results"
/ actual_result.name
)
with pytest.raises(CanonicalRecordedCatalogError, match="runtime root"):
publish_canonical_recorded_vegetation_result(
store=CapturingStore(), # type: ignore[arg-type]
runtime_root=runtime_root,
result_root=escaped_result,
)
def test_canonical_recorded_projection_rejects_document_changed_after_proof(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
runtime_root = tmp_path / "runtime"
runtime_root.mkdir()
result_root = _sealed_result(runtime_root)
original = canonical_catalog.verify_laboratory_evidence_result
def mutate_after_verification(*args: object, **kwargs: object) -> dict[str, object]:
proof = original(*args, **kwargs) # type: ignore[arg-type]
path = result_root / "result.json"
document = json.loads(path.read_text(encoding="utf-8"))
document["method"]["pipeline_id"] = "tampered-after-proof/v1"
path.write_text(json.dumps(document, sort_keys=True), encoding="utf-8")
return proof
monkeypatch.setattr(
canonical_catalog,
"verify_laboratory_evidence_result",
mutate_after_verification,
)
store = CapturingStore()
with pytest.raises(CanonicalRecordedCatalogError, match="changed after verification"):
publish_canonical_recorded_vegetation_result(
store=store, # type: ignore[arg-type]
runtime_root=runtime_root,
result_root=result_root,
)
assert store.parameters is None
+76 -1
View File
@@ -12,9 +12,10 @@ from pathlib import Path
from typing import Any
import pytest
from fastapi import APIRouter, HTTPException, Request, Response
from fastapi import APIRouter, FastAPI, HTTPException, Request, Response
from fastapi.responses import FileResponse
from fastapi.routing import APIRoute
from fastapi.testclient import TestClient
import k1link.sessions.media as recorded_media_module
import k1link.web.session_api as session_api_module
@@ -22,6 +23,7 @@ from k1link.compute import RecordedPerceptionOverlayArtifact, RecordedPerception
from k1link.device_plugins.xgrids_k1 import xgrids_k1_archive_source
from k1link.device_plugins.xgrids_k1.mqtt.capture import FRAME_HEADER, RAW_MAGIC
from k1link.sessions import (
LabReplayCapability,
MaterializedRecording,
RecordedMediaInspector,
RecordedMediaManifest,
@@ -347,6 +349,79 @@ def test_session_router_exposes_immutable_lab_provenance(tmp_path: Path) -> None
assert_no_local_paths((item, detail), repository)
def test_session_router_rolls_capability_projections_out_only_in_v2(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
source = make_legacy_session(sessions, "20260716T205632Z_viewer_live")
store = SessionStore(repository, data_dir=tmp_path / "data")
store.reconcile_archive(xgrids_k1_archive_source(sessions))
legacy = store.publish_lab_instance(
session_id="lab-e21-legacy",
source_session_id=source.name,
display_name="LAB E21 · legacy",
lab_id="LAB E21",
result_kind="e21-realtime-envelope",
result_id="e21-realtime-envelope-" + "1" * 64,
run_created_at_utc="2026-07-23T15:55:15.548Z",
provenance={"method": lab_method()},
)
capability = LabReplayCapability(
schema_version="missioncore.observation-lab-replay-capability/v1",
kind="canonical-recorded-rerun",
viewer_profile="recorded-session",
timeline="session_time",
activation="explicit",
commands_enabled=False,
)
canonical = store.publish_lab_instance(
session_id="lab-v1-vegetation-shadow-" + "8" * 64,
source_session_id=source.name,
display_name="RAV004 · recorded",
lab_id="LAB V1",
result_kind="recorded-perception-qualification",
result_id="lab-v1-vegetation-shadow-" + "8" * 64,
run_created_at_utc="2026-08-29T18:05:11.329061+00:00",
replay_capability=capability,
provenance={
"replay_capability": capability.as_dict(),
"method": lab_method(),
},
)
router = build_session_router(store)
list_route = endpoint(router, "/api/v1/observation-sessions", "GET")
default_items = list_route(limit=20, cursor=None, scope="all")["items"]
assert {item["id"] for item in default_items} == {source.name, legacy.session_id}
default_legacy = next(item for item in default_items if item["id"] == legacy.session_id)
assert "replay_capability" not in default_legacy["lab"]
v1_labs = list_route(
limit=20,
cursor=None,
scope="laboratory",
lab_contract="v1",
)["items"]
assert [item["id"] for item in v1_labs] == [legacy.session_id]
v2_labs = list_route(
limit=20,
cursor=None,
scope="laboratory",
lab_contract="v2",
)["items"]
by_id = {item["id"]: item for item in v2_labs}
assert set(by_id) == {legacy.session_id, canonical.session_id}
assert by_id[legacy.session_id]["lab"]["replay_capability"] is None
assert by_id[canonical.session_id]["lab"]["replay_capability"] == capability.as_dict()
application = FastAPI()
application.include_router(router)
assert TestClient(application).get(
"/api/v1/observation-sessions?lab_contract=v3"
).status_code == 422
def test_delete_session_removes_evidence_and_cache_but_refuses_an_open_recording(
tmp_path: Path,
) -> None:
+55
View File
@@ -16,6 +16,7 @@ from fastapi.routing import APIRoute
from k1link.device_plugins.xgrids_k1 import xgrids_k1_archive_source
from k1link.device_plugins.xgrids_k1.mqtt.capture import FRAME_HEADER, RAW_MAGIC
from k1link.sessions import (
LabReplayCapability,
SessionRecordingMaterializer,
SessionRecordingPreparationManager,
SessionStore,
@@ -200,6 +201,60 @@ def test_startup_scan_baselines_historical_sessions_without_enqueuing(
manager.close()
def test_background_scan_never_prepares_explicit_capability_projection(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
source = _make_completed_session(sessions, "20260716T205632Z_viewer_live")
store = SessionStore(repository, data_dir=tmp_path / "data")
store.reconcile_archive(xgrids_k1_archive_source(sessions))
monkeypatch.setattr(app_module, "session_store", store)
baseline = set(app_module.finalized_replayable_recording_ids())
capability = LabReplayCapability(
schema_version="missioncore.observation-lab-replay-capability/v1",
kind="canonical-recorded-rerun",
viewer_profile="recorded-session",
timeline="session_time",
activation="explicit",
commands_enabled=False,
)
projection = store.publish_lab_instance(
session_id="lab-v1-vegetation-shadow-" + "8" * 64,
source_session_id=source.name,
display_name="RAV004 · explicit recorded review",
lab_id="LAB V1",
result_kind="recorded-perception-qualification",
result_id="lab-v1-vegetation-shadow-" + "8" * 64,
run_created_at_utc="2026-08-29T18:05:11.329061+00:00",
replay_capability=capability,
provenance={
"replay_capability": capability.as_dict(),
"method": {
"schema_version": "missioncore.laboratory-method/v1",
"completeness": "legacy-partial",
"execution_class": "ai-inference",
"pipeline_id": "fixture/v1",
"components": [
{
"kind": "source",
"name": "fixture",
"version": "v1",
"role": "test",
"identity_sha256": "9" * 64,
}
],
},
},
)
current = set(app_module.finalized_replayable_recording_ids())
assert baseline == {source.name}
assert projection.session_id not in current
assert app_module.newly_finalized_recording_ids(baseline, current) == ()
def test_archive_revision_tracks_session_lifecycle_without_capture_churn(
tmp_path: Path,
) -> None:
+525
View File
@@ -15,6 +15,7 @@ from k1link.device_plugins.xgrids_k1.mqtt.capture import (
iter_capture_frames,
)
from k1link.sessions import (
LabReplayCapability,
LayoutConflictError,
SessionIntegrityError,
SessionNotFoundError,
@@ -823,6 +824,7 @@ def test_lab_instance_is_independent_and_never_deletes_source_evidence(
"method": lab_method(),
},
)
assert binding.replay_capability is None
detail = store.get_session(binding.session_id)
lab_command = store.prepare_replay(binding.session_id)
@@ -879,6 +881,421 @@ def test_lab_instance_publication_is_idempotent_but_provenance_is_immutable(
store.publish_lab_instance(**{**parameters, "config_sha256": "0" * 64})
def test_lab_replay_capability_column_migrates_existing_catalog(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
source = make_legacy_session(sessions, "20260716T205632Z_viewer_live")
data_dir = tmp_path / "data"
initial = SessionStore(repository, data_dir=data_dir)
initial.reconcile_archive(xgrids_k1_archive_source(sessions))
legacy = initial.publish_lab_instance(
session_id="lab-e19-pre-capability",
source_session_id=source.name,
display_name="LAB E19 · pre-capability",
lab_id="LAB E19",
result_kind="e19-legacy",
result_id="e19-legacy-result",
run_created_at_utc="2026-07-23T05:19:43.138Z",
provenance={"method": lab_method()},
)
with sqlite3.connect(initial.database_path) as connection:
connection.execute(
"ALTER TABLE observation_lab_instances DROP COLUMN replay_capability_json"
)
connection.execute(
"ALTER TABLE observation_lab_instances DROP COLUMN include_recorded_media"
)
connection.commit()
migrated = SessionStore(repository, data_dir=data_dir)
with sqlite3.connect(migrated.database_path) as connection:
columns = {
row[1]
for row in connection.execute(
"PRAGMA table_info(observation_lab_instances)"
)
}
assert "replay_capability_json" in columns
assert "include_recorded_media" in columns
assert migrated.get_lab_instance(legacy.session_id).replay_capability is None
def test_migration_types_only_the_exact_rolling_canonical_projection(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
source = make_legacy_session(sessions, "20260828T130511Z_viewer_live")
make_recorded_camera_source(source)
data_dir = tmp_path / "data"
initial = SessionStore(repository, data_dir=data_dir)
initial.reconcile_archive(xgrids_k1_archive_source(sessions))
with sqlite3.connect(initial.database_path) as connection:
connection.execute(
"UPDATE observation_sessions SET archive_id = ? WHERE session_id = ?",
("xgrids-k1.viewer-live.evidence", source.name),
)
connection.commit()
evidence_identity = "a" * 64
capability = LabReplayCapability(
schema_version="missioncore.observation-lab-replay-capability/v1",
kind="canonical-recorded-rerun",
viewer_profile="recorded-session",
timeline="session_time",
activation="explicit",
commands_enabled=False,
)
provenance = {
"schema_version": "missioncore.canonical-recorded-lab-projection/v1",
"evidence_identity_sha256": evidence_identity,
"result_document_sha256": "b" * 64,
"replay_capability": capability.as_dict(),
"authority": {
"commands_enabled": False,
"navigation_or_safety_accepted": False,
"actuation_accepted": False,
},
"method": {
"schema_version": "missioncore.laboratory-method/v1",
"completeness": "legacy-partial",
"execution_class": "ai-inference",
"pipeline_id": "ravnoves004tree-full-eomt-ddrnet-recorded-review/v1",
"components": [
{
"kind": "source",
"name": "sealed full-route LAB result",
"version": "missioncore.lab-v1-vegetation-shadow/v1",
"role": "immutable Session catalog projection",
"identity_sha256": evidence_identity,
}
],
},
}
parameters = {
"session_id": f"lab-v1-vegetation-shadow-{evidence_identity}",
"source_session_id": source.name,
"display_name": "RAVNOVES004TREE · полный маршрут восприятия",
"lab_id": "LAB V1",
"result_kind": "recorded-perception-qualification",
"result_id": f"lab-v1-vegetation-shadow-{evidence_identity}",
"source_result_id": "lab-v1-vegetation-shadow-" + "c" * 64,
"config_sha256": None,
"run_created_at_utc": "2026-08-29T18:05:11.329061+00:00",
"duration_seconds": 718.0,
"replay_capability": capability,
"provenance": provenance,
"include_recorded_media": False,
}
binding = initial.publish_lab_instance(**parameters)
with sqlite3.connect(initial.database_path) as connection:
connection.execute(
"UPDATE observation_sessions SET modalities_json = ?, source_count = ?, "
"total_bytes = ? WHERE session_id = ?",
('["point-cloud","trajectory","video"]', 3, 999_999_999, binding.session_id),
)
connection.execute(
"ALTER TABLE observation_lab_instances DROP COLUMN replay_capability_json"
)
connection.execute(
"ALTER TABLE observation_lab_instances DROP COLUMN include_recorded_media"
)
connection.commit()
migrated = SessionStore(repository, data_dir=data_dir)
assert migrated.get_lab_instance(binding.session_id).replay_capability == capability
migrated_detail = migrated.get_session(binding.session_id)
assert migrated_detail.summary.modalities == ("point-cloud", "trajectory")
assert migrated_detail.summary.source_count == 2
assert all(source.modality != "video" for source in migrated_detail.sources)
assert migrated.list_recent(
scope="laboratory",
include_capability_projections=False,
).items == ()
assert [
item.session_id
for item in migrated.list_recent(
scope="laboratory",
include_capability_projections=True,
).items
] == [binding.session_id]
assert migrated.publish_lab_instance(**parameters).session_id == binding.session_id
def test_migration_rejects_a_non_replayable_canonical_projection(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
source = make_legacy_session(sessions, "20260828T130511Z_viewer_live")
make_recorded_camera_source(source)
data_dir = tmp_path / "data"
initial = SessionStore(repository, data_dir=data_dir)
initial.reconcile_archive(xgrids_k1_archive_source(sessions))
with sqlite3.connect(initial.database_path) as connection:
connection.execute(
"UPDATE observation_sessions SET archive_id = ? WHERE session_id = ?",
("xgrids-k1.viewer-live.evidence", source.name),
)
connection.commit()
capability = LabReplayCapability(
schema_version="missioncore.observation-lab-replay-capability/v1",
kind="canonical-recorded-rerun",
viewer_profile="recorded-session",
timeline="session_time",
activation="explicit",
commands_enabled=False,
)
evidence_identity = "a" * 64
result_id = f"lab-v1-vegetation-shadow-{evidence_identity}"
initial.publish_lab_instance(
session_id=result_id,
source_session_id=source.name,
display_name="RAVNOVES004TREE · полный маршрут восприятия",
lab_id="LAB V1",
result_kind="recorded-perception-qualification",
result_id=result_id,
source_result_id="lab-v1-vegetation-shadow-" + "c" * 64,
run_created_at_utc="2026-08-29T18:05:11.329061+00:00",
duration_seconds=718.0,
include_recorded_media=False,
replay_capability=capability,
provenance={
"schema_version": "missioncore.canonical-recorded-lab-projection/v1",
"evidence_identity_sha256": evidence_identity,
"result_document_sha256": "b" * 64,
"replay_capability": capability.as_dict(),
"authority": {
"commands_enabled": False,
"navigation_or_safety_accepted": False,
"actuation_accepted": False,
},
"method": {
"schema_version": "missioncore.laboratory-method/v1",
"completeness": "legacy-partial",
"execution_class": "ai-inference",
"pipeline_id": "ravnoves004tree-full-eomt-ddrnet-recorded-review/v1",
"components": [
{
"kind": "source",
"name": "sealed full-route LAB result",
"version": "missioncore.lab-v1-vegetation-shadow/v1",
"role": "immutable Session catalog projection",
"identity_sha256": evidence_identity,
}
],
},
},
)
with sqlite3.connect(initial.database_path) as connection:
connection.execute(
"UPDATE observation_sessions SET replayable = 0, "
"primary_replay_artifact_id = NULL, timeline_origin_epoch_ns = NULL, "
"timeline_origin_monotonic_ns = NULL WHERE session_id = ?",
(result_id,),
)
connection.execute(
"ALTER TABLE observation_lab_instances DROP COLUMN replay_capability_json"
)
connection.execute(
"ALTER TABLE observation_lab_instances DROP COLUMN include_recorded_media"
)
connection.commit()
with pytest.raises(SessionIntegrityError, match="LAB"):
SessionStore(repository, data_dir=data_dir)
def test_migration_rejects_boolean_aliases_in_rolling_authority(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
data_dir = tmp_path / "data"
store = SessionStore(repository, data_dir=data_dir)
with sqlite3.connect(store.database_path) as connection:
capability = {
"schema_version": "missioncore.observation-lab-replay-capability/v1",
"kind": "canonical-recorded-rerun",
"viewer_profile": "recorded-session",
"timeline": "session_time",
"activation": "explicit",
"commands_enabled": False,
}
evidence_identity = "a" * 64
provenance = {
"schema_version": "missioncore.canonical-recorded-lab-projection/v1",
"evidence_identity_sha256": evidence_identity,
"result_document_sha256": "b" * 64,
"replay_capability": capability,
"authority": {
"commands_enabled": 0,
"navigation_or_safety_accepted": 0,
"actuation_accepted": 0,
},
"method": {
"schema_version": "missioncore.laboratory-method/v1",
"completeness": "legacy-partial",
"execution_class": "ai-inference",
"pipeline_id": "ravnoves004tree-full-eomt-ddrnet-recorded-review/v1",
"components": [
{
"kind": "source",
"name": "sealed full-route LAB result",
"version": "missioncore.lab-v1-vegetation-shadow/v1",
"role": "immutable Session catalog projection",
"identity_sha256": evidence_identity,
}
],
},
}
result_id = f"lab-v1-vegetation-shadow-{evidence_identity}"
connection.execute("PRAGMA foreign_keys = OFF")
connection.execute(
"INSERT INTO observation_sessions "
"(session_id, plugin_id, archive_id, display_name, status, modalities_json, "
"replayable, origin, source_count, total_bytes, allowed_root, session_root, "
"created_at_utc, updated_at_utc) "
"VALUES (?, ?, ?, ?, 'ready', '[]', 0, ?, 0, 0, ?, ?, ?, ?)",
(
result_id,
"fixture.plugin",
"missioncore.lab-instances",
"invalid rolling authority",
"missioncore.lab-instance/v1",
str(repository),
str(repository),
"2026-08-30T00:00:00Z",
"2026-08-30T00:00:00Z",
),
)
connection.execute(
"INSERT INTO observation_lab_instances "
"(session_id, source_session_id, lab_id, result_kind, result_id, "
"source_result_id, config_sha256, run_created_at_utc, published_at_utc, "
"include_recorded_media, replay_capability_json, provenance_json) "
"VALUES (?, ?, 'LAB V1', 'recorded-perception-qualification', ?, ?, "
"NULL, ?, ?, NULL, NULL, ?)",
(
result_id,
"20260828T130511Z_viewer_live",
result_id,
"lab-v1-vegetation-shadow-" + "c" * 64,
"2026-08-29T18:05:11.329061+00:00",
"2026-08-30T00:00:00Z",
json.dumps(provenance, sort_keys=True),
),
)
connection.commit()
migrated = SessionStore(repository, data_dir=data_dir)
with sqlite3.connect(migrated.database_path) as connection:
row = connection.execute(
"SELECT replay_capability_json, include_recorded_media "
"FROM observation_lab_instances WHERE session_id = ?",
("lab-v1-vegetation-shadow-" + "a" * 64,),
).fetchone()
assert row == (None, None)
def test_lab_instance_persists_typed_explicit_recorded_replay_capability(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
source = make_legacy_session(sessions, "20260716T205632Z_viewer_live")
store = SessionStore(repository, data_dir=tmp_path / "data")
store.reconcile_archive(xgrids_k1_archive_source(sessions))
capability = LabReplayCapability(
schema_version="missioncore.observation-lab-replay-capability/v1",
kind="canonical-recorded-rerun",
viewer_profile="recorded-session",
timeline="session_time",
activation="explicit",
commands_enabled=False,
)
binding = store.publish_lab_instance(
session_id="lab-recorded-replay",
source_session_id=source.name,
display_name="LAB V1 · recorded replay",
lab_id="LAB V1",
result_kind="recorded-perception-qualification",
result_id="lab-v1-vegetation-shadow-" + "a" * 64,
source_result_id="lab-v1-vegetation-shadow-" + "b" * 64,
run_created_at_utc="2026-08-29T18:05:11.329061+00:00",
replay_capability=capability,
provenance={
"replay_capability": capability.as_dict(),
"method": lab_method(),
},
)
assert binding.replay_capability == capability
assert "replay_capability" not in binding.as_dict()
assert binding.as_dict()["provenance"]["replay_capability"] == capability.as_dict()
assert store.get_lab_instance(binding.session_id) == binding
with sqlite3.connect(store.database_path) as connection:
connection.execute(
"UPDATE observation_lab_instances SET replay_capability_json = ? "
"WHERE session_id = ?",
('{"kind":"unknown"}', binding.session_id),
)
connection.commit()
with pytest.raises(SessionIntegrityError, match="replay capability"):
store.get_lab_instance(binding.session_id)
@pytest.mark.parametrize("value", [0, 1, None, True])
def test_lab_replay_capability_rejects_non_literal_false(value: object) -> None:
with pytest.raises(ValueError, match="replay capability"):
LabReplayCapability(
schema_version="missioncore.observation-lab-replay-capability/v1",
kind="canonical-recorded-rerun",
viewer_profile="recorded-session",
timeline="session_time",
activation="explicit",
commands_enabled=value, # type: ignore[arg-type]
)
def test_lab_instance_rejects_boolean_alias_in_capability_provenance(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
source = make_legacy_session(sessions, "20260716T205632Z_viewer_live")
store = SessionStore(repository, data_dir=tmp_path / "data")
store.reconcile_archive(xgrids_k1_archive_source(sessions))
capability = LabReplayCapability(
schema_version="missioncore.observation-lab-replay-capability/v1",
kind="canonical-recorded-rerun",
viewer_profile="recorded-session",
timeline="session_time",
activation="explicit",
commands_enabled=False,
)
aliased = {**capability.as_dict(), "commands_enabled": 0}
with pytest.raises(ValueError, match="exactly match provenance"):
store.publish_lab_instance(
session_id="lab-recorded-replay-alias",
source_session_id=source.name,
display_name="LAB V1 · recorded replay alias",
lab_id="LAB V1",
result_kind="recorded-perception-qualification",
result_id="lab-v1-vegetation-shadow-" + "a" * 64,
run_created_at_utc="2026-08-29T18:05:11.329061+00:00",
replay_capability=capability,
provenance={
"replay_capability": aliased,
"method": lab_method(),
},
)
def test_lab_instance_rejects_publication_without_a_method_manifest(
tmp_path: Path,
) -> None:
@@ -933,6 +1350,114 @@ def test_bounded_lab_instance_excludes_unbounded_recorded_media(
assert store.prepare_replay(binding.session_id).primary_artifact.path.is_file()
def test_capability_projection_summary_is_exact_and_idempotently_repairable(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
source = make_legacy_session(sessions, "20260716T205632Z_viewer_live")
make_recorded_camera_source(source)
store = SessionStore(repository, data_dir=tmp_path / "data")
store.reconcile_archive(xgrids_k1_archive_source(sessions))
_source_detail, source_snapshot_sha256 = (
store.get_session_with_catalog_snapshot(source.name)
)
capability = LabReplayCapability(
schema_version="missioncore.observation-lab-replay-capability/v1",
kind="canonical-recorded-rerun",
viewer_profile="recorded-session",
timeline="session_time",
activation="explicit",
commands_enabled=False,
)
parameters = {
"session_id": "lab-recorded-bounded",
"source_session_id": source.name,
"display_name": "LAB V1 · bounded recorded review",
"lab_id": "LAB V1",
"result_kind": "recorded-perception-qualification",
"result_id": "lab-v1-vegetation-shadow-" + "1" * 64,
"source_result_id": "lab-v1-vegetation-shadow-" + "2" * 64,
"run_created_at_utc": "2026-08-29T18:05:11.329061+00:00",
"duration_seconds": 59.962,
"include_recorded_media": False,
"expected_source_catalog_sha256": source_snapshot_sha256,
"replay_capability": capability,
"provenance": {
"replay_capability": capability.as_dict(),
"method": lab_method(),
},
}
binding = store.publish_lab_instance(**parameters)
detail = store.get_session(binding.session_id)
assert detail.summary.modalities == ("point-cloud", "trajectory")
assert detail.summary.source_count == len(detail.sources) == 2
referenced_artifacts = {item.artifact_id for item in detail.sources}
assert detail.summary.total_bytes == sum(
artifact.byte_length
for artifact in detail.artifacts
if artifact.artifact_id in referenced_artifacts
)
with sqlite3.connect(store.database_path) as connection:
connection.execute(
"UPDATE observation_sessions SET modalities_json = ?, source_count = ?, "
"total_bytes = ? WHERE session_id = ?",
('["point-cloud","trajectory","video"]', 3, 999_999_999, binding.session_id),
)
connection.commit()
assert store.publish_lab_instance(**parameters) == binding
repaired = store.get_session(binding.session_id)
assert repaired.summary.modalities == ("point-cloud", "trajectory")
assert repaired.summary.source_count == 2
assert repaired.summary.total_bytes == detail.summary.total_bytes
with pytest.raises(SessionIntegrityError, match="recorded-media policy"):
store.publish_lab_instance(**{**parameters, "include_recorded_media": True})
with sqlite3.connect(store.database_path) as connection:
connection.execute(
"UPDATE observation_session_artifacts SET sha256 = ? "
"WHERE session_id = ? AND artifact_id = 'raw-transport-primary'",
("0" * 64, binding.session_id),
)
connection.commit()
with pytest.raises(SessionIntegrityError, match="source snapshot"):
store.publish_lab_instance(**parameters)
def test_lab_publication_rejects_a_source_changed_after_snapshot(
tmp_path: Path,
) -> None:
repository = tmp_path / "repo"
sessions = repository / "sessions"
source = make_legacy_session(sessions, "20260716T205632Z_viewer_live")
store = SessionStore(repository, data_dir=tmp_path / "data")
store.reconcile_archive(xgrids_k1_archive_source(sessions))
_detail, snapshot_sha256 = store.get_session_with_catalog_snapshot(source.name)
with sqlite3.connect(store.database_path) as connection:
connection.execute(
"UPDATE observation_session_artifacts SET byte_length = byte_length + 1 "
"WHERE session_id = ? AND artifact_id = 'raw-transport-primary'",
(source.name,),
)
connection.commit()
with pytest.raises(SessionIntegrityError, match="changed after admission"):
store.publish_lab_instance(
session_id="lab-source-snapshot-race",
source_session_id=source.name,
display_name="LAB E21 · source snapshot race",
lab_id="LAB E21",
result_kind="source-snapshot-race",
result_id="source-snapshot-race-result",
run_created_at_utc="2026-08-29T18:05:11.329061+00:00",
provenance={"method": lab_method()},
expected_source_catalog_sha256=snapshot_sha256,
)
assert store.get_lab_instance("lab-source-snapshot-race") is None
def test_delete_session_rejects_a_catalog_target_outside_its_allowed_root(
tmp_path: Path,
) -> None: