feat(observatory): add portable LAB V1 foundation

This commit is contained in:
DCCONSTRUCTIONS
2026-08-31 11:02:34 +03:00
parent d67e86176e
commit c9302c78c2
27 changed files with 7629 additions and 266 deletions
@@ -0,0 +1,574 @@
from __future__ import annotations
import json
from dataclasses import replace
from pathlib import Path
import pytest
from k1link.observatory.portable_queue_binding import (
PortableQueueBindingIntegrityError,
PortableQueueBindingStaleCheckError,
PortableRecordedQueueBindingService,
PortableRecordedRunPreparation,
)
from k1link.observatory.portable_run_definitions import (
PortableExecutorAvailability,
PortableRunDefinitionRegistry,
PortableRunDefinitionUnavailableError,
canonical_sha256,
)
from k1link.observatory.recorded_jobs import ObservatoryRecordedJobQueue
from k1link.observatory.source_admission import (
PORTABLE_SOURCE_DOCUMENT_DIRECTORY,
PortableRecordedSourceAdmission,
PortableSourceNotPreparedError,
RecordedK1SourceAdmissionService,
)
from k1link.sessions.media import (
CAMERA_ARCHIVE_SCHEMA,
RecordedMediaEpoch,
RecordedMediaManifest,
RecordedMediaSegment,
)
from k1link.sessions.models import (
RecordedMediaArtifact,
ReplayArtifact,
ReplayCommand,
SessionArtifact,
SessionDetail,
SessionSource,
SessionSummary,
)
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
REGISTRY_PATH = REPOSITORY_ROOT / "config" / "observatory-portable-run-definitions.json"
SESSION_ID = "20260831T000000Z_viewer_live"
CATALOG_SHA256 = "1" * 64
RAW_SHA256 = "2" * 64
GENERATION_SHA256 = "3" * 64
SEGMENT_SHA256 = "4" * 64
INIT_SHA256 = "e2279963e16d84c91d68e7dbb1f7efed840533387dfeb844b7398bff45fbde38"
def _blocked_registry() -> PortableRunDefinitionRegistry:
return PortableRunDefinitionRegistry.from_file(REGISTRY_PATH)
def _ready_registry() -> PortableRunDefinitionRegistry:
blocked = _blocked_registry().definitions[0]
executor = PortableExecutorAvailability(
contour_id="worker-006",
state="ready",
release_id="lab-v1-eomt-ddrnet-executor-v1",
release_sha256="5" * 64,
image_sha256="6" * 64,
reason_code=None,
reason=None,
)
identity = blocked.identity_document()
identity["executor"] = executor.identity_document()
ready = replace(
blocked,
executor=executor,
definition_sha256=canonical_sha256(identity),
)
return PortableRunDefinitionRegistry((ready,))
def _detail(*, display_name: str = "arbitrary-operator-label") -> SessionDetail:
return SessionDetail(
summary=SessionSummary(
session_id=SESSION_ID,
display_name=display_name,
status="ready",
started_at_utc="2026-08-31T00:00:00Z",
completed_at_utc="2026-08-31T00:10:00Z",
duration_seconds=600.0,
modalities=("point-cloud", "trajectory", "video"),
source_count=3,
total_bytes=120,
replayable=True,
origin="xgrids-k1.viewer-live.evidence",
),
sources=(
SessionSource(
source_id="sensor.camera.right",
semantic_channel_id="camera.video.recorded",
modality="video",
status="recorded",
seekable=True,
artifact_id="recorded-video-right",
),
SessionSource(
source_id="sensor.lidar.primary",
semantic_channel_id="spatial.point-cloud.recorded",
modality="point-cloud",
status="recorded",
seekable=True,
artifact_id="raw-transport-primary",
),
SessionSource(
source_id="spatial.trajectory",
semantic_channel_id="spatial.pose.recorded",
modality="trajectory",
status="recorded",
seekable=True,
artifact_id="raw-transport-primary",
),
),
artifacts=(
SessionArtifact(
artifact_id="raw-transport-primary",
kind="raw-transport",
media_type="application/x-nodedc-k1mqtt",
byte_length=100,
sha256=RAW_SHA256,
integrity_status="verified",
),
SessionArtifact(
artifact_id="recorded-video-right",
kind="recorded-video",
media_type="video/mp4",
byte_length=20,
sha256=None,
integrity_status="validated-structure",
),
),
plugin_id="nodedc.device.xgrids-lixelkity-k1",
archive_id="xgrids-k1.viewer-live.evidence",
)
def _replay(root: Path) -> ReplayCommand:
return ReplayCommand(
session_id=SESSION_ID,
plugin_id="nodedc.device.xgrids-lixelkity-k1",
allowed_root=root,
session_root=root / SESSION_ID,
primary_artifact_id="raw-transport-primary",
artifacts=(
ReplayArtifact(
artifact_id="raw-transport-primary",
path=root / "mqtt.raw.k1mqtt",
media_type="application/x-nodedc-k1mqtt",
file_byte_length=100,
replay_byte_length=100,
expected_sha256=RAW_SHA256,
),
),
timeline_origin_epoch_ns=1,
timeline_origin_monotonic_ns=2,
speed=1.0,
loop=False,
)
def _media_artifact(root: Path) -> RecordedMediaArtifact:
return RecordedMediaArtifact(
session_id=SESSION_ID,
public_source_id="recorded.camera.right",
artifact_id="recorded-video-right",
source_path=root / "media" / "sensor.camera.right",
byte_length=20,
)
def _manifest(root: Path) -> RecordedMediaManifest:
epoch = RecordedMediaEpoch(
ordinal=1,
path=root / "epoch-1",
init_path=root / "epoch-1" / "init.mp4",
init_byte_length=10,
init_sha256=INIT_SHA256,
media_type='video/mp4; codecs="avc1.641028"',
timeline_start_seconds=10.0,
timeline_end_seconds=10.1,
segments=(
RecordedMediaSegment(
sequence=1,
path=root / "epoch-1" / "segments" / "1.m4s",
byte_length=10,
sha256=SEGMENT_SHA256,
random_access=True,
end_time_seconds=10.1,
),
),
)
return RecordedMediaManifest(
session_id=SESSION_ID,
public_source_id="recorded.camera.right",
artifact_id="recorded-video-right",
synchronization="host-arrival-best-effort",
generation_sha256=GENERATION_SHA256,
timeline_start_seconds=10.0,
timeline_end_seconds=10.1,
byte_length=20,
epochs=(epoch,),
)
class _Store:
def __init__(
self,
root: Path,
*,
catalogs: tuple[str, ...] = (CATALOG_SHA256,),
) -> None:
self.data_dir = root.resolve()
self.detail = _detail()
self.replay = _replay(root)
self.media = (_media_artifact(root),)
self.catalogs = catalogs
self.catalog_reads = 0
self.prepare_replay_calls = 0
self.recorded_media_reads = 0
def get_session_with_catalog_snapshot(
self,
session_id: str,
) -> tuple[SessionDetail, str]:
assert session_id == SESSION_ID
index = min(self.catalog_reads, len(self.catalogs) - 1)
self.catalog_reads += 1
return self.detail, self.catalogs[index]
def prepare_replay(self, session_id: str) -> ReplayCommand:
assert session_id == SESSION_ID
self.prepare_replay_calls += 1
return self.replay
def list_recorded_media(
self,
session_id: str,
) -> tuple[RecordedMediaArtifact, ...]:
assert session_id == SESSION_ID
self.recorded_media_reads += 1
return self.media
class _Inspector:
def __init__(self, manifest: RecordedMediaManifest | None) -> None:
self.manifest = manifest
self.inspect_calls = 0
self.restore_calls = 0
def inspect(
self,
artifact: RecordedMediaArtifact,
replay: ReplayCommand,
) -> RecordedMediaManifest:
assert artifact.session_id == replay.session_id
self.inspect_calls += 1
assert self.manifest is not None
return self.manifest
def restore_prepared(
self,
artifact: RecordedMediaArtifact,
replay: ReplayCommand,
) -> RecordedMediaManifest | None:
assert artifact.session_id == replay.session_id
self.restore_calls += 1
return self.manifest
def _write_probe_summary(root: Path, *, segment_count: int = 11) -> None:
epoch = root / "media" / "sensor.camera.right" / "epoch-1"
epoch.mkdir(parents=True)
(epoch / "summary.json").write_text(
json.dumps(
{
"schema_version": CAMERA_ARCHIVE_SCHEMA,
"source_id": "sensor.camera.right",
"codec_epoch": 1,
"status": "complete",
"segment_count": segment_count,
"entry_count": segment_count,
"media_segment_count": segment_count,
"init_sha256": INIT_SHA256,
"synchronization": "host-arrival-best-effort",
"commit_policy": "per-segment-fsync",
"failure_code": None,
"artifacts": {
"init": "init.mp4",
"segments": "segments",
"index": "index.jsonl",
},
}
),
encoding="utf-8",
)
def _service(
tmp_path: Path,
*,
registry: PortableRunDefinitionRegistry,
store: _Store | None = None,
inspector: _Inspector | None = None,
with_queue: bool = True,
) -> tuple[
PortableRecordedQueueBindingService,
_Store,
ObservatoryRecordedJobQueue | None,
_Inspector,
]:
active_store = store or _Store(tmp_path)
queue = None
if with_queue:
queue = ObservatoryRecordedJobQueue(
tmp_path,
definitions=registry.to_recorded_registry(),
clock=lambda: "2026-08-31T00:00:00.000Z",
)
active_inspector = inspector or _Inspector(_manifest(tmp_path))
service = PortableRecordedQueueBindingService(
data_dir=tmp_path,
session_store=active_store, # type: ignore[arg-type]
media_inspector=active_inspector, # type: ignore[arg-type]
definitions=registry,
queue=queue,
)
return service, active_store, queue, active_inspector
def _check(
service: PortableRecordedQueueBindingService,
registry: PortableRunDefinitionRegistry,
) -> PortableRecordedRunPreparation:
definition = registry.definitions[0]
return service.check(
source_session_id=SESSION_ID,
setup_id=definition.setup_id,
definition_sha256=definition.definition_sha256,
)
def test_not_installed_definition_fails_before_source_or_queue_writes(
tmp_path: Path,
) -> None:
registry = _blocked_registry()
service, store, queue, _inspector = _service(
tmp_path,
registry=registry,
with_queue=False,
)
with pytest.raises(
PortableRunDefinitionUnavailableError,
match="not sealed or installed",
):
_check(service, registry)
assert store.catalog_reads == 0
assert queue is None
assert not (tmp_path / PORTABLE_SOURCE_DOCUMENT_DIRECTORY).exists()
assert not (tmp_path / "observatory-recorded-jobs.sqlite3").exists()
def test_probe_is_bounded_and_does_not_enter_replay_or_media_inspector(
tmp_path: Path,
) -> None:
registry = _ready_registry()
_write_probe_summary(tmp_path, segment_count=31)
service, store, queue, inspector = _service(tmp_path, registry=registry)
definition = registry.definitions[0]
capability = service.probe(
source_session_id=SESSION_ID,
setup_id=definition.setup_id,
definition_sha256=definition.definition_sha256,
)
assert capability.source_session_id == SESSION_ID
assert capability.source_catalog_sha256 == CATALOG_SHA256
assert capability.source_adapter_sha256 == definition.source_adapter.contract_sha256
assert capability.camera_segment_count == 31
assert store.catalog_reads == 1
assert store.recorded_media_reads == 1
assert store.prepare_replay_calls == 0
assert inspector.inspect_calls == 0
assert inspector.restore_calls == 0
assert not (tmp_path / "media" / "sensor.camera.right" / "epoch-1" / "segments").exists()
assert not (tmp_path / PORTABLE_SOURCE_DOCUMENT_DIRECTORY).exists()
assert queue is not None
assert queue.list_jobs() == ()
def test_check_fails_typed_when_media_was_never_prepared(
tmp_path: Path,
) -> None:
registry = _ready_registry()
empty_inspector = _Inspector(None)
service, _, queue, inspector = _service(
tmp_path,
registry=registry,
inspector=empty_inspector,
)
with pytest.raises(PortableSourceNotPreparedError, match="not been prepared"):
_check(service, registry)
assert inspector.inspect_calls == 0
assert inspector.restore_calls == 1
assert not (tmp_path / PORTABLE_SOURCE_DOCUMENT_DIRECTORY).exists()
assert queue is not None
assert queue.list_jobs() == ()
def test_check_is_path_free_read_only_and_builds_exact_queue_intent(
tmp_path: Path,
) -> None:
registry = _ready_registry()
service, _, queue, inspector = _service(tmp_path, registry=registry)
checked = _check(service, registry)
intent = checked.intent(idempotency_key="portable-run-001")
assert intent.source_session_id == SESSION_ID
assert intent.source_catalog_sha256 == checked.source.source_catalog_sha256
assert intent.source_bundle_sha256 == checked.source.source_bundle_sha256
assert intent.source_capability_manifest_sha256 == (
checked.source.source_capability_manifest_sha256
)
assert intent.setup_id == registry.definitions[0].setup_id
assert intent.definition_sha256 == registry.definitions[0].definition_sha256
assert checked.source.source_adapter_sha256 == (
registry.definitions[0].source_adapter.contract_sha256
)
assert "path" not in str(checked.as_dict()).lower()
assert not (tmp_path / PORTABLE_SOURCE_DOCUMENT_DIRECTORY).exists()
assert queue is not None
assert queue.list_jobs() == ()
assert inspector.inspect_calls == 0
assert inspector.restore_calls == 1
def test_admit_persists_exact_documents_and_submit_queues_same_identity(
tmp_path: Path,
) -> None:
registry = _ready_registry()
service, _, queue, _inspector = _service(tmp_path, registry=registry)
checked = _check(service, registry)
definition = registry.definitions[0]
admitted = service.admit(
source_session_id=SESSION_ID,
setup_id=definition.setup_id,
definition_sha256=definition.definition_sha256,
expected_check_sha256=checked.check_sha256,
)
job, created = service.submit(
source_session_id=SESSION_ID,
setup_id=definition.setup_id,
definition_sha256=definition.definition_sha256,
expected_check_sha256=checked.check_sha256,
idempotency_key="portable-run-001",
)
root = tmp_path / PORTABLE_SOURCE_DOCUMENT_DIRECTORY
assert sorted(path.name for path in root.iterdir()) == sorted(
(
f"{admitted.source.source_bundle_sha256}.json",
f"{admitted.source.source_capability_manifest_sha256}.json",
)
)
assert created is True
assert job.state == "queued"
assert job.source_catalog_sha256 == admitted.source.source_catalog_sha256
assert job.source_bundle_sha256 == admitted.source.source_bundle_sha256
assert job.source_capability_manifest_sha256 == (
admitted.source.source_capability_manifest_sha256
)
assert queue is not None
assert queue.list_jobs() == (job,)
def test_admit_rejects_catalog_change_since_check_without_writes_or_job(
tmp_path: Path,
) -> None:
registry = _ready_registry()
store = _Store(tmp_path, catalogs=(CATALOG_SHA256, "7" * 64))
service, _, queue, _inspector = _service(
tmp_path,
registry=registry,
store=store,
)
checked = _check(service, registry)
definition = registry.definitions[0]
with pytest.raises(PortableQueueBindingStaleCheckError, match="changed"):
service.submit(
source_session_id=SESSION_ID,
setup_id=definition.setup_id,
definition_sha256=definition.definition_sha256,
expected_check_sha256=checked.check_sha256,
idempotency_key="portable-run-stale-001",
)
assert not (tmp_path / PORTABLE_SOURCE_DOCUMENT_DIRECTORY).exists()
assert queue is not None
assert queue.list_jobs() == ()
def test_admit_rejects_change_during_commit_before_source_documents(
tmp_path: Path,
) -> None:
registry = _ready_registry()
store = _Store(
tmp_path,
catalogs=(
CATALOG_SHA256,
CATALOG_SHA256,
CATALOG_SHA256,
"8" * 64,
),
)
service, _, queue, _inspector = _service(
tmp_path,
registry=registry,
store=store,
)
checked = _check(service, registry)
definition = registry.definitions[0]
with pytest.raises(PortableQueueBindingStaleCheckError, match="changed"):
service.submit(
source_session_id=SESSION_ID,
setup_id=definition.setup_id,
definition_sha256=definition.definition_sha256,
expected_check_sha256=checked.check_sha256,
idempotency_key="portable-run-racing-001",
)
assert not (tmp_path / PORTABLE_SOURCE_DOCUMENT_DIRECTORY).exists()
assert queue is not None
assert queue.list_jobs() == ()
def test_registry_and_source_admission_adapter_digests_must_match(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
registry = _ready_registry()
service, _, queue, _inspector = _service(tmp_path, registry=registry)
original_check = RecordedK1SourceAdmissionService.check
def corrupted_check(
source_service: RecordedK1SourceAdmissionService,
source_session_id: str,
) -> PortableRecordedSourceAdmission:
return replace(
original_check(source_service, source_session_id),
source_adapter_sha256="9" * 64,
)
monkeypatch.setattr(RecordedK1SourceAdmissionService, "check", corrupted_check)
with pytest.raises(PortableQueueBindingIntegrityError, match="adapter"):
_check(service, registry)
assert not (tmp_path / PORTABLE_SOURCE_DOCUMENT_DIRECTORY).exists()
assert queue is not None
assert queue.list_jobs() == ()
@@ -0,0 +1,322 @@
from __future__ import annotations
import copy
import json
from dataclasses import FrozenInstanceError, replace
from pathlib import Path
import pytest
from k1link.observatory.portable_run_definitions import (
PORTABLE_MODEL_MANIFEST_SCHEMA,
PortableExecutorAvailability,
PortableRunDefinitionRegistry,
PortableRunDefinitionRegistryError,
PortableRunDefinitionUnavailableError,
canonical_sha256,
)
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
REGISTRY_PATH = REPOSITORY_ROOT / "config" / "observatory-portable-run-definitions.json"
DEFINITION_SHA256 = "57bf8f0859e10e54e30322c9a8aa28b427699f6fe6b5267e279ec3390fa78466"
MODEL_MANIFEST_SHA256 = "3fd2d43af73bd73f89d9ffae95d8770cfdeb46033ec967509124fac6ae4afe56"
def _registry() -> PortableRunDefinitionRegistry:
return PortableRunDefinitionRegistry.from_file(REGISTRY_PATH)
def _document() -> dict[str, object]:
return json.loads(REGISTRY_PATH.read_text(encoding="utf-8"))
def _write(tmp_path: Path, document: object) -> Path:
path = tmp_path / "portable-definitions.json"
path.write_text(json.dumps(document), encoding="utf-8")
return path
def _first(document: dict[str, object]) -> dict[str, object]:
definitions = document["definitions"]
assert isinstance(definitions, list)
first = definitions[0]
assert isinstance(first, dict)
return first
def test_production_definition_is_source_independent_and_requirements_are_immutable() -> None:
definition = _registry().definitions[0]
requirements = definition.source_requirements
assert definition.setup_id == "lab-v1-eomt-ddrnet-portable-v1"
assert requirements.plugin_id == "nodedc.device.xgrids-lixelkity-k1"
assert requirements.archive_id == "xgrids-k1.viewer-live.evidence"
assert requirements.required_modalities == ("point-cloud", "trajectory", "video")
assert requirements.camera_source_id == "sensor.camera.right"
assert requirements.camera_semantic_channel_id == "camera.video.recorded"
assert requirements.recorded_media_type == 'video/mp4; codecs="avc1.641028"'
assert requirements.recorded_media_init_sha256 == (
"e2279963e16d84c91d68e7dbb1f7efed840533387dfeb844b7398bff45fbde38"
)
assert requirements.camera_width == 800
assert requirements.camera_height == 600
assert requirements.calibration_slot == "camera_1"
assert requirements.calibration_identity_sha256 == (
"05f3ad9b38b3a4fc95388a8ec83da83c745e217709e51787b3d5aad0969f6fa9"
)
assert requirements.exactly_one_media_epoch is True
assert requirements.seekable is True
assert not hasattr(requirements, "session_id")
assert not hasattr(requirements, "label")
identity = json.dumps(definition.identity_document(), sort_keys=True)
assert "RAVNOVES" not in identity
assert "20260828T130511Z_viewer_live" not in identity
assert "historical_results" not in identity
assert not hasattr(definition, "historical_results")
assert "session_id" not in identity
with pytest.raises(FrozenInstanceError):
requirements.plugin_id = "changed" # type: ignore[misc]
def test_source_requirements_map_exactly_to_admission_contract() -> None:
definition = _registry().definitions[0]
admission = definition.to_source_admission_requirements()
assert admission.plugin_id == definition.source_requirements.plugin_id
assert admission.archive_id == definition.source_requirements.archive_id
assert admission.expected_width == definition.source_requirements.camera_width
assert admission.expected_height == definition.source_requirements.camera_height
assert admission.calibration_slot == definition.source_requirements.calibration_slot
assert admission.require_single_camera_epoch is True
assert admission.adapter_document() == definition.source_adapter.identity_document(
definition.source_requirements
)
assert admission.adapter_sha256 == definition.source_adapter.contract_sha256
def test_all_canonical_identities_are_recomputed_from_typed_content() -> None:
definition = _registry().definitions[0]
assert definition.definition_sha256 == DEFINITION_SHA256
assert canonical_sha256(definition.identity_document()) == DEFINITION_SHA256
assert definition.source_adapter.contract_sha256 == canonical_sha256(
definition.source_adapter.identity_document(definition.source_requirements)
)
assert definition.resource_profile.profile_sha256 == canonical_sha256(
definition.resource_profile.identity_document()
)
assert definition.result_contract.contract_sha256 == canonical_sha256(
definition.result_contract.identity_document()
)
assert definition.model_manifest_sha256 == MODEL_MANIFEST_SHA256
assert definition.model_manifest_sha256 == canonical_sha256(
{
"schema_version": PORTABLE_MODEL_MANIFEST_SCHEMA,
"models": [model.as_dict() for model in definition.models],
}
)
def test_registry_rejects_legacy_result_metadata(
tmp_path: Path,
) -> None:
document = _document()
first = _first(document)
first["historical_results"] = []
with pytest.raises(PortableRunDefinitionRegistryError, match="fields are invalid"):
PortableRunDefinitionRegistry.from_file(_write(tmp_path, document))
def test_component_or_model_mutation_without_a_new_digest_is_rejected(
tmp_path: Path,
) -> None:
document = _document()
first = _first(document)
models = first["models"]
assert isinstance(models, list)
model = models[0]
assert isinstance(model, dict)
artifacts = model["artifacts"]
assert isinstance(artifacts, list)
artifact = artifacts[1]
assert isinstance(artifact, dict)
artifact["sha256"] = "0" * 64
with pytest.raises(
PortableRunDefinitionRegistryError,
match="portable definition digest changed",
):
PortableRunDefinitionRegistry.from_file(_write(tmp_path, document))
@pytest.mark.parametrize(
"forbidden_key",
[
"source_session_id",
"source_label",
"runner_path",
"command",
"environment",
"user_priority",
],
)
def test_registry_rejects_source_binding_and_executable_or_priority_fields(
tmp_path: Path,
forbidden_key: str,
) -> None:
document = _document()
first = _first(document)
requirements = first["source_requirements"]
assert isinstance(requirements, dict)
requirements[forbidden_key] = "caller-owned"
with pytest.raises(PortableRunDefinitionRegistryError, match="forbids"):
PortableRunDefinitionRegistry.from_file(_write(tmp_path, document))
def test_registry_rejects_authority_escalation_and_calibration_disagreement(
tmp_path: Path,
) -> None:
authority_escalation = _document()
first = _first(authority_escalation)
authority = first["authority"]
assert isinstance(authority, dict)
authority["commands_enabled"] = True
with pytest.raises(PortableRunDefinitionRegistryError, match="observation-only"):
PortableRunDefinitionRegistry.from_file(_write(tmp_path, authority_escalation))
calibration_drift = _document()
first = _first(calibration_drift)
requirements = first["source_requirements"]
assert isinstance(requirements, dict)
requirements["calibration_identity_sha256"] = "a" * 64
adapter = first["source_adapter"]
assert isinstance(adapter, dict)
adapter_document = (
_registry()
.definitions[0]
.source_adapter.identity_document(_registry().definitions[0].source_requirements)
)
calibration = adapter_document["calibration"]
assert isinstance(calibration, dict)
calibration["sha256"] = "a" * 64
adapter["contract_sha256"] = canonical_sha256(adapter_document)
with pytest.raises(PortableRunDefinitionRegistryError, match="calibration"):
PortableRunDefinitionRegistry.from_file(_write(tmp_path, calibration_drift))
def test_duplicate_definition_and_incomplete_ready_executor_are_rejected(
tmp_path: Path,
) -> None:
duplicate = _document()
definitions = duplicate["definitions"]
assert isinstance(definitions, list)
definitions.append(copy.deepcopy(definitions[0]))
with pytest.raises(PortableRunDefinitionRegistryError, match="setup IDs"):
PortableRunDefinitionRegistry.from_file(_write(tmp_path, duplicate))
incomplete = _document()
first = _first(incomplete)
executor = first["executor"]
assert isinstance(executor, dict)
executor["state"] = "ready"
executor["reason_code"] = None
executor["reason"] = None
with pytest.raises(PortableRunDefinitionRegistryError, match="release identity"):
PortableRunDefinitionRegistry.from_file(_write(tmp_path, incomplete))
def test_production_definition_is_blocked_until_release_and_image_are_sealed() -> None:
registry = _registry()
definition = registry.definitions[0]
assert definition.executor.state == "not-installed"
assert definition.executor.release_id is None
assert definition.executor.release_sha256 is None
assert definition.executor.image_sha256 is None
with pytest.raises(
PortableRunDefinitionUnavailableError,
match="not sealed or installed",
):
definition.to_recorded_run_definition()
with pytest.raises(PortableRunDefinitionUnavailableError):
registry.to_recorded_registry()
def test_conversion_to_recorded_definition_requires_and_preserves_sealed_identities() -> None:
blocked = _registry().definitions[0]
ready_executor = PortableExecutorAvailability(
contour_id="worker-006",
state="ready",
release_id="lab-v1-eomt-ddrnet-executor-v1",
release_sha256="1" * 64,
image_sha256="2" * 64,
reason_code=None,
reason=None,
)
identity = blocked.identity_document()
identity["executor"] = ready_executor.identity_document()
ready = replace(
blocked,
executor=ready_executor,
definition_sha256=canonical_sha256(identity),
)
recorded = ready.to_recorded_run_definition()
assert recorded.setup_id == ready.setup_id
assert recorded.definition_sha256 == ready.definition_sha256
assert recorded.source_adapter_sha256 == ready.source_adapter.contract_sha256
assert recorded.executor_release_sha256 == "1" * 64
assert recorded.executor_image_sha256 == "2" * 64
assert recorded.model_release_ids == ready.learned_models
assert recorded.model_manifest_sha256 == MODEL_MANIFEST_SHA256
assert recorded.resource_profile_sha256 == ready.resource_profile.profile_sha256
assert recorded.checkpoint_policy == "non-checkpointable"
def test_production_lab_v1_model_component_and_result_identities_are_exact() -> None:
definition = _registry().definitions[0]
models = {model.release_id: model for model in definition.models}
eomt = models["eomt-cityscapes-large-1024-v1"]
ddrnet = models["lab-v1-ddrnet-39-goose-fine-64-v1"]
assert eomt.model_id == "tue-mps/cityscapes_semantic_eomt_large_1024"
assert eomt.revision == "8d6b6d1a3f7b50d441afd7d247c2ed10db186e8f"
assert {artifact.role: artifact.sha256 for artifact in eomt.artifacts} == {
"config-json": ("7f4aa94fa4e43c0dbd79a5420edb511120aef62bd82bfbcbcece79948286a650"),
"model-weights": "c265da9a74f58f5c3f4826d23ca4ca78beac0b106cca5842beca61580de5b782",
"preprocessor-config": ("97e2fbf7f0bdba2cfc90251c5133bae9c27ddc9c4410509f40670be2332854e7"),
}
assert ddrnet.model_id == "goose-ddrnet-class-512"
assert ddrnet.revision is None
assert ddrnet.architecture == "ddrnet_39"
assert ddrnet.artifacts[0].sha256 == (
"b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6"
)
assert ddrnet.artifacts[0].byte_length == 259_419_077
components = {component.component_id: component for component in definition.components}
assert components["eomt-recorded-profile-v1"].sha256 == (
"ea583966bc3409f5cf563cbf4fad05e366907e67187082eb692aff53d9f5d875"
)
assert components["eomt-recorded-runner-v1"].sha256 == (
"651e8e06c3912dffb036b7fd08f2c0623f7563d8306cc7aee05db562798518f4"
)
assert components["k1-camera-1-calibration-v1"].sha256 == (
"05f3ad9b38b3a4fc95388a8ec83da83c745e217709e51787b3d5aad0969f6fa9"
)
assert components["k1-valid-fov-identity-v1"].sha256 == (
"b4dd8ddf2b87c1d520ee8a0868c4fea062d7c14d1bae73ccabd3abe1f3acbac2"
)
assert components["k1-valid-fov-mask-v1"].sha256 == (
"a40cee06b7c6f69b6a09a11563dcfd237f3de833b1ccd31459e66692e528ba63"
)
assert definition.result_contract.result_schema == (
"missioncore.recorded-eomt-ddrnet-review/v2"
)
assert definition.result_contract.result_kind == "recorded-perception-qualification"
@@ -0,0 +1,114 @@
from __future__ import annotations
from pathlib import Path
from types import SimpleNamespace
from fastapi import FastAPI
from fastapi.testclient import TestClient
from k1link.observatory.portable_run_definitions import PortableRunDefinitionRegistry
from k1link.observatory.portable_setup_projection import PortableLabV1SetupProjector
from k1link.observatory.source_admission import PortableRecordedSourceCapability
from k1link.sessions import SessionNotFoundError
from k1link.sessions.models import SessionSummary
from k1link.web.observatory_api import build_observatory_router
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
REGISTRY_PATH = REPOSITORY_ROOT / "config" / "observatory-portable-run-definitions.json"
SOURCE_SESSION_ID = "20260831T080000Z_viewer_live"
def _summary() -> SessionSummary:
return SessionSummary(
session_id=SOURCE_SESSION_ID,
display_name="RAVNOVES005",
status="ready",
started_at_utc="2026-08-31T08:00:00Z",
completed_at_utc="2026-08-31T08:10:00Z",
duration_seconds=600.0,
modalities=("point-cloud", "trajectory", "video"),
source_count=3,
total_bytes=1,
replayable=True,
origin="recorded",
)
class _Store:
def get_session(self, session_id: str) -> SimpleNamespace:
if session_id != SOURCE_SESSION_ID:
raise SessionNotFoundError(session_id)
return SimpleNamespace(summary=_summary())
def _projector() -> PortableLabV1SetupProjector:
registry = PortableRunDefinitionRegistry.from_file(REGISTRY_PATH)
definition = registry.definitions[0]
def probe(session_id: str) -> PortableRecordedSourceCapability:
return PortableRecordedSourceCapability(
source_session_id=session_id,
source_catalog_sha256="a" * 64,
source_adapter_sha256=definition.source_adapter.contract_sha256,
camera_segment_count=600,
)
return PortableLabV1SetupProjector(
registry=registry,
capability_probe=probe,
)
def test_portable_setup_catalog_exposes_capability_and_executor_separately() -> None:
app = FastAPI()
app.include_router(
build_observatory_router(
_Store(), # type: ignore[arg-type]
portable_setup_projector=_projector(),
)
)
response = TestClient(app).get(
"/api/v1/observatory/portable-laboratory-setups",
params={"source_session_id": SOURCE_SESSION_ID},
)
assert response.status_code == 200
document = response.json()
assert document["schema_version"] == ("missioncore.observatory-portable-setup-catalog/v2")
setup = document["setups"][0]
assert setup["origin"] == "portable-definition"
assert setup["source_compatibility"]["outcome"] == "pass"
assert setup["executor"]["state"] == "not-installed"
assert setup["existing_results"] == []
assert setup["preflight"]["outcome"] == "blocked"
assert setup["preflight"]["submission_allowed"] is False
def test_portable_setup_catalog_preserves_source_and_optional_slice_failures() -> None:
ready_app = FastAPI()
ready_app.include_router(
build_observatory_router(
_Store(), # type: ignore[arg-type]
portable_setup_projector=_projector(),
)
)
missing = TestClient(ready_app).get(
"/api/v1/observatory/portable-laboratory-setups",
params={"source_session_id": "missing-session"},
)
assert missing.status_code == 404
unavailable_app = FastAPI()
unavailable_app.include_router(
build_observatory_router(
_Store(), # type: ignore[arg-type]
portable_setup_projector_error="drifted portable registry",
)
)
unavailable = TestClient(unavailable_app).get(
"/api/v1/observatory/portable-laboratory-setups",
params={"source_session_id": SOURCE_SESSION_ID},
)
assert unavailable.status_code == 503
assert unavailable.json()["detail"] == "Portable-каталог LAB V1 недоступен."
@@ -0,0 +1,244 @@
from __future__ import annotations
from dataclasses import replace
from pathlib import Path
import pytest
from k1link.observatory.portable_run_definitions import (
PortableExecutorAvailability,
PortableRunDefinitionRegistry,
canonical_sha256,
)
from k1link.observatory.portable_setup_projection import (
PORTABLE_LAB_V1_DISPLAY_NAME,
PORTABLE_LABORATORY_SETUP_CATALOG_SCHEMA,
PortableLabV1SetupProjector,
PortableSetupProjectionError,
PortableSourceCapabilityProbe,
)
from k1link.observatory.source_admission import (
PortableRecordedSourceCapability,
PortableSourceAdmissionIntegrityError,
)
from k1link.sessions.models import SessionSummary
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
REGISTRY_PATH = REPOSITORY_ROOT / "config" / "observatory-portable-run-definitions.json"
RAV004_SESSION_ID = "20260828T130511Z_viewer_live"
NEW_SESSION_ID = "20260831T080000Z_viewer_live"
def _registry() -> PortableRunDefinitionRegistry:
return PortableRunDefinitionRegistry.from_file(REGISTRY_PATH)
def _source(
session_id: str,
*,
display_name: str = "arbitrary operator label",
) -> SessionSummary:
return SessionSummary(
session_id=session_id,
display_name=display_name,
status="ready",
started_at_utc="2026-08-31T08:00:00Z",
completed_at_utc="2026-08-31T08:10:00Z",
duration_seconds=600.0,
modalities=("point-cloud", "trajectory", "video"),
source_count=3,
total_bytes=1,
replayable=True,
origin="recorded",
)
def _capability(
source_session_id: str,
*,
adapter_sha256: str | None = None,
) -> PortableRecordedSourceCapability:
definition = _registry().definitions[0]
return PortableRecordedSourceCapability(
source_session_id=source_session_id,
source_catalog_sha256="a" * 64,
source_adapter_sha256=(adapter_sha256 or definition.source_adapter.contract_sha256),
camera_segment_count=60,
)
def _projector(
capability_probe: PortableSourceCapabilityProbe,
*,
registry: PortableRunDefinitionRegistry | None = None,
) -> PortableLabV1SetupProjector:
return PortableLabV1SetupProjector(
registry=registry or _registry(),
capability_probe=capability_probe,
)
def test_projection_uses_portable_identity_and_exact_model_presentation() -> None:
source = _source(NEW_SESSION_ID, display_name="RAVNOVES005")
projection = _projector(lambda session_id: _capability(session_id)).catalog(source)
setup = projection["setups"][0]
assert projection["schema_version"] == PORTABLE_LABORATORY_SETUP_CATALOG_SCHEMA
assert setup["origin"] == "portable-definition"
assert setup["display_name"] == PORTABLE_LAB_V1_DISPLAY_NAME
assert setup["run_definition"]["models"] == [
{
"name": "EoMT Cityscapes Large 1024",
"release_id": "eomt-cityscapes-large-1024-v1",
"model_id": "tue-mps/cityscapes_semantic_eomt_large_1024",
"architecture": "EomtForUniversalSegmentation",
},
{
"name": "DDRNet-39",
"release_id": "lab-v1-ddrnet-39-goose-fine-64-v1",
"model_id": "goose-ddrnet-class-512",
"architecture": "ddrnet_39",
},
]
requirements = setup["source_requirements"]
assert "source_session_id" not in requirements
assert "source_label" not in requirements
assert "label" not in requirements
assert "RAVNOVES" not in str(requirements)
assert setup["run_definition"]["definition_sha256"] == (
_registry().definitions[0].definition_sha256
)
assert setup["run_definition"]["result_schema"] == (
_registry().definitions[0].result_contract.result_schema
)
assert setup["authority"] == {
"commands_enabled": False,
"actuation_allowed": False,
"navigation_or_safety_accepted": False,
"production_accepted": False,
}
def test_new_compatible_source_passes_capability_but_uninstalled_executor_blocks() -> None:
source = _source(NEW_SESSION_ID)
setup = _projector(lambda session_id: _capability(session_id)).project(source)
assert setup["source_compatibility"] == {
"outcome": "pass",
"compatible": True,
"reason": "Запись соответствует требованиям EoMT + DDRNet.",
}
assert setup["executor"]["state"] == "not-installed"
assert setup["executor"]["ready"] is False
assert setup["existing_results"] == []
assert setup["preflight"] == {
"outcome": "blocked",
"action": "blocked",
"reason": "Вычислительный контур LAB V1 пока недоступен.",
"submission_allowed": False,
"existing_result_ids": [],
}
def test_legacy_vegetation_result_is_never_existing_for_portable_v2() -> None:
setup = _projector(lambda session_id: _capability(session_id)).project(
_source(RAV004_SESSION_ID)
)
assert setup["run_definition"]["result_schema"] == (
"missioncore.recorded-eomt-ddrnet-review/v2"
)
assert setup["existing_results"] == []
assert setup["preflight"] == {
"outcome": "blocked",
"action": "blocked",
"reason": "Вычислительный контур LAB V1 пока недоступен.",
"submission_allowed": False,
"existing_result_ids": [],
}
class _RejectingCapabilityService:
def probe(self, source_session_id: str) -> PortableRecordedSourceCapability:
del source_session_id
raise PortableSourceAdmissionIntegrityError("missing sealed video")
def test_real_capability_probe_rejection_wins_over_summary() -> None:
setup = _projector(_RejectingCapabilityService()).project(_source(RAV004_SESSION_ID))
assert setup["source_compatibility"] == {
"outcome": "blocked",
"compatible": False,
"reason": "Запись не соответствует требованиям EoMT + DDRNet.",
}
assert setup["existing_results"] == []
assert setup["preflight"]["outcome"] == "blocked"
@pytest.mark.parametrize("mismatch", ["source", "adapter"])
def test_capability_probe_must_match_source_and_definition_adapter(
mismatch: str,
) -> None:
source = _source(NEW_SESSION_ID)
def probe(source_session_id: str) -> PortableRecordedSourceCapability:
if mismatch == "source":
return _capability(RAV004_SESSION_ID)
return _capability(source_session_id, adapter_sha256="f" * 64)
with pytest.raises(PortableSetupProjectionError, match=mismatch):
_projector(probe).project(source)
class _ProbeOnlyCapabilityService:
def probe(self, source_session_id: str) -> PortableRecordedSourceCapability:
return _capability(source_session_id)
def check(self, source_session_id: str) -> None:
raise AssertionError(f"full admission check called for {source_session_id}")
def test_projector_uses_lightweight_probe_and_never_full_admission_check() -> None:
setup = _projector(_ProbeOnlyCapabilityService()).project(_source(NEW_SESSION_ID))
assert setup["source_compatibility"]["outcome"] == "pass"
def _ready_registry() -> PortableRunDefinitionRegistry:
blocked = _registry().definitions[0]
ready_executor = PortableExecutorAvailability(
contour_id="worker-006",
state="ready",
release_id="lab-v1-eomt-ddrnet-executor-v1",
release_sha256="1" * 64,
image_sha256="2" * 64,
reason_code=None,
reason=None,
)
identity = blocked.identity_document()
identity["executor"] = ready_executor.identity_document()
ready = replace(
blocked,
executor=ready_executor,
definition_sha256=canonical_sha256(identity),
)
return PortableRunDefinitionRegistry((ready,))
def test_ready_executor_still_blocks_without_a_dispatch_boundary() -> None:
setup = _projector(
lambda session_id: _capability(session_id),
registry=_ready_registry(),
).project(_source(NEW_SESSION_ID))
assert setup["preflight"] == {
"outcome": "blocked",
"action": "blocked",
"reason": (
"Server-side проверка definition/check SHA и постановка portable "
"LAB V1 в очередь пока недоступны."
),
"submission_allowed": False,
"existing_result_ids": [],
}
+558
View File
@@ -0,0 +1,558 @@
from __future__ import annotations
import json
from dataclasses import replace
from pathlib import Path
import pytest
from k1link.observatory.source_admission import (
PORTABLE_SOURCE_BUNDLE_SCHEMA,
PORTABLE_SOURCE_CAPABILITY_SCHEMA,
PortableSourceAdmissionIntegrityError,
PortableSourceAdmissionStaleError,
PortableSourceNotPreparedError,
RecordedK1SourceAdmissionService,
RecordedK1SourceRequirements,
)
from k1link.sessions.media import (
CAMERA_ARCHIVE_SCHEMA,
RecordedMediaEpoch,
RecordedMediaManifest,
RecordedMediaSegment,
)
from k1link.sessions.models import (
LabReplayCapability,
LabSessionBinding,
RecordedMediaArtifact,
ReplayArtifact,
ReplayCommand,
SessionArtifact,
SessionDetail,
SessionSource,
SessionSummary,
)
INIT_SHA256 = "e2279963e16d84c91d68e7dbb1f7efed840533387dfeb844b7398bff45fbde38"
CALIBRATION_SHA256 = "05f3ad9b38b3a4fc95388a8ec83da83c745e217709e51787b3d5aad0969f6fa9"
CATALOG_SHA256 = "1" * 64
RAW_SHA256 = "2" * 64
GENERATION_SHA256 = "3" * 64
SEGMENT_SHA256 = "4" * 64
def _requirements() -> RecordedK1SourceRequirements:
return RecordedK1SourceRequirements(
adapter_id="recorded-k1-right-camera",
adapter_version=1,
plugin_id="nodedc.device.xgrids-lixelkity-k1",
archive_id="xgrids-k1.viewer-live.evidence",
required_modalities=("point-cloud", "trajectory", "video"),
camera_source_id="sensor.camera.right",
camera_semantic_channel_id="camera.video.recorded",
camera_media_type='video/mp4; codecs="avc1.641028"',
camera_init_sha256=INIT_SHA256,
expected_width=800,
expected_height=600,
calibration_slot="camera_1",
calibration_sha256=CALIBRATION_SHA256,
)
def _detail(session_id: str, display_name: str) -> SessionDetail:
return SessionDetail(
summary=SessionSummary(
session_id=session_id,
display_name=display_name,
status="ready",
started_at_utc="2026-08-31T00:00:00Z",
completed_at_utc="2026-08-31T00:10:00Z",
duration_seconds=600.0,
modalities=("point-cloud", "trajectory", "video"),
source_count=3,
total_bytes=123,
replayable=True,
origin="xgrids-k1.viewer-live.evidence",
),
sources=(
SessionSource(
source_id="sensor.camera.right",
semantic_channel_id="camera.video.recorded",
modality="video",
status="recorded",
seekable=True,
artifact_id="recorded-video-right",
),
SessionSource(
source_id="sensor.lidar.primary",
semantic_channel_id="spatial.point-cloud.recorded",
modality="point-cloud",
status="recorded",
seekable=True,
artifact_id="raw-transport-primary",
),
SessionSource(
source_id="spatial.trajectory",
semantic_channel_id="spatial.pose.recorded",
modality="trajectory",
status="recorded",
seekable=True,
artifact_id="raw-transport-primary",
),
),
artifacts=(
SessionArtifact(
artifact_id="raw-transport-primary",
kind="raw-transport",
media_type="application/x-nodedc-k1mqtt",
byte_length=100,
sha256=RAW_SHA256,
integrity_status="verified",
),
SessionArtifact(
artifact_id="recorded-video-right",
kind="recorded-video",
media_type="video/mp4",
byte_length=20,
sha256=None,
integrity_status="validated-structure",
),
),
plugin_id="nodedc.device.xgrids-lixelkity-k1",
archive_id="xgrids-k1.viewer-live.evidence",
)
def _replay(session_id: str, root: Path) -> ReplayCommand:
return ReplayCommand(
session_id=session_id,
plugin_id="nodedc.device.xgrids-lixelkity-k1",
allowed_root=root,
session_root=root / session_id,
primary_artifact_id="raw-transport-primary",
artifacts=(
ReplayArtifact(
artifact_id="raw-transport-primary",
path=root / "mqtt.raw.k1mqtt",
media_type="application/x-nodedc-k1mqtt",
file_byte_length=100,
replay_byte_length=100,
expected_sha256=RAW_SHA256,
),
),
timeline_origin_epoch_ns=1,
timeline_origin_monotonic_ns=2,
speed=1.0,
loop=False,
)
def _recorded_media(session_id: str, root: Path) -> RecordedMediaArtifact:
return RecordedMediaArtifact(
session_id=session_id,
public_source_id="recorded.camera.right",
artifact_id="recorded-video-right",
source_path=root / "media" / "sensor.camera.right",
byte_length=20,
)
def _manifest(session_id: str, root: Path) -> RecordedMediaManifest:
segment = RecordedMediaSegment(
sequence=1,
path=root / "epoch-1" / "segments" / "1.m4s",
byte_length=10,
sha256=SEGMENT_SHA256,
random_access=True,
end_time_seconds=0.1,
)
epoch = RecordedMediaEpoch(
ordinal=1,
path=root / "epoch-1",
init_path=root / "epoch-1" / "init.mp4",
init_byte_length=10,
init_sha256=INIT_SHA256,
media_type='video/mp4; codecs="avc1.641028"',
timeline_start_seconds=10.0,
timeline_end_seconds=10.1,
segments=(segment,),
)
return RecordedMediaManifest(
session_id=session_id,
public_source_id="recorded.camera.right",
artifact_id="recorded-video-right",
synchronization="host-arrival-best-effort",
generation_sha256=GENERATION_SHA256,
timeline_start_seconds=10.0,
timeline_end_seconds=10.1,
byte_length=20,
epochs=(epoch,),
)
class _Store:
def __init__(
self,
root: Path,
detail: SessionDetail,
*,
catalogs: tuple[str, ...] = (CATALOG_SHA256,),
) -> None:
self.data_dir = root
self.detail = detail
self.replay = _replay(detail.summary.session_id, root)
self.media = (_recorded_media(detail.summary.session_id, root),)
self.catalogs = catalogs
self.catalog_reads = 0
self.prepare_replay_calls = 0
self.recorded_media_reads = 0
def get_session_with_catalog_snapshot(
self,
session_id: str,
) -> tuple[SessionDetail, str]:
assert session_id == self.detail.summary.session_id
index = min(self.catalog_reads, len(self.catalogs) - 1)
self.catalog_reads += 1
return self.detail, self.catalogs[index]
def prepare_replay(self, session_id: str) -> ReplayCommand:
assert session_id == self.detail.summary.session_id
self.prepare_replay_calls += 1
return self.replay
def list_recorded_media(
self,
session_id: str,
) -> tuple[RecordedMediaArtifact, ...]:
assert session_id == self.detail.summary.session_id
self.recorded_media_reads += 1
return self.media
class _Inspector:
def __init__(self, manifest: RecordedMediaManifest | None) -> None:
self.manifest = manifest
self.inspect_calls = 0
self.restore_calls = 0
def inspect(
self,
artifact: RecordedMediaArtifact,
replay: ReplayCommand,
) -> RecordedMediaManifest | None:
assert artifact.session_id == replay.session_id
self.inspect_calls += 1
return self.manifest
def restore_prepared(
self,
artifact: RecordedMediaArtifact,
replay: ReplayCommand,
) -> RecordedMediaManifest | None:
assert artifact.session_id == replay.session_id
self.restore_calls += 1
return self.manifest
def _write_probe_summary(root: Path, *, segment_count: int = 7) -> None:
epoch = root / "media" / "sensor.camera.right" / "epoch-1"
epoch.mkdir(parents=True)
(epoch / "summary.json").write_text(
json.dumps(
{
"schema_version": CAMERA_ARCHIVE_SCHEMA,
"source_id": "sensor.camera.right",
"codec_epoch": 1,
"status": "complete",
"segment_count": segment_count,
"entry_count": segment_count,
"media_segment_count": segment_count,
"init_sha256": INIT_SHA256,
"synchronization": "host-arrival-best-effort",
"commit_policy": "per-segment-fsync",
"failure_code": None,
"artifacts": {
"init": "init.mp4",
"segments": "segments",
"index": "index.jsonl",
},
}
),
encoding="utf-8",
)
def _service(
tmp_path: Path,
*,
session_id: str = "20260831T000000Z_viewer_live",
display_name: str = "RAVNOVES005",
detail: SessionDetail | None = None,
manifest: RecordedMediaManifest | None = None,
) -> RecordedK1SourceAdmissionService:
active_detail = detail or _detail(session_id, display_name)
store = _Store(tmp_path, active_detail)
return RecordedK1SourceAdmissionService(
data_dir=tmp_path,
session_store=store, # type: ignore[arg-type]
media_inspector=_Inspector(
manifest or _manifest(active_detail.summary.session_id, tmp_path)
), # type: ignore[arg-type]
requirements=_requirements(),
)
@pytest.mark.parametrize(
("session_id", "display_name"),
(
("20260720T065719Z_viewer_live", "RAVNOVES00"),
("20260828T130511Z_viewer_live", "RAVNOVES004TREE"),
("20260831T000000Z_viewer_live", "RAVNOVES005"),
),
)
def test_portable_source_admission_is_independent_from_session_label(
tmp_path: Path,
session_id: str,
display_name: str,
) -> None:
admission = _service(
tmp_path,
session_id=session_id,
display_name=display_name,
).check(session_id)
assert admission.source_session_id == session_id
assert admission.frame_count == 1
bundle = json.loads(admission.source_bundle)
capability = json.loads(admission.capability_manifest)
assert bundle["schema_version"] == PORTABLE_SOURCE_BUNDLE_SCHEMA
assert capability["schema_version"] == PORTABLE_SOURCE_CAPABILITY_SCHEMA
assert "RAVNOVES" not in admission.source_bundle.decode()
assert "path" not in admission.source_bundle.decode()
assert capability["camera_profile"]["width"] == 800
assert capability["camera_profile"]["height"] == 600
def test_catalog_capability_check_restores_media_without_preparing_it(
tmp_path: Path,
) -> None:
detail = _detail("20260831T000000Z_viewer_live", "RAVNOVES005")
store = _Store(tmp_path, detail)
inspector = _Inspector(_manifest(detail.summary.session_id, tmp_path))
service = RecordedK1SourceAdmissionService(
data_dir=tmp_path,
session_store=store, # type: ignore[arg-type]
media_inspector=inspector, # type: ignore[arg-type]
requirements=_requirements(),
prepare_media=False,
)
admission = service.check(detail.summary.session_id)
assert admission.frame_count == 1
assert inspector.inspect_calls == 0
assert inspector.restore_calls == 1
def test_lightweight_probe_reads_only_catalog_media_handle_and_summary(
tmp_path: Path,
) -> None:
detail = _detail("20260831T000000Z_viewer_live", "ignored-label")
store = _Store(tmp_path, detail)
inspector = _Inspector(_manifest(detail.summary.session_id, tmp_path))
_write_probe_summary(tmp_path, segment_count=23)
service = RecordedK1SourceAdmissionService(
data_dir=tmp_path,
session_store=store, # type: ignore[arg-type]
media_inspector=inspector, # type: ignore[arg-type]
requirements=_requirements(),
)
capability = service.probe(detail.summary.session_id)
assert capability.source_session_id == detail.summary.session_id
assert capability.source_catalog_sha256 == CATALOG_SHA256
assert capability.source_adapter_sha256 == _requirements().adapter_sha256
assert capability.camera_segment_count == 23
assert store.catalog_reads == 1
assert store.recorded_media_reads == 1
assert store.prepare_replay_calls == 0
assert inspector.inspect_calls == 0
assert inspector.restore_calls == 0
assert not (tmp_path / "media" / "sensor.camera.right" / "epoch-1" / "segments").exists()
assert not (tmp_path / "observatory-portable-source-contracts").exists()
def test_read_only_check_reports_missing_prepared_manifest_without_writes(
tmp_path: Path,
) -> None:
detail = _detail("20260831T000000Z_viewer_live", "ignored-label")
store = _Store(tmp_path, detail)
inspector = _Inspector(None)
service = RecordedK1SourceAdmissionService(
data_dir=tmp_path,
session_store=store, # type: ignore[arg-type]
media_inspector=inspector, # type: ignore[arg-type]
requirements=_requirements(),
)
with pytest.raises(PortableSourceNotPreparedError, match="not been prepared"):
service.check(detail.summary.session_id)
assert inspector.inspect_calls == 0
assert inspector.restore_calls == 1
assert not (tmp_path / "observatory-portable-source-contracts").exists()
@pytest.mark.parametrize(
("mutation", "message"),
(
("replay-session", "another source contract"),
("replay-digest", "replay member disagrees"),
("media-session", "artifact identity disagrees"),
),
)
def test_full_check_rejects_cross_bound_replay_and_media(
tmp_path: Path,
mutation: str,
message: str,
) -> None:
detail = _detail("20260831T000000Z_viewer_live", "ignored-label")
store = _Store(tmp_path, detail)
if mutation == "replay-session":
store.replay = replace(store.replay, session_id="another-session")
elif mutation == "replay-digest":
store.replay = replace(
store.replay,
artifacts=(replace(store.replay.artifacts[0], expected_sha256="9" * 64),),
)
else:
store.media = (replace(store.media[0], session_id="another-session"),)
inspector = _Inspector(_manifest(detail.summary.session_id, tmp_path))
service = RecordedK1SourceAdmissionService(
data_dir=tmp_path,
session_store=store, # type: ignore[arg-type]
media_inspector=inspector, # type: ignore[arg-type]
requirements=_requirements(),
)
with pytest.raises(PortableSourceAdmissionIntegrityError, match=message):
service.check(detail.summary.session_id)
assert inspector.inspect_calls == 0
assert not (tmp_path / "observatory-portable-source-contracts").exists()
def test_admit_rechecks_catalog_immediately_before_persistence(
tmp_path: Path,
) -> None:
detail = _detail("20260831T000000Z_viewer_live", "ignored-label")
store = _Store(tmp_path, detail, catalogs=(CATALOG_SHA256, "7" * 64))
service = RecordedK1SourceAdmissionService(
data_dir=tmp_path,
session_store=store, # type: ignore[arg-type]
media_inspector=_Inspector(_manifest(detail.summary.session_id, tmp_path)), # type: ignore[arg-type]
requirements=_requirements(),
)
with pytest.raises(PortableSourceAdmissionStaleError, match="changed"):
service.admit(detail.summary.session_id)
assert store.catalog_reads == 2
assert not (tmp_path / "observatory-portable-source-contracts").exists()
def test_portable_source_admission_rejects_missing_video(tmp_path: Path) -> None:
detail = _detail("20260728T163450Z_viewer_live", "RAVNOVES01")
detail = replace(
detail,
summary=replace(
detail.summary,
modalities=("point-cloud", "trajectory"),
source_count=2,
),
sources=tuple(source for source in detail.sources if source.modality != "video"),
artifacts=tuple(
artifact
for artifact in detail.artifacts
if artifact.artifact_id != "recorded-video-right"
),
)
with pytest.raises(
PortableSourceAdmissionIntegrityError,
match="modalities",
):
_service(tmp_path, detail=detail).check(detail.summary.session_id)
def test_portable_source_admission_rejects_another_camera_profile(
tmp_path: Path,
) -> None:
session_id = "20260831T000000Z_viewer_live"
manifest = _manifest(session_id, tmp_path)
manifest = replace(
manifest,
epochs=(replace(manifest.epochs[0], init_sha256="9" * 64),),
)
with pytest.raises(
PortableSourceAdmissionIntegrityError,
match="media profile",
):
_service(tmp_path, session_id=session_id, manifest=manifest).check(session_id)
def test_portable_source_admission_rejects_lab_chaining(tmp_path: Path) -> None:
detail = _detail("20260831T000000Z_viewer_live", "Derived")
lab = LabSessionBinding(
session_id=detail.summary.session_id,
source_session_id="20260828T130511Z_viewer_live",
lab_id="LAB V1",
result_kind="recorded-perception-qualification",
result_id="lab-v1-result",
source_result_id=None,
config_sha256=None,
run_created_at_utc="2026-08-31T00:00:00Z",
published_at_utc="2026-08-31T00:00:01Z",
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=False,
),
provenance={},
)
detail = replace(detail, summary=replace(detail.summary, lab=lab))
with pytest.raises(
PortableSourceAdmissionIntegrityError,
match="not an admitted",
):
_service(tmp_path, detail=detail).check(detail.summary.session_id)
def test_portable_source_admission_persists_only_content_addressed_documents(
tmp_path: Path,
) -> None:
session_id = "20260831T000000Z_viewer_live"
service = _service(tmp_path, session_id=session_id)
first = service.admit(session_id)
repeated = service.admit(session_id)
assert repeated == first
root = tmp_path / "observatory-portable-source-contracts"
assert sorted(path.name for path in root.iterdir()) == sorted(
(
f"{first.source_bundle_sha256}.json",
f"{first.source_capability_manifest_sha256}.json",
)
)
assert (root / f"{first.source_bundle_sha256}.json").read_bytes() == first.source_bundle
assert (
root / f"{first.source_capability_manifest_sha256}.json"
).read_bytes() == first.capability_manifest
+416
View File
@@ -0,0 +1,416 @@
from __future__ import annotations
from collections.abc import Callable, Mapping
from copy import deepcopy
from dataclasses import dataclass, field
from pathlib import Path
from threading import Event, Thread
import pytest
from k1link.observatory.recorded_jobs import (
ObservatoryRecordedJobIntent,
ObservatoryRecordedJobQueue,
RecordedRunDefinition,
RecordedRunDefinitionRegistry,
)
from k1link.observatory.worker_agent import (
MAX_EXECUTOR_FAILURE_MESSAGE_LENGTH,
WORKER_006_CONTOUR_ID,
ObservatoryWorkerAgent,
ObservatoryWorkerAgentBusyError,
ObservatoryWorkerExecutionResult,
ObservatoryWorkerExecutorIdentity,
ObservatoryWorkerExecutorRegistration,
ObservatoryWorkerExecutorRegistry,
SealedObservatoryRecordedJob,
)
DEFINITION_SHA = "1" * 64
ADAPTER_SHA = "2" * 64
EXECUTOR_RELEASE_SHA = "3" * 64
EXECUTOR_IMAGE_SHA = "4" * 64
MODEL_MANIFEST_SHA = "5" * 64
RESOURCE_PROFILE_SHA = "6" * 64
CATALOG_SHA = "7" * 64
SOURCE_BUNDLE_SHA = "8" * 64
SOURCE_CAPABILITY_SHA = "9" * 64
RESULT_SHA = "a" * 64
def _definition() -> RecordedRunDefinition:
return RecordedRunDefinition(
setup_id="portable-lab-v1",
definition_id="portable-lab-v1-definition",
definition_version=1,
definition_sha256=DEFINITION_SHA,
source_adapter_id="sealed-session-source",
source_adapter_version=1,
source_adapter_sha256=ADAPTER_SHA,
executor_release_id="portable-lab-v1-worker",
executor_release_sha256=EXECUTOR_RELEASE_SHA,
executor_image_sha256=EXECUTOR_IMAGE_SHA,
model_release_ids=("eomt-cityscapes-large", "ddrnet-39"),
model_manifest_sha256=MODEL_MANIFEST_SHA,
resource_profile_id="worker006-single-gpu",
resource_profile_sha256=RESOURCE_PROFILE_SHA,
checkpoint_policy="cooperative",
allowed_checkpoints=("semantic-pass",),
)
def _identity(
*,
release_sha256: str = EXECUTOR_RELEASE_SHA,
) -> ObservatoryWorkerExecutorIdentity:
return ObservatoryWorkerExecutorIdentity(
release_sha256=release_sha256,
image_sha256=EXECUTOR_IMAGE_SHA,
model_manifest_sha256=MODEL_MANIFEST_SHA,
resource_profile_sha256=RESOURCE_PROFILE_SHA,
)
def _queue(tmp_path: Path) -> ObservatoryRecordedJobQueue:
return ObservatoryRecordedJobQueue(
tmp_path,
definitions=RecordedRunDefinitionRegistry((_definition(),)),
)
def _enqueue(queue: ObservatoryRecordedJobQueue) -> str:
job, created = queue.submit(
ObservatoryRecordedJobIntent(
idempotency_key="worker-agent:test-job",
source_session_id="20260831T120000Z_viewer_live",
source_catalog_sha256=CATALOG_SHA,
source_bundle_sha256=SOURCE_BUNDLE_SHA,
source_capability_manifest_sha256=SOURCE_CAPABILITY_SHA,
setup_id="portable-lab-v1",
definition_sha256=DEFINITION_SHA,
),
enqueue=True,
)
assert created is True
return job.job_id
ClaimMutator = Callable[[dict[str, object]], dict[str, object]]
@dataclass(slots=True)
class FakeTransport:
queue: ObservatoryRecordedJobQueue
claim_mutator: ClaimMutator | None = None
starts: list[str] = field(default_factory=list)
successes: list[tuple[str, str, str]] = field(default_factory=list)
failures: list[tuple[str, str, str]] = field(default_factory=list)
def claim_next(
self,
*,
claimant_id: str,
claim_request_id: str,
) -> Mapping[str, object] | None:
claim = self.queue.claim_next(
claimant_id=claimant_id,
claim_request_id=claim_request_id,
)
if claim is None:
return None
payload = claim.as_dict()
return self.claim_mutator(payload) if self.claim_mutator is not None else payload
def start(
self,
*,
claimant_id: str,
job_id: str,
claim_token: str,
) -> Mapping[str, object]:
assert claimant_id == WORKER_006_CONTOUR_ID
self.starts.append(job_id)
return self.queue.start(job_id, claim_token=claim_token).as_dict()
def succeed(
self,
*,
claimant_id: str,
job_id: str,
claim_token: str,
result_id: str,
result_sha256: str,
) -> Mapping[str, object]:
assert claimant_id == WORKER_006_CONTOUR_ID
self.successes.append((job_id, result_id, result_sha256))
return self.queue.succeed(
job_id,
claim_token=claim_token,
result_id=result_id,
result_sha256=result_sha256,
).as_dict()
def fail(
self,
*,
claimant_id: str,
job_id: str,
claim_token: str,
error_code: str,
message: str,
) -> Mapping[str, object]:
assert claimant_id == WORKER_006_CONTOUR_ID
self.failures.append((job_id, error_code, message))
return self.queue.fail(
job_id,
claim_token=claim_token,
error_code=error_code,
message=message,
).as_dict()
@dataclass(slots=True)
class FakeExecutor:
result: ObservatoryWorkerExecutionResult = field(
default_factory=lambda: ObservatoryWorkerExecutionResult(
result_id="lab-v1-result",
result_sha256=RESULT_SHA,
)
)
error: Exception | None = None
jobs: list[SealedObservatoryRecordedJob] = field(default_factory=list)
def execute(
self,
job: SealedObservatoryRecordedJob,
) -> ObservatoryWorkerExecutionResult:
self.jobs.append(job)
if self.error is not None:
raise self.error
return self.result
def _agent(
transport: FakeTransport,
executor: FakeExecutor,
*,
identity: ObservatoryWorkerExecutorIdentity | None = None,
) -> ObservatoryWorkerAgent:
return ObservatoryWorkerAgent(
transport=transport,
executors=ObservatoryWorkerExecutorRegistry(
(
ObservatoryWorkerExecutorRegistration(
identity=identity or _identity(),
adapter=executor,
),
)
),
claim_request_id_factory=lambda: "worker-006:test-cycle",
)
def test_worker_agent_executes_one_sealed_allowlisted_job(tmp_path: Path) -> None:
queue = _queue(tmp_path)
job_id = _enqueue(queue)
transport = FakeTransport(queue)
executor = FakeExecutor()
report = _agent(transport, executor).run_once()
assert report.state == "succeeded"
assert report.job_id == job_id
assert report.result_id == "lab-v1-result"
assert transport.starts == [job_id]
assert transport.successes == [(job_id, "lab-v1-result", RESULT_SHA)]
assert transport.failures == []
assert len(executor.jobs) == 1
sealed_job = executor.jobs[0]
assert sealed_job.executor_identity == _identity()
assert sealed_job.source_bundle_sha256 == SOURCE_BUNDLE_SHA
assert not hasattr(sealed_job, "command")
assert not hasattr(sealed_job, "path")
assert not hasattr(sealed_job, "environment")
assert queue.get(job_id).state == "succeeded"
def test_worker_agent_leaves_empty_queue_untouched(tmp_path: Path) -> None:
queue = _queue(tmp_path)
transport = FakeTransport(queue)
executor = FakeExecutor()
report = _agent(transport, executor).run_once()
assert report.state == "empty"
assert report.job_id is None
assert transport.starts == []
assert transport.failures == []
assert executor.jobs == []
def test_exact_release_mismatch_fails_closed_without_start(tmp_path: Path) -> None:
queue = _queue(tmp_path)
job_id = _enqueue(queue)
transport = FakeTransport(queue)
executor = FakeExecutor()
report = _agent(
transport,
executor,
identity=_identity(release_sha256="b" * 64),
).run_once()
assert report.state == "failed"
assert report.failure_code == "executor-not-allowlisted"
assert transport.starts == []
assert transport.successes == []
assert transport.failures == [
(
job_id,
"executor-not-allowlisted",
"Exact executor identity is not installed on Worker 006.",
)
]
assert executor.jobs == []
assert queue.get(job_id).state == "failed"
def _spoof_claimant(payload: dict[str, object]) -> dict[str, object]:
changed = deepcopy(payload)
changed["claimant_id"] = "worker-007"
return changed
def _inject_unknown_execution_payload(payload: dict[str, object]) -> dict[str, object]:
changed = deepcopy(payload)
job = changed["job"]
assert isinstance(job, dict)
job["command"] = ["python", "untrusted.py"]
return changed
def _corrupt_job_identity(payload: dict[str, object]) -> dict[str, object]:
changed = deepcopy(payload)
job = changed["job"]
assert isinstance(job, dict)
source = job["source"]
assert isinstance(source, dict)
source["bundle_sha256"] = "c" * 64
return changed
@pytest.mark.parametrize(
"mutator",
[_spoof_claimant, _inject_unknown_execution_payload, _corrupt_job_identity],
)
def test_spoofed_unknown_or_corrupted_claim_is_rejected_without_execution(
tmp_path: Path,
mutator: ClaimMutator,
) -> None:
queue = _queue(tmp_path)
job_id = _enqueue(queue)
transport = FakeTransport(queue, claim_mutator=mutator)
executor = FakeExecutor()
report = _agent(transport, executor).run_once()
assert report.state == "rejected"
assert report.failure_code == "claim-rejected"
assert transport.starts == []
assert transport.successes == []
assert transport.failures == []
assert executor.jobs == []
assert queue.get(job_id).state == "claimed"
def test_executor_error_is_reported_as_bounded_failure(tmp_path: Path) -> None:
queue = _queue(tmp_path)
job_id = _enqueue(queue)
transport = FakeTransport(queue)
executor = FakeExecutor(error=RuntimeError("unsafe\n" + ("x" * 2_000)))
report = _agent(transport, executor).run_once()
assert report.state == "failed"
assert report.failure_code == "executor-error"
assert transport.starts == [job_id]
assert transport.successes == []
assert len(transport.failures) == 1
failed_job_id, failure_code, message = transport.failures[0]
assert failed_job_id == job_id
assert failure_code == "executor-error"
assert len(message) <= MAX_EXECUTOR_FAILURE_MESSAGE_LENGTH
assert "\n" not in message
assert queue.get(job_id).state == "failed"
@dataclass(slots=True)
class BlockingEmptyTransport:
entered: Event
release: Event
def claim_next(
self,
*,
claimant_id: str,
claim_request_id: str,
) -> Mapping[str, object] | None:
assert claimant_id == WORKER_006_CONTOUR_ID
assert claim_request_id == "worker-006:overlap-test"
self.entered.set()
assert self.release.wait(timeout=2)
return None
def start(
self,
*,
claimant_id: str,
job_id: str,
claim_token: str,
) -> Mapping[str, object]:
raise AssertionError("an empty transport cannot start a job")
def succeed(
self,
*,
claimant_id: str,
job_id: str,
claim_token: str,
result_id: str,
result_sha256: str,
) -> Mapping[str, object]:
raise AssertionError("an empty transport cannot succeed a job")
def fail(
self,
*,
claimant_id: str,
job_id: str,
claim_token: str,
error_code: str,
message: str,
) -> Mapping[str, object]:
raise AssertionError("an empty transport cannot fail a job")
def test_worker_agent_allows_only_one_claim_cycle_at_a_time() -> None:
entered = Event()
release = Event()
transport = BlockingEmptyTransport(entered=entered, release=release)
agent = ObservatoryWorkerAgent(
transport=transport,
executors=ObservatoryWorkerExecutorRegistry(()),
claim_request_id_factory=lambda: "worker-006:overlap-test",
)
reports: list[object] = []
first = Thread(target=lambda: reports.append(agent.run_once()))
first.start()
assert entered.wait(timeout=2)
with pytest.raises(ObservatoryWorkerAgentBusyError, match="active claim"):
agent.run_once()
release.set()
first.join(timeout=2)
assert not first.is_alive()
assert len(reports) == 1
+408
View File
@@ -0,0 +1,408 @@
from __future__ import annotations
import hashlib
from pathlib import Path
from typing import Any
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from k1link.observatory.recorded_jobs import (
ObservatoryRecordedJobIntent,
ObservatoryRecordedJobQueue,
RecordedRunDefinition,
RecordedRunDefinitionRegistry,
)
from k1link.web.observatory_worker_api import (
OBSERVATORY_WORKER_CONTOUR_HEADER,
ObservatoryWorkerAuthentication,
build_observatory_worker_router,
load_observatory_worker_authentication,
)
WORKER_TOKEN = "worker-006-test-bearer-secret-32bytes"
WORKER_TOKEN_SHA256 = hashlib.sha256(WORKER_TOKEN.encode()).hexdigest()
WORKER_HEADERS = {
"Authorization": f"Bearer {WORKER_TOKEN}",
OBSERVATORY_WORKER_CONTOUR_HEADER: "worker-006",
}
CLAIM_SCHEMA = "missioncore.observatory-worker-claim-request/v1"
START_SCHEMA = "missioncore.observatory-worker-start-request/v1"
CHECKPOINT_SCHEMA = "missioncore.observatory-worker-checkpoint-request/v1"
SUCCEED_SCHEMA = "missioncore.observatory-worker-succeed-request/v1"
FAIL_SCHEMA = "missioncore.observatory-worker-fail-request/v1"
def _definition() -> RecordedRunDefinition:
return RecordedRunDefinition(
setup_id="portable-lab-v1",
definition_id="portable-lab-v1-definition",
definition_version=1,
definition_sha256="1" * 64,
source_adapter_id="sealed-session-source",
source_adapter_version=1,
source_adapter_sha256="2" * 64,
executor_release_id="portable-lab-v1-worker",
executor_release_sha256="3" * 64,
executor_image_sha256="4" * 64,
model_release_ids=("eomt-cityscapes-large", "ddrnet-39"),
model_manifest_sha256="5" * 64,
resource_profile_id="worker006-single-gpu",
resource_profile_sha256="6" * 64,
checkpoint_policy="cooperative",
allowed_checkpoints=("semantic-pass",),
)
def _services(tmp_path: Path) -> tuple[TestClient, ObservatoryRecordedJobQueue]:
definition = _definition()
queue = ObservatoryRecordedJobQueue(
tmp_path,
definitions=RecordedRunDefinitionRegistry((definition,)),
)
app = FastAPI()
app.include_router(
build_observatory_worker_router(
queue,
authentication=ObservatoryWorkerAuthentication(
bearer_token_sha256=WORKER_TOKEN_SHA256,
contour_id="worker-006",
),
)
)
return TestClient(app), queue
def _enqueue(
queue: ObservatoryRecordedJobQueue,
*,
idempotency_key: str = "worker-api:test-job",
) -> str:
definition = _definition()
job, created = queue.submit(
ObservatoryRecordedJobIntent(
idempotency_key=idempotency_key,
source_session_id="20260831T120000Z_viewer_live",
source_catalog_sha256="7" * 64,
source_bundle_sha256="8" * 64,
source_capability_manifest_sha256="9" * 64,
setup_id=definition.setup_id,
definition_sha256=definition.definition_sha256,
),
enqueue=True,
)
assert created is True
return job.job_id
def _claim(
client: TestClient,
*,
claim_request_id: str = "worker-006:test-claim",
) -> dict[str, Any]:
response = client.post(
"/api/v1/worker/observatory/recorded-jobs/claims",
headers=WORKER_HEADERS,
json={
"schema_version": CLAIM_SCHEMA,
"claim_request_id": claim_request_id,
},
)
assert response.status_code == 200
return response.json()
def test_worker_authentication_requires_digest_and_configured_contour(
tmp_path: Path,
) -> None:
client, queue = _services(tmp_path)
_enqueue(queue)
request = {
"schema_version": CLAIM_SCHEMA,
"claim_request_id": "worker-006:auth-claim",
}
missing = client.post(
"/api/v1/worker/observatory/recorded-jobs/claims",
json=request,
)
wrong_token = client.post(
"/api/v1/worker/observatory/recorded-jobs/claims",
headers={
"Authorization": "Bearer wrong-secret",
OBSERVATORY_WORKER_CONTOUR_HEADER: "worker-006",
},
json=request,
)
wrong_contour = client.post(
"/api/v1/worker/observatory/recorded-jobs/claims",
headers={
"Authorization": f"Bearer {WORKER_TOKEN}",
OBSERVATORY_WORKER_CONTOUR_HEADER: "worker-007",
},
json=request,
)
assert missing.status_code == 401
assert missing.headers["www-authenticate"] == "Bearer"
assert wrong_token.status_code == 401
assert wrong_contour.status_code == 403
assert queue.list_jobs()[0].state == "queued"
claimed = client.post(
"/api/v1/worker/observatory/recorded-jobs/claims",
headers=WORKER_HEADERS,
json=request,
)
assert claimed.status_code == 200
assert claimed.json()["claimant_id"] == "worker-006"
assert WORKER_TOKEN not in claimed.text
def test_claim_is_idempotent_and_request_schema_rejects_execution_inputs(
tmp_path: Path,
) -> None:
client, queue = _services(tmp_path)
job_id = _enqueue(queue)
request = {
"schema_version": CLAIM_SCHEMA,
"claim_request_id": "worker-006:stable-claim",
}
first = client.post(
"/api/v1/worker/observatory/recorded-jobs/claims",
headers=WORKER_HEADERS,
json=request,
)
repeated = client.post(
"/api/v1/worker/observatory/recorded-jobs/claims",
headers=WORKER_HEADERS,
json=request,
)
forbidden_inputs = client.post(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}/start",
headers=WORKER_HEADERS,
json={
"schema_version": START_SCHEMA,
"claim_token": first.json()["claim_token"],
"command": ["python", "worker.py"],
"working_path": "/tmp/run",
"environment": {"CUDA_VISIBLE_DEVICES": "0"},
"image": "unsealed:latest",
},
)
assert first.status_code == 200
assert repeated.status_code == 200
assert first.json()["job"]["job_id"] == job_id
assert repeated.json() == first.json()
assert queue.get(job_id).claim_generation == 1
assert forbidden_inputs.status_code == 422
assert queue.get(job_id).state == "claimed"
def test_empty_claim_is_204_and_empty_receipt_remains_idempotent(
tmp_path: Path,
) -> None:
client, queue = _services(tmp_path)
request = {
"schema_version": CLAIM_SCHEMA,
"claim_request_id": "worker-006:empty-poll",
}
first = client.post(
"/api/v1/worker/observatory/recorded-jobs/claims",
headers=WORKER_HEADERS,
json=request,
)
_enqueue(queue)
repeated = client.post(
"/api/v1/worker/observatory/recorded-jobs/claims",
headers=WORKER_HEADERS,
json=request,
)
fresh = client.post(
"/api/v1/worker/observatory/recorded-jobs/claims",
headers=WORKER_HEADERS,
json={
"schema_version": CLAIM_SCHEMA,
"claim_request_id": "worker-006:fresh-poll",
},
)
assert first.status_code == 204
assert first.content == b""
assert repeated.status_code == 204
assert fresh.status_code == 200
def test_worker_can_start_checkpoint_and_read_job_but_stale_token_fails_closed(
tmp_path: Path,
) -> None:
client, queue = _services(tmp_path)
job_id = _enqueue(queue)
claim = _claim(client)
claim_token = claim["claim_token"]
stale = client.post(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}/start",
headers=WORKER_HEADERS,
json={"schema_version": START_SCHEMA, "claim_token": "a" * 64},
)
started = client.post(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}/start",
headers=WORKER_HEADERS,
json={"schema_version": START_SCHEMA, "claim_token": claim_token},
)
checkpointed = client.post(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}/checkpoint",
headers=WORKER_HEADERS,
json={
"schema_version": CHECKPOINT_SCHEMA,
"claim_token": claim_token,
"checkpoint_id": "semantic-pass",
},
)
fetched = client.get(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}",
headers=WORKER_HEADERS,
)
assert stale.status_code == 409
assert started.status_code == 200
assert started.json()["state"] == "running"
assert checkpointed.status_code == 200
assert checkpointed.json()["state"] == "running"
assert checkpointed.json()["checkpoint_policy"]["last_checkpoint_id"] == ("semantic-pass")
assert fetched.status_code == 200
assert fetched.json()["job_id"] == job_id
assert "active_claim_token" not in fetched.json()
def test_worker_can_publish_success_idempotently(tmp_path: Path) -> None:
client, queue = _services(tmp_path)
job_id = _enqueue(queue)
claim_token = _claim(client)["claim_token"]
client.post(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}/start",
headers=WORKER_HEADERS,
json={"schema_version": START_SCHEMA, "claim_token": claim_token},
)
request = {
"schema_version": SUCCEED_SCHEMA,
"claim_token": claim_token,
"result_id": "lab-v1-worker-result-001",
"result_sha256": "b" * 64,
}
succeeded = client.post(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}/succeed",
headers=WORKER_HEADERS,
json=request,
)
repeated = client.post(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}/succeed",
headers=WORKER_HEADERS,
json=request,
)
conflicting_failure = client.post(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}/fail",
headers=WORKER_HEADERS,
json={
"schema_version": FAIL_SCHEMA,
"claim_token": claim_token,
"error_code": "executor-failed",
"message": "Must not replace sealed success.",
},
)
assert succeeded.status_code == 200
assert succeeded.json()["state"] == "succeeded"
assert succeeded.json()["result"] == {
"result_id": "lab-v1-worker-result-001",
"sha256": "b" * 64,
}
assert repeated.status_code == 200
assert repeated.json() == succeeded.json()
assert conflicting_failure.status_code == 409
def test_worker_can_fail_claimed_job_idempotently(tmp_path: Path) -> None:
client, queue = _services(tmp_path)
job_id = _enqueue(queue)
claim_token = _claim(client)["claim_token"]
request = {
"schema_version": FAIL_SCHEMA,
"claim_token": claim_token,
"error_code": "model-unavailable",
"message": "Sealed model release is not installed.",
}
failed = client.post(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}/fail",
headers=WORKER_HEADERS,
json=request,
)
repeated = client.post(
f"/api/v1/worker/observatory/recorded-jobs/{job_id}/fail",
headers=WORKER_HEADERS,
json=request,
)
assert failed.status_code == 200
assert failed.json()["state"] == "failed"
assert failed.json()["terminal"] == {
"code": "model-unavailable",
"message": "Sealed model release is not installed.",
}
assert repeated.status_code == 200
assert repeated.json() == failed.json()
@pytest.mark.parametrize(
"bearer_token_sha256,contour_id",
[("not-a-digest", "worker-006"), ("a" * 64, "WORKER 006")],
)
def test_worker_authentication_configuration_is_strict(
bearer_token_sha256: str,
contour_id: str,
) -> None:
with pytest.raises(ValueError):
ObservatoryWorkerAuthentication(
bearer_token_sha256=bearer_token_sha256,
contour_id=contour_id,
)
def test_worker_authentication_loads_private_regular_token_file(
tmp_path: Path,
) -> None:
token_path = tmp_path / "observatory-worker.token"
token_path.write_text(WORKER_TOKEN, encoding="ascii")
token_path.chmod(0o600)
authentication = load_observatory_worker_authentication(token_path)
assert authentication == ObservatoryWorkerAuthentication(
bearer_token_sha256=WORKER_TOKEN_SHA256,
contour_id="worker-006",
)
assert WORKER_TOKEN not in repr(authentication)
def test_worker_authentication_rejects_broad_permissions_and_symlinks(
tmp_path: Path,
) -> None:
token_path = tmp_path / "observatory-worker.token"
token_path.write_text(WORKER_TOKEN, encoding="ascii")
token_path.chmod(0o644)
with pytest.raises(ValueError, match="permissions"):
load_observatory_worker_authentication(token_path)
token_path.chmod(0o600)
link = tmp_path / "linked.token"
link.symlink_to(token_path)
with pytest.raises(ValueError, match="credential"):
load_observatory_worker_authentication(link)
@@ -0,0 +1,59 @@
from __future__ import annotations
from pathlib import Path
from k1link.web import app as app_module
WORKER_ROUTE_PREFIX = "/api/v1/worker/observatory"
def test_worker_router_is_hard_disabled_until_lease_and_publisher_exist() -> None:
assert app_module.OBSERVATORY_RECORDED_JOB_QUEUE is not None
assert app_module.OBSERVATORY_WORKER_CLAIM_LEASE_READY is False
assert app_module.OBSERVATORY_WORKER_VERIFIED_RESULT_PUBLISHER_READY is False
assert app_module.OBSERVATORY_WORKER_PRODUCTION_API_ENABLED is False
assert app_module.OBSERVATORY_WORKER_AUTHENTICATION is None
assert app_module.OBSERVATORY_WORKER_API_ERROR is not None
assert "hard-disabled" in app_module.OBSERVATORY_WORKER_API_ERROR
assert not any(
getattr(route, "path", "").startswith(WORKER_ROUTE_PREFIX)
for route in app_module.app.routes
)
def test_invalid_worker_credential_disables_only_optional_authentication(
tmp_path: Path,
) -> None:
token_path = tmp_path / "observatory-worker.token"
token_path.write_text("worker-006-test-bearer-secret-32bytes", encoding="ascii")
token_path.chmod(0o644)
authentication, error = app_module._load_optional_observatory_worker_authentication(
app_module.OBSERVATORY_RECORDED_JOB_QUEUE,
token_path=token_path,
)
assert authentication is None
assert error is not None and "permissions" in error
def test_valid_worker_credential_cannot_enable_production_router(
tmp_path: Path,
) -> None:
token_path = tmp_path / "observatory-worker.token"
token_path.write_text("worker-006-test-bearer-secret-32bytes", encoding="ascii")
token_path.chmod(0o600)
authentication, error = app_module._load_optional_observatory_worker_authentication(
app_module.OBSERVATORY_RECORDED_JOB_QUEUE,
token_path=token_path,
)
assert authentication is not None
assert error is None
assert app_module.OBSERVATORY_WORKER_PRODUCTION_API_ENABLED is False
assert app_module.OBSERVATORY_WORKER_AUTHENTICATION is None
assert not any(
getattr(route, "path", "").startswith(WORKER_ROUTE_PREFIX)
for route in app_module.app.routes
)