refactor(platform): harden LAB evidence and telemetry
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
"""Configuration contracts for Mission Core laboratory evidence."""
|
||||
|
||||
from k1link.laboratory.evidence_registry import (
|
||||
LABORATORY_EVIDENCE_DEFINITION_SCHEMA,
|
||||
LaboratoryEvidenceDefinition,
|
||||
LaboratoryEvidenceRegistry,
|
||||
LaboratoryRegistryError,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"LABORATORY_EVIDENCE_DEFINITION_SCHEMA",
|
||||
"LaboratoryEvidenceDefinition",
|
||||
"LaboratoryEvidenceRegistry",
|
||||
"LaboratoryRegistryError",
|
||||
]
|
||||
@@ -0,0 +1,187 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path, PurePosixPath
|
||||
from typing import Final
|
||||
|
||||
LABORATORY_EVIDENCE_DEFINITION_SCHEMA: Final = "missioncore.laboratory-evidence-definition/v1"
|
||||
_DEFINITION_MAX_BYTES: Final = 16 * 1024
|
||||
_IDENTIFIER = re.compile(r"^[a-z][a-z0-9-]{2,95}$")
|
||||
_SCHEMA_VERSION = re.compile(r"^missioncore\.[a-z0-9.-]+/v[1-9][0-9]*$")
|
||||
_TOP_LEVEL_KEYS: Final = frozenset({"schema_version", "work_id", "evidence"})
|
||||
_EVIDENCE_KEYS: Final = frozenset(
|
||||
{"runtime_relative_root", "result_id_prefix", "document_name", "schema_version"}
|
||||
)
|
||||
|
||||
|
||||
class LaboratoryRegistryError(ValueError):
|
||||
"""Raised when a LAB evidence definition is unsafe or ambiguous."""
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class LaboratoryEvidenceDefinition:
|
||||
work_id: str
|
||||
runtime_relative_root: PurePosixPath
|
||||
result_id_prefix: str
|
||||
document_name: str
|
||||
result_schema_version: str
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
_identifier(self.work_id, "work_id")
|
||||
_identifier(self.result_id_prefix, "result_id_prefix")
|
||||
_document_name(self.document_name)
|
||||
_schema_version(self.result_schema_version)
|
||||
if not isinstance(self.runtime_relative_root, PurePosixPath):
|
||||
raise LaboratoryRegistryError("runtime_relative_root must be a POSIX path")
|
||||
_relative_root(str(self.runtime_relative_root))
|
||||
|
||||
@property
|
||||
def result_id_pattern(self) -> re.Pattern[str]:
|
||||
return re.compile(rf"^{re.escape(self.result_id_prefix)}-[a-f0-9]{{64}}$")
|
||||
|
||||
def result_root(self, runtime_root: Path) -> Path:
|
||||
return runtime_root.joinpath(*self.runtime_relative_root.parts)
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class LaboratoryEvidenceRegistry:
|
||||
definitions: tuple[LaboratoryEvidenceDefinition, ...]
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if not isinstance(self.definitions, tuple) or not all(
|
||||
isinstance(definition, LaboratoryEvidenceDefinition) for definition in self.definitions
|
||||
):
|
||||
raise LaboratoryRegistryError("LAB definitions must be an immutable tuple")
|
||||
_reject_duplicates(self.definitions)
|
||||
|
||||
@classmethod
|
||||
def from_directory(cls, root: Path) -> LaboratoryEvidenceRegistry:
|
||||
definition_root = _real_directory(root, "LAB definition root")
|
||||
definitions = tuple(
|
||||
_read_definition(path)
|
||||
for path in sorted(definition_root.glob("*.json"), key=lambda item: item.name)
|
||||
)
|
||||
return cls(definitions=definitions)
|
||||
|
||||
|
||||
def _real_directory(path: Path, label: str) -> Path:
|
||||
candidate = path.expanduser().absolute()
|
||||
if candidate.is_symlink():
|
||||
raise LaboratoryRegistryError(f"{label} must not be a symlink")
|
||||
try:
|
||||
resolved = candidate.resolve(strict=True)
|
||||
except OSError as exc:
|
||||
raise LaboratoryRegistryError(f"{label} does not exist") from exc
|
||||
if not resolved.is_dir():
|
||||
raise LaboratoryRegistryError(f"{label} must be a directory")
|
||||
return resolved
|
||||
|
||||
|
||||
def _read_definition(path: Path) -> LaboratoryEvidenceDefinition:
|
||||
if path.is_symlink() or not path.is_file():
|
||||
raise LaboratoryRegistryError(f"LAB definition must be a regular file: {path.name}")
|
||||
if path.stat().st_size > _DEFINITION_MAX_BYTES:
|
||||
raise LaboratoryRegistryError(f"LAB definition is too large: {path.name}")
|
||||
try:
|
||||
payload: object = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (json.JSONDecodeError, OSError) as exc:
|
||||
raise LaboratoryRegistryError(f"LAB definition is unreadable: {path.name}") from exc
|
||||
document = _object(payload, f"LAB definition {path.name}")
|
||||
_exact_keys(document, _TOP_LEVEL_KEYS, f"LAB definition {path.name}")
|
||||
if document["schema_version"] != LABORATORY_EVIDENCE_DEFINITION_SCHEMA:
|
||||
raise LaboratoryRegistryError(f"LAB definition schema is invalid: {path.name}")
|
||||
work_id = _identifier(document["work_id"], "work_id")
|
||||
if path.name != f"{work_id}.json":
|
||||
raise LaboratoryRegistryError(f"LAB definition filename must match work_id: {path.name}")
|
||||
evidence = _object(document["evidence"], f"LAB evidence {work_id}")
|
||||
_exact_keys(evidence, _EVIDENCE_KEYS, f"LAB evidence {work_id}")
|
||||
result_id_prefix = _identifier(evidence["result_id_prefix"], "result_id_prefix")
|
||||
document_name = _document_name(evidence["document_name"])
|
||||
result_schema_version = _schema_version(evidence["schema_version"])
|
||||
return LaboratoryEvidenceDefinition(
|
||||
work_id=work_id,
|
||||
runtime_relative_root=_relative_root(evidence["runtime_relative_root"]),
|
||||
result_id_prefix=result_id_prefix,
|
||||
document_name=document_name,
|
||||
result_schema_version=result_schema_version,
|
||||
)
|
||||
|
||||
|
||||
def _object(value: object, label: str) -> dict[str, object]:
|
||||
if not isinstance(value, dict) or not all(isinstance(key, str) for key in value):
|
||||
raise LaboratoryRegistryError(f"{label} must be an object")
|
||||
return value
|
||||
|
||||
|
||||
def _exact_keys(document: dict[str, object], expected: frozenset[str], label: str) -> None:
|
||||
actual = frozenset(document)
|
||||
if actual != expected:
|
||||
missing = sorted(expected - actual)
|
||||
unexpected = sorted(actual - expected)
|
||||
raise LaboratoryRegistryError(
|
||||
f"{label} keys are invalid; missing={missing}, unexpected={unexpected}"
|
||||
)
|
||||
|
||||
|
||||
def _text(value: object, label: str) -> str:
|
||||
if not isinstance(value, str) or not value.strip() or value != value.strip():
|
||||
raise LaboratoryRegistryError(f"{label} must be a non-empty trimmed string")
|
||||
return value
|
||||
|
||||
|
||||
def _identifier(value: object, label: str) -> str:
|
||||
text = _text(value, label)
|
||||
if _IDENTIFIER.fullmatch(text) is None:
|
||||
raise LaboratoryRegistryError(f"{label} is invalid")
|
||||
return text
|
||||
|
||||
|
||||
def _schema_version(value: object) -> str:
|
||||
text = _text(value, "evidence schema_version")
|
||||
if _SCHEMA_VERSION.fullmatch(text) is None:
|
||||
raise LaboratoryRegistryError("evidence schema_version is invalid")
|
||||
return text
|
||||
|
||||
|
||||
def _document_name(value: object) -> str:
|
||||
text = _text(value, "document_name")
|
||||
candidate = PurePosixPath(text)
|
||||
if (
|
||||
candidate.is_absolute()
|
||||
or len(candidate.parts) != 1
|
||||
or candidate.name != text
|
||||
or candidate.suffix != ".json"
|
||||
):
|
||||
raise LaboratoryRegistryError("document_name must be one JSON filename")
|
||||
return text
|
||||
|
||||
|
||||
def _relative_root(value: object) -> PurePosixPath:
|
||||
text = _text(value, "runtime_relative_root")
|
||||
if "\\" in text:
|
||||
raise LaboratoryRegistryError("runtime_relative_root must use POSIX separators")
|
||||
candidate = PurePosixPath(text)
|
||||
if (
|
||||
candidate.is_absolute()
|
||||
or not candidate.parts
|
||||
or text == "."
|
||||
or str(candidate) != text
|
||||
or any(part in {"", ".", ".."} for part in candidate.parts)
|
||||
):
|
||||
raise LaboratoryRegistryError("runtime_relative_root must be a normalized relative path")
|
||||
return candidate
|
||||
|
||||
|
||||
def _reject_duplicates(definitions: tuple[LaboratoryEvidenceDefinition, ...]) -> None:
|
||||
dimensions = {
|
||||
"work_id": [definition.work_id for definition in definitions],
|
||||
"result_id_prefix": [definition.result_id_prefix for definition in definitions],
|
||||
"runtime_relative_root": [
|
||||
str(definition.runtime_relative_root) for definition in definitions
|
||||
],
|
||||
}
|
||||
for label, values in dimensions.items():
|
||||
if len(values) != len(set(values)):
|
||||
raise LaboratoryRegistryError(f"duplicate LAB {label}")
|
||||
@@ -55,6 +55,7 @@ from k1link.compute.e40_perception_product_gate import (
|
||||
E40PerceptionProductGateError,
|
||||
read_e40_perception_product_gate,
|
||||
)
|
||||
from k1link.laboratory import LaboratoryEvidenceDefinition, LaboratoryEvidenceRegistry
|
||||
from k1link.web.l3_pointpillars_visual_api import latest_l3_visual_identity
|
||||
from k1link.web.l32_pointpillars_camera_review_api import latest_l32_identity
|
||||
from k1link.web.l33_camera_first_detector_review_api import latest_l33_identity
|
||||
@@ -72,24 +73,6 @@ _E37_RESULT_ID = re.compile(r"^e37-ravnoves-acceptance-[a-f0-9]{64}$")
|
||||
_E38_RESULT_ID = re.compile(r"^e38-perception-baseline-[a-f0-9]{64}$")
|
||||
_E39_RESULT_ID = re.compile(r"^e39-perception-refinement-[a-f0-9]{64}$")
|
||||
_E40_RESULT_ID = re.compile(r"^e40-perception-product-gate-[a-f0-9]{64}$")
|
||||
_E46_RESULT_ID = re.compile(r"^e46-detector-truth-island-[a-f0-9]{64}$")
|
||||
_E46A_RESULT_ID = re.compile(r"^e46a-ai-engineering-preannotation-[a-f0-9]{64}$")
|
||||
_E46B_RESULT_ID = re.compile(r"^e46b-temporal-motion-[a-f0-9]{64}$")
|
||||
_E46C_RESULT_ID = re.compile(r"^e46c-full-replay-world-tracks-[a-f0-9]{64}$")
|
||||
_E46D_RESULT_ID = re.compile(r"^e46d-temporal-failure-audit-[a-f0-9]{64}$")
|
||||
_E46E_RESULT_ID = re.compile(r"^e46e-ready-stack-[a-f0-9]{64}$")
|
||||
_E46F_RESULT_ID = re.compile(r"^e46f-dashcam-bakeoff-[a-f0-9]{64}$")
|
||||
_E46G_RESULT_ID = re.compile(r"^e46g-rectified-detector-bakeoff-[a-f0-9]{64}$")
|
||||
_E46H_RESULT_ID = re.compile(r"^e46h-full-rectified-front-replay-[a-f0-9]{64}$")
|
||||
_E46I_RESULT_ID = re.compile(r"^e46i-grounding-dino-full-replay-[a-f0-9]{64}$")
|
||||
_E46J_RESULT_ID = re.compile(r"^e46j-raw-fisheye-realtime-[a-f0-9]{64}$")
|
||||
_L34_RESULT_ID = re.compile(r"^l34-right-yolox-truth-island-freeze-[a-f0-9]{64}$")
|
||||
_L34A_RESULT_ID = re.compile(r"^l34a-assisted-yolox-error-audit-[a-f0-9]{64}$")
|
||||
_L34B_RESULT_ID = re.compile(r"^l34b-nested-box-consolidation-shadow-[a-f0-9]{64}$")
|
||||
_L34C_RESULT_ID = re.compile(r"^l34c-tile-seam-stitch-shadow-[a-f0-9]{64}$")
|
||||
_L34D_RESULT_ID = re.compile(r"^l34d-cumulative-postprocessing-candidate-[a-f0-9]{64}$")
|
||||
_L34E_RESULT_ID = re.compile(r"^l34e-self-review-diagnostic-[a-f0-9]{64}$")
|
||||
_L34F_RESULT_ID = re.compile(r"^l34f-adjudicated-reference-[a-f0-9]{64}$")
|
||||
|
||||
RootProvider = Callable[[], Path | None]
|
||||
|
||||
@@ -299,6 +282,50 @@ def _advanced_index(
|
||||
}
|
||||
|
||||
|
||||
def _registry_index_specs(
|
||||
registry: LaboratoryEvidenceRegistry,
|
||||
runtime_root_provider: RootProvider,
|
||||
) -> tuple[_AdvancedIndexSpec, ...]:
|
||||
return tuple(
|
||||
(
|
||||
definition.work_id,
|
||||
_evidence_root_provider(definition, runtime_root_provider),
|
||||
definition.result_id_pattern,
|
||||
definition.document_name,
|
||||
definition.result_schema_version,
|
||||
)
|
||||
for definition in registry.definitions
|
||||
)
|
||||
|
||||
|
||||
def _evidence_root_provider(
|
||||
definition: LaboratoryEvidenceDefinition,
|
||||
runtime_root_provider: RootProvider,
|
||||
) -> RootProvider:
|
||||
def result_root_provider() -> Path | None:
|
||||
configured_runtime_root = runtime_root_provider()
|
||||
if configured_runtime_root is None:
|
||||
return None
|
||||
runtime_candidate = configured_runtime_root.expanduser().absolute()
|
||||
if runtime_candidate.is_symlink():
|
||||
return None
|
||||
try:
|
||||
runtime_root = runtime_candidate.resolve(strict=True)
|
||||
except OSError:
|
||||
return None
|
||||
candidate = definition.result_root(runtime_root)
|
||||
if candidate.exists():
|
||||
try:
|
||||
resolved = candidate.resolve(strict=True)
|
||||
except OSError:
|
||||
return None
|
||||
if resolved != candidate.absolute() or not resolved.is_relative_to(runtime_root):
|
||||
return None
|
||||
return candidate
|
||||
|
||||
return result_root_provider
|
||||
|
||||
|
||||
def _object(value: object, label: str) -> dict[str, Any]:
|
||||
if not isinstance(value, dict):
|
||||
raise ValueError(f"{label} is invalid")
|
||||
@@ -786,6 +813,8 @@ def _empty_catalog(configured: bool) -> dict[str, object]:
|
||||
|
||||
def build_advanced_laboratory_router(
|
||||
*,
|
||||
evidence_registry: LaboratoryEvidenceRegistry | None = None,
|
||||
evidence_runtime_root_provider: RootProvider = lambda: None,
|
||||
e31_root_provider: RootProvider = lambda: None,
|
||||
e32_root_provider: RootProvider = lambda: None,
|
||||
e33_root_provider: RootProvider = lambda: None,
|
||||
@@ -795,24 +824,6 @@ def build_advanced_laboratory_router(
|
||||
e38_root_provider: RootProvider = lambda: None,
|
||||
e39_root_provider: RootProvider = lambda: None,
|
||||
e40_root_provider: RootProvider = lambda: None,
|
||||
e46_root_provider: RootProvider = lambda: None,
|
||||
e46a_root_provider: RootProvider = lambda: None,
|
||||
e46b_root_provider: RootProvider = lambda: None,
|
||||
e46c_root_provider: RootProvider = lambda: None,
|
||||
e46d_root_provider: RootProvider = lambda: None,
|
||||
e46e_root_provider: RootProvider = lambda: None,
|
||||
e46f_root_provider: RootProvider = lambda: None,
|
||||
e46g_root_provider: RootProvider = lambda: None,
|
||||
e46h_root_provider: RootProvider = lambda: None,
|
||||
e46i_root_provider: RootProvider = lambda: None,
|
||||
e46j_root_provider: RootProvider = lambda: None,
|
||||
l34_root_provider: RootProvider = lambda: None,
|
||||
l34a_root_provider: RootProvider = lambda: None,
|
||||
l34b_root_provider: RootProvider = lambda: None,
|
||||
l34c_root_provider: RootProvider = lambda: None,
|
||||
l34d_root_provider: RootProvider = lambda: None,
|
||||
l34e_root_provider: RootProvider = lambda: None,
|
||||
l34f_root_provider: RootProvider = lambda: None,
|
||||
l3_visual_root_provider: RootProvider = lambda: None,
|
||||
l31_ravnoves_root_provider: RootProvider = lambda: None,
|
||||
l32_camera_review_root_provider: RootProvider = lambda: None,
|
||||
@@ -822,8 +833,8 @@ def build_advanced_laboratory_router(
|
||||
|
||||
@router.get("/advanced-index")
|
||||
def list_advanced_results() -> dict[str, object]:
|
||||
result = _advanced_index(
|
||||
(
|
||||
if evidence_registry is None:
|
||||
specs: tuple[_AdvancedIndexSpec, ...] = (
|
||||
(
|
||||
"e31-source-binding",
|
||||
e31_root_provider,
|
||||
@@ -887,134 +898,13 @@ def build_advanced_laboratory_router(
|
||||
"manifest.json",
|
||||
"missioncore.e40-perception-product-gate/v1",
|
||||
),
|
||||
(
|
||||
"e46-detector-truth-island",
|
||||
e46_root_provider,
|
||||
_E46_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46-detector-truth-island/v1",
|
||||
),
|
||||
(
|
||||
"e46a-ai-engineering-preannotation",
|
||||
e46a_root_provider,
|
||||
_E46A_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46a-ai-engineering-preannotation/v1",
|
||||
),
|
||||
(
|
||||
"e46b-temporal-motion",
|
||||
e46b_root_provider,
|
||||
_E46B_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46b-temporal-motion/v1",
|
||||
),
|
||||
(
|
||||
"e46c-full-replay-world-tracks",
|
||||
e46c_root_provider,
|
||||
_E46C_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46c-full-replay-world-tracks/v1",
|
||||
),
|
||||
(
|
||||
"e46d-temporal-failure-audit",
|
||||
e46d_root_provider,
|
||||
_E46D_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46d-temporal-failure-audit/v1",
|
||||
),
|
||||
(
|
||||
"e46e-ready-stack",
|
||||
e46e_root_provider,
|
||||
_E46E_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46e-ready-stack-result/v1",
|
||||
),
|
||||
(
|
||||
"e46f-dashcam-bakeoff",
|
||||
e46f_root_provider,
|
||||
_E46F_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46f-dashcam-bakeoff-result/v1",
|
||||
),
|
||||
(
|
||||
"e46g-rectified-detector-bakeoff",
|
||||
e46g_root_provider,
|
||||
_E46G_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46g-rectified-detector-bakeoff-result/v1",
|
||||
),
|
||||
(
|
||||
"e46h-full-rectified-front-replay",
|
||||
e46h_root_provider,
|
||||
_E46H_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46h-full-rectified-front-replay-result/v1",
|
||||
),
|
||||
(
|
||||
"e46i-grounding-dino-full-replay",
|
||||
e46i_root_provider,
|
||||
_E46I_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46i-grounding-dino-full-replay-result/v1",
|
||||
),
|
||||
(
|
||||
"e46j-raw-fisheye-realtime",
|
||||
e46j_root_provider,
|
||||
_E46J_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.e46j-raw-fisheye-realtime-result/v1",
|
||||
),
|
||||
(
|
||||
"l34-right-yolox-truth-island-freeze",
|
||||
l34_root_provider,
|
||||
_L34_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.l34-right-yolox-truth-island-freeze/v1",
|
||||
),
|
||||
(
|
||||
"l34a-assisted-yolox-error-audit",
|
||||
l34a_root_provider,
|
||||
_L34A_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.l34a-assisted-yolox-error-audit/v1",
|
||||
),
|
||||
(
|
||||
"l34b-nested-box-consolidation-shadow",
|
||||
l34b_root_provider,
|
||||
_L34B_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.l34b-nested-box-consolidation-shadow/v1",
|
||||
),
|
||||
(
|
||||
"l34c-tile-seam-stitch-shadow",
|
||||
l34c_root_provider,
|
||||
_L34C_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.l34c-tile-seam-stitch-shadow/v1",
|
||||
),
|
||||
(
|
||||
"l34d-cumulative-postprocessing-candidate",
|
||||
l34d_root_provider,
|
||||
_L34D_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.l34d-cumulative-postprocessing-candidate/v1",
|
||||
),
|
||||
(
|
||||
"l34e-self-review-diagnostic",
|
||||
l34e_root_provider,
|
||||
_L34E_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.l34e-self-review-diagnostic/v1",
|
||||
),
|
||||
(
|
||||
"l34f-adjudicated-reference",
|
||||
l34f_root_provider,
|
||||
_L34F_RESULT_ID,
|
||||
"manifest.json",
|
||||
"missioncore.l34f-adjudicated-reference/v1",
|
||||
),
|
||||
)
|
||||
)
|
||||
else:
|
||||
specs = _registry_index_specs(
|
||||
evidence_registry,
|
||||
evidence_runtime_root_provider,
|
||||
)
|
||||
result = _advanced_index(specs)
|
||||
items = result["items"]
|
||||
if not isinstance(items, list):
|
||||
raise RuntimeError("advanced LAB index items are invalid")
|
||||
|
||||
+8
-90
@@ -23,6 +23,7 @@ from k1link.compute import (
|
||||
RecordedPerceptionOverlayMux,
|
||||
RecordedPerceptionOverlayStore,
|
||||
)
|
||||
from k1link.laboratory import LaboratoryEvidenceRegistry
|
||||
from k1link.sessions import (
|
||||
MaterializedRecording,
|
||||
RecordedMediaInspector,
|
||||
@@ -133,6 +134,9 @@ from k1link.web.viewer_diagnostics_api import build_viewer_diagnostics_router
|
||||
|
||||
REPOSITORY_ROOT = Path(__file__).resolve().parents[3]
|
||||
INVALID_REQUEST_DETAIL = "Некорректные параметры запроса."
|
||||
LABORATORY_EVIDENCE_REGISTRY = LaboratoryEvidenceRegistry.from_directory(
|
||||
REPOSITORY_ROOT / "config" / "laboratories"
|
||||
)
|
||||
|
||||
|
||||
def _resolve_media_tool(name: str) -> Path | None:
|
||||
@@ -557,6 +561,10 @@ app.include_router(
|
||||
)
|
||||
app.include_router(
|
||||
build_advanced_laboratory_router(
|
||||
evidence_registry=LABORATORY_EVIDENCE_REGISTRY,
|
||||
evidence_runtime_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments"
|
||||
),
|
||||
e31_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "e31" / "source-qualifications"
|
||||
),
|
||||
@@ -584,96 +592,6 @@ app.include_router(
|
||||
e40_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "e40" / "results"
|
||||
),
|
||||
e46_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "e46" / "results"
|
||||
),
|
||||
e46a_root_provider=lambda: (
|
||||
REPOSITORY_ROOT
|
||||
/ ".runtime"
|
||||
/ "compute-experiments"
|
||||
/ "e46a"
|
||||
/ "ai-engineering-preannotations"
|
||||
),
|
||||
e46b_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "e46b" / "temporal-motion"
|
||||
),
|
||||
e46c_root_provider=lambda: (
|
||||
REPOSITORY_ROOT
|
||||
/ ".runtime"
|
||||
/ "compute-experiments"
|
||||
/ "e46c"
|
||||
/ "full-replay-world-tracks"
|
||||
),
|
||||
e46d_root_provider=lambda: (
|
||||
REPOSITORY_ROOT
|
||||
/ ".runtime"
|
||||
/ "compute-experiments"
|
||||
/ "e46d"
|
||||
/ "temporal-failure-audits"
|
||||
),
|
||||
e46e_root_provider=lambda: (
|
||||
REPOSITORY_ROOT
|
||||
/ ".runtime"
|
||||
/ "compute-experiments"
|
||||
/ "e46e"
|
||||
/ "ready-stack-results"
|
||||
),
|
||||
e46f_root_provider=lambda: (
|
||||
REPOSITORY_ROOT
|
||||
/ ".runtime"
|
||||
/ "compute-experiments"
|
||||
/ "e46f"
|
||||
/ "dashcam-bakeoff-results"
|
||||
),
|
||||
e46g_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "e46g" / "results"
|
||||
),
|
||||
e46h_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "e46h" / "results"
|
||||
),
|
||||
e46i_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "e46i" / "results"
|
||||
),
|
||||
e46j_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "e46j" / "results"
|
||||
),
|
||||
l34_root_provider=lambda: (
|
||||
REPOSITORY_ROOT
|
||||
/ ".runtime"
|
||||
/ "compute-experiments"
|
||||
/ "l3"
|
||||
/ "right-yolox-truth-island-freeze"
|
||||
),
|
||||
l34a_root_provider=lambda: (
|
||||
REPOSITORY_ROOT
|
||||
/ ".runtime"
|
||||
/ "compute-experiments"
|
||||
/ "l3"
|
||||
/ "assisted-yolox-error-audits"
|
||||
),
|
||||
l34b_root_provider=lambda: (
|
||||
REPOSITORY_ROOT
|
||||
/ ".runtime"
|
||||
/ "compute-experiments"
|
||||
/ "l3"
|
||||
/ "nested-box-consolidation-shadows"
|
||||
),
|
||||
l34c_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "l3" / "tile-seam-stitch-shadows"
|
||||
),
|
||||
l34d_root_provider=lambda: (
|
||||
REPOSITORY_ROOT
|
||||
/ ".runtime"
|
||||
/ "compute-experiments"
|
||||
/ "l3"
|
||||
/ "cumulative-postprocessing-candidates"
|
||||
),
|
||||
l34e_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "l3" / "self-review-diagnostics"
|
||||
),
|
||||
l34f_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "l3" / "adjudicated-references"
|
||||
),
|
||||
l3_visual_root_provider=lambda: (
|
||||
REPOSITORY_ROOT / ".runtime" / "compute-experiments" / "l3" / "visual-audits"
|
||||
),
|
||||
|
||||
@@ -313,6 +313,15 @@ elseif ((Get-Service -Name "telegraf").Status -ne "Running") {
|
||||
[TimeSpan]::FromSeconds(20)
|
||||
)
|
||||
}
|
||||
& sc.exe failure telegraf reset= 86400 `
|
||||
actions= restart/5000/restart/30000/restart/60000 | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to configure Telegraf service recovery actions"
|
||||
}
|
||||
& sc.exe failureflag telegraf 1 | Out-Null
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Failed to enable Telegraf recovery for non-crash failures"
|
||||
}
|
||||
$resolved = @(
|
||||
[Net.Dns]::GetHostAddresses([string]$payload.mqtt_host) |
|
||||
ForEach-Object { $_.IPAddressToString } |
|
||||
@@ -326,6 +335,7 @@ $resolved = @(
|
||||
mqtt_port = [int]$payload.mqtt_port
|
||||
resolved_addresses = $resolved
|
||||
broker_reachable = $true
|
||||
recovery_configured = $true
|
||||
changed = $changed
|
||||
} | ConvertTo-Json -Depth 5 -Compress
|
||||
""".strip()
|
||||
@@ -587,6 +597,7 @@ def apply_worker_network(
|
||||
or document.get("mqtt_port") != target.mqtt_port
|
||||
or document.get("service_status") != "Running"
|
||||
or document.get("broker_reachable") is not True
|
||||
or document.get("recovery_configured") is not True
|
||||
):
|
||||
raise NetworkOperationError(
|
||||
"Worker не подтвердил применённый сетевой профиль."
|
||||
|
||||
Reference in New Issue
Block a user