feat(perception): publish immutable lab session instances

This commit is contained in:
DCCONSTRUCTIONS
2026-07-23 20:13:40 +03:00
parent f1f8e21b78
commit 10019a454a
16 changed files with 1970 additions and 30 deletions
+33
View File
@@ -265,6 +265,39 @@ def test_session_router_lists_details_and_dispatches_opaque_replay(tmp_path: Pat
assert_no_local_paths(value, repository)
def test_session_router_exposes_immutable_lab_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))
binding = store.publish_lab_instance(
session_id="lab-e21-d0201712",
source_session_id=source.name,
display_name="LAB E21 · Real-time 1× · d0201712",
lab_id="LAB E21",
result_kind="e21-realtime-envelope",
result_id="e10-integrated-perception-" + "a" * 64,
source_result_id="e21-realtime-envelope-" + "b" * 64,
config_sha256="c" * 64,
run_created_at_utc="2026-07-23T15:55:15.548Z",
provenance={"source_payloads_mutated": False},
)
router = build_session_router(store)
list_route = endpoint(router, "/api/v1/observation-sessions", "GET")
detail_route = endpoint(router, "/api/v1/observation-sessions/{session_id}", "GET")
listing = list_route(limit=20, cursor=None)
item = next(value for value in listing["items"] if value["id"] == binding.session_id)
detail = detail_route(session_id=binding.session_id)
assert item["lab"] == binding.as_dict()
assert detail["lab"] == binding.as_dict()
assert item["lab"]["source_session_id"] == source.name
assert item["lab"]["provenance"]["source_payloads_mutated"] is False
assert_no_local_paths((item, detail), repository)
def test_delete_session_removes_evidence_and_cache_but_refuses_an_open_recording(
tmp_path: Path,
) -> None:
+89
View File
@@ -0,0 +1,89 @@
from __future__ import annotations
import hashlib
import json
from pathlib import Path
from k1link.sessions.lab_cache import publish_lab_replay_cache
from k1link.sessions.recording import (
CACHE_SCHEMA,
RECORDING_CACHE_FILENAME,
RECORDING_CACHE_SIDECAR_FILENAME,
)
def canonical_json(value: object) -> bytes:
return json.dumps(
value,
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
allow_nan=False,
).encode()
def test_publish_lab_replay_cache_hardlinks_rrd_and_rebinds_sidecars(
tmp_path: Path,
) -> None:
data = tmp_path / "mission-core"
recordings = data / "recordings"
source = recordings / "source-session"
source.mkdir(parents=True)
source_rrd = source / RECORDING_CACHE_FILENAME
source_rrd.write_bytes(b"RRF2immutable")
source_sidecar = {
"schema_version": CACHE_SCHEMA,
"session_id": source.name,
"recording_byte_length": source_rrd.stat().st_size,
"recording_mtime_ns": source_rrd.stat().st_mtime_ns,
"recording_sha256": hashlib.sha256(source_rrd.read_bytes()).hexdigest(),
}
(source / RECORDING_CACHE_SIDECAR_FILENAME).write_text(
json.dumps(source_sidecar),
encoding="utf-8",
)
media_root = data / "recorded-media-preparations"
media_root.mkdir()
media_body = {
"schema_version": "missioncore.recorded-media-preparation/v1",
"session_id": source.name,
"artifact_id": "recorded-video-1",
"generation": "accepted",
}
(media_root / "source.json").write_text(
json.dumps(
{
**media_body,
"checksum_sha256": hashlib.sha256(canonical_json(media_body)).hexdigest(),
}
),
encoding="utf-8",
)
publish_lab_replay_cache(
data,
source_session_id=source.name,
lab_session_id="lab-e21-result",
)
lab = recordings / "lab-e21-result"
lab_rrd = lab / RECORDING_CACHE_FILENAME
assert lab_rrd.read_bytes() == source_rrd.read_bytes()
assert lab_rrd.stat().st_ino == source_rrd.stat().st_ino
assert lab_rrd.stat().st_nlink == 2
cloned_cache = json.loads(
(lab / RECORDING_CACHE_SIDECAR_FILENAME).read_text(encoding="utf-8")
)
assert cloned_cache["session_id"] == "lab-e21-result"
cloned_media = [
json.loads(path.read_text(encoding="utf-8"))
for path in media_root.iterdir()
if path.name != "source.json"
]
assert len(cloned_media) == 1
assert cloned_media[0]["session_id"] == "lab-e21-result"
cloned_checksum = cloned_media[0].pop("checksum_sha256")
assert cloned_checksum == hashlib.sha256(canonical_json(cloned_media[0])).hexdigest()
lab_rrd.unlink()
assert source_rrd.read_bytes() == b"RRF2immutable"
+72
View File
@@ -777,6 +777,78 @@ def test_delete_session_removes_only_the_exact_evidence_tree_and_catalog_row(
assert store.get_session(retained.name).summary.session_id == retained.name
def test_lab_instance_is_independent_and_never_deletes_source_evidence(
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")
archive = xgrids_k1_archive_source(sessions)
store.reconcile_archive(archive)
source_command = store.prepare_replay(source.name)
binding = store.publish_lab_instance(
session_id="lab-e21-d0201712",
source_session_id=source.name,
display_name="LAB E21 · RT 1× · d0201712",
lab_id="LAB E21",
result_kind="e10-integrated-perception",
result_id="e10-integrated-perception-" + "a" * 64,
source_result_id="e21-realtime-envelope-" + "b" * 64,
config_sha256="c" * 64,
run_created_at_utc="2026-07-23T15:51:25.000Z",
provenance={"storage_mode": "hard-linked-immutable-payloads"},
)
detail = store.get_session(binding.session_id)
lab_command = store.prepare_replay(binding.session_id)
assert detail.summary.lab == binding
assert detail.summary.display_name == "LAB E21 · RT 1× · d0201712"
assert lab_command.primary_artifact.path == source_command.primary_artifact.path
assert lab_command.session_id == binding.session_id
assert source.is_dir()
with pytest.raises(SessionIntegrityError, match="has LAB instances"):
store.delete_session(source.name)
assert source.is_dir()
store.delete_session(binding.session_id)
assert source.is_dir()
assert store.get_session(source.name).summary.lab is None
with pytest.raises(SessionNotFoundError):
store.get_session(binding.session_id)
def test_lab_instance_publication_is_idempotent_but_provenance_is_immutable(
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))
parameters = {
"session_id": "lab-e19-36964643",
"source_session_id": source.name,
"display_name": "LAB E19 · Ground-aware 3D",
"lab_id": "LAB E19",
"result_kind": "e10-integrated-perception",
"result_id": "e10-integrated-perception-" + "d" * 64,
"source_result_id": "e10-integrated-perception-" + "e" * 64,
"config_sha256": "f" * 64,
"run_created_at_utc": "2026-07-23T05:19:43.138Z",
"provenance": {"source": "accepted"},
}
first = store.publish_lab_instance(**parameters)
second = store.publish_lab_instance(**parameters)
assert second == first
with pytest.raises(SessionIntegrityError, match="different provenance"):
store.publish_lab_instance(**{**parameters, "config_sha256": "0" * 64})
def test_delete_session_rejects_a_catalog_target_outside_its_allowed_root(
tmp_path: Path,
) -> None: