feat(observatory): add portable calculation profiles

This commit is contained in:
DCCONSTRUCTIONS
2026-08-31 15:42:56 +03:00
parent d1b75efcea
commit 9beb534108
75 changed files with 24419 additions and 348 deletions
+82 -1
View File
@@ -9,10 +9,15 @@ import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from k1link.observatory import LaboratorySetupRegistry, LaboratorySetupRegistryError
from k1link.observatory import (
OBSERVATORY_CALCULATION_PROFILE_SCHEMA,
LaboratorySetupRegistry,
LaboratorySetupRegistryError,
)
from k1link.sessions import LabReplayCapability, LabSessionBinding, SessionNotFoundError
from k1link.sessions.models import SessionSummary
from k1link.web.observatory_api import build_observatory_router
from k1link.web.session_api import build_session_router
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
REGISTRY_PATH = REPOSITORY_ROOT / "config" / "observatory-laboratory-setups.json"
@@ -163,6 +168,34 @@ def test_repository_setup_registry_keeps_real_definition_and_pre_definition_resu
assert existing["preflight"]["submission_allowed"] is False
def test_registry_attributes_only_the_exact_admitted_preserved_result() -> None:
registry = _registry()
projection = _rav004_projection()
assert registry.observatory_calculation_profile(projection) == {
"schema_version": OBSERVATORY_CALCULATION_PROFILE_SCHEMA,
"setup_id": "lab-v1-ravnoves004tree-final",
"display_name": "LAB V1 · EoMT Cityscapes Large 1024 + DDRNet-39",
"origin": "existing-result",
"definition_id": None,
"definition_version": None,
"definition_sha256": None,
}
assert registry.observatory_calculation_profile(
replace(
projection,
session_id="lab-v1-vegetation-shadow-" + "0" * 64,
)
) is None
assert projection.lab is not None
assert registry.observatory_calculation_profile(
replace(
projection,
lab=replace(projection.lab, provenance={}),
)
) is None
@pytest.mark.parametrize(
("source", "reason_code"),
[
@@ -238,6 +271,54 @@ class _Store:
raise SessionNotFoundError(session_id) from exc
return SimpleNamespace(summary=summary)
def list_recent(
self,
*,
limit: int,
cursor: str | None,
scope: str,
include_capability_projections: bool = False,
):
del limit, cursor
items = (
(_rav004_projection(),)
if scope == "laboratory" and include_capability_projections
else ()
)
return SimpleNamespace(items=items, next_cursor=None)
def test_session_catalog_v3_projects_the_exact_preserved_profile() -> None:
registry = _registry()
app = FastAPI()
app.include_router(
build_session_router(
_Store(), # type: ignore[arg-type]
lab_calculation_profile_resolver=registry.observatory_calculation_profile,
)
)
client = TestClient(app)
v2_lab = client.get(
"/api/v1/observation-sessions",
params={"scope": "laboratory", "lab_contract": "v2"},
).json()["items"][0]["lab"]
v3_lab = client.get(
"/api/v1/observation-sessions",
params={"scope": "laboratory", "lab_contract": "v3"},
).json()["items"][0]["lab"]
assert "calculation_profile" not in v2_lab
assert v3_lab["calculation_profile"] == {
"schema_version": OBSERVATORY_CALCULATION_PROFILE_SCHEMA,
"setup_id": "lab-v1-ravnoves004tree-final",
"display_name": "LAB V1 · EoMT Cityscapes Large 1024 + DDRNet-39",
"origin": "existing-result",
"definition_id": None,
"definition_version": None,
"definition_sha256": None,
}
def test_observatory_setup_catalog_and_preflight_are_read_only_and_fail_closed() -> None:
app = FastAPI()