feat(observatory): admit canonical recorded replay
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user