bind M4.7 graph results to Worker runtime
This commit is contained in:
@@ -357,6 +357,7 @@ $graphArguments += @(
|
|||||||
"--triton-origin", $descriptor.container.triton_origin,
|
"--triton-origin", $descriptor.container.triton_origin,
|
||||||
"--mode", $descriptor.acceptance.run_mode,
|
"--mode", $descriptor.acceptance.run_mode,
|
||||||
"--expected-frames", ([string]$descriptor.acceptance.expected_frames),
|
"--expected-frames", ([string]$descriptor.acceptance.expected_frames),
|
||||||
|
"--runtime-identity", "/run/mission-core/runtime-identity.json",
|
||||||
"--output-root", "/output"
|
"--output-root", "/output"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -416,7 +417,7 @@ try {
|
|||||||
throw "M4.7 graph candidate isolation contract changed"
|
throw "M4.7 graph candidate isolation contract changed"
|
||||||
}
|
}
|
||||||
$runtimeIdentity = [ordered]@{
|
$runtimeIdentity = [ordered]@{
|
||||||
schema_version = "missioncore.reference-graph-runtime-identity/v2"
|
schema_version = "missioncore.reference-graph-runtime-identity/v3"
|
||||||
worker_id = "worker-006"
|
worker_id = "worker-006"
|
||||||
worker_node = $env:COMPUTERNAME
|
worker_node = $env:COMPUTERNAME
|
||||||
worker_container_id = $candidate.Id
|
worker_container_id = $candidate.Id
|
||||||
@@ -428,8 +429,10 @@ try {
|
|||||||
historical_triton_container_id = $historicalTritonBefore.Id
|
historical_triton_container_id = $historicalTritonBefore.Id
|
||||||
historical_triton_running = $historicalTritonBefore.Running
|
historical_triton_running = $historicalTritonBefore.Running
|
||||||
artifact_sha256 = $ExpectedArtifactSha256
|
artifact_sha256 = $ExpectedArtifactSha256
|
||||||
|
patch_id = $descriptor.patch_id
|
||||||
code_revision = $descriptor.code_revision
|
code_revision = $descriptor.code_revision
|
||||||
graph_id = $descriptor.readiness.graph.graph_id
|
graph_id = $descriptor.readiness.graph.graph_id
|
||||||
|
started_at_utc = [DateTime]::UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
|
||||||
source_mount_read_only = $true
|
source_mount_read_only = $true
|
||||||
isolated_model_service = $true
|
isolated_model_service = $true
|
||||||
public_worker_port_added = $false
|
public_worker_port_added = $false
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import time
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from .graph_contracts import GraphRunMode, GraphRunResultV2
|
from .graph_contracts import GraphRunMode, GraphRunResultV2
|
||||||
|
from .reference_graph_identity import ReferenceGraphRuntimeIdentity
|
||||||
from .reference_graph_parity import compare_reference_graph_to_accepted_ledgers
|
from .reference_graph_parity import compare_reference_graph_to_accepted_ledgers
|
||||||
from .reference_graph_result import seal_reference_graph_result
|
from .reference_graph_result import seal_reference_graph_result
|
||||||
from .reference_graph_runtime import ReferenceGraphRuntimePaths, build_reference_graph_runtime
|
from .reference_graph_runtime import ReferenceGraphRuntimePaths, build_reference_graph_runtime
|
||||||
@@ -35,8 +36,12 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
default=GraphRunMode.LOSSLESS_REPLAY.value,
|
default=GraphRunMode.LOSSLESS_REPLAY.value,
|
||||||
)
|
)
|
||||||
parser.add_argument("--expected-frames", type=int, default=4489)
|
parser.add_argument("--expected-frames", type=int, default=4489)
|
||||||
|
parser.add_argument("--runtime-identity", type=Path, required=True)
|
||||||
parser.add_argument("--output-root", type=Path, required=True)
|
parser.add_argument("--output-root", type=Path, required=True)
|
||||||
args = parser.parse_args(argv)
|
args = parser.parse_args(argv)
|
||||||
|
runtime_identity = ReferenceGraphRuntimeIdentity.from_dict(
|
||||||
|
json.loads(args.runtime_identity.resolve(strict=True).read_text("utf-8"))
|
||||||
|
)
|
||||||
paths = ReferenceGraphRuntimePaths(
|
paths = ReferenceGraphRuntimePaths(
|
||||||
graph_config=args.graph_config,
|
graph_config=args.graph_config,
|
||||||
baseline_profile=args.baseline_profile,
|
baseline_profile=args.baseline_profile,
|
||||||
@@ -65,17 +70,20 @@ def main(argv: list[str] | None = None) -> int:
|
|||||||
threat_frames_path=args.threat_parity_frames,
|
threat_frames_path=args.threat_parity_frames,
|
||||||
expected_frames=args.expected_frames,
|
expected_frames=args.expected_frames,
|
||||||
)
|
)
|
||||||
|
execution_elapsed_seconds = (time.perf_counter_ns() - started_ns) / 1_000_000_000
|
||||||
sealed = seal_reference_graph_result(
|
sealed = seal_reference_graph_result(
|
||||||
graph_result,
|
graph_result,
|
||||||
output_root=args.output_root,
|
output_root=args.output_root,
|
||||||
expected_frames=args.expected_frames,
|
expected_frames=args.expected_frames,
|
||||||
parity=parity,
|
parity=parity,
|
||||||
|
runtime_identity=runtime_identity,
|
||||||
|
execution_elapsed_seconds=execution_elapsed_seconds,
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
json.dumps(
|
json.dumps(
|
||||||
{
|
{
|
||||||
"accepted": sealed.accepted,
|
"accepted": sealed.accepted,
|
||||||
"elapsed_seconds": (time.perf_counter_ns() - started_ns) / 1_000_000_000,
|
"elapsed_seconds": execution_elapsed_seconds,
|
||||||
"result_id": sealed.result_id,
|
"result_id": sealed.result_id,
|
||||||
"result_root": str(sealed.result_root),
|
"result_root": str(sealed.result_root),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,185 @@
|
|||||||
|
"""Strict execution identity for the isolated M4.7 reference graph shadow."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import datetime as dt
|
||||||
|
import re
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Final
|
||||||
|
|
||||||
|
from .graph_contracts import REFERENCE_GRAPH_ID_V2
|
||||||
|
|
||||||
|
REFERENCE_GRAPH_RUNTIME_IDENTITY_SCHEMA: Final = "missioncore.reference-graph-runtime-identity/v3"
|
||||||
|
|
||||||
|
_SHA256 = re.compile(r"^[a-f0-9]{64}$")
|
||||||
|
_GIT_REVISION = re.compile(r"^[a-f0-9]{40}$")
|
||||||
|
_DOCKER_IMAGE_ID = re.compile(r"^sha256:[a-f0-9]{64}$")
|
||||||
|
_IDENTIFIER = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:/-]{0,255}$")
|
||||||
|
|
||||||
|
|
||||||
|
class ReferenceGraphRuntimeIdentityError(ValueError):
|
||||||
|
"""The Worker execution identity is incomplete or exceeds shadow authority."""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class ReferenceGraphRuntimeIdentity:
|
||||||
|
worker_id: str
|
||||||
|
worker_node: str
|
||||||
|
worker_container_id: str
|
||||||
|
worker_image_id: str
|
||||||
|
isolated_triton_container_id: str
|
||||||
|
isolated_triton_image_id: str
|
||||||
|
historical_worker_container_id: str
|
||||||
|
historical_worker_running: bool
|
||||||
|
historical_triton_container_id: str
|
||||||
|
historical_triton_running: bool
|
||||||
|
artifact_sha256: str
|
||||||
|
patch_id: str
|
||||||
|
code_revision: str
|
||||||
|
graph_id: str
|
||||||
|
started_at_utc: str
|
||||||
|
source_mount_read_only: bool
|
||||||
|
isolated_model_service: bool
|
||||||
|
public_worker_port_added: bool
|
||||||
|
commands_enabled: bool
|
||||||
|
actuation_allowed: bool
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
if self.worker_id != "worker-006":
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("M4.7 shadow must run on Worker 006")
|
||||||
|
_identifier(self.worker_node, "worker node")
|
||||||
|
_identifier(self.patch_id, "patch id")
|
||||||
|
for value, label in (
|
||||||
|
(self.worker_container_id, "worker container id"),
|
||||||
|
(self.isolated_triton_container_id, "isolated Triton container id"),
|
||||||
|
(self.historical_worker_container_id, "historical worker container id"),
|
||||||
|
(self.historical_triton_container_id, "historical Triton container id"),
|
||||||
|
):
|
||||||
|
if _SHA256.fullmatch(value) is None:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError(f"{label} must be a full digest")
|
||||||
|
for value, label in (
|
||||||
|
(self.worker_image_id, "worker image id"),
|
||||||
|
(self.isolated_triton_image_id, "isolated Triton image id"),
|
||||||
|
):
|
||||||
|
if _DOCKER_IMAGE_ID.fullmatch(value) is None:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError(f"{label} must be a full image digest")
|
||||||
|
if _SHA256.fullmatch(self.artifact_sha256) is None:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("artifact must be digest-bound")
|
||||||
|
if _GIT_REVISION.fullmatch(self.code_revision) is None:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("code revision must be a full Git SHA")
|
||||||
|
if self.graph_id != REFERENCE_GRAPH_ID_V2:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("runtime graph id changed")
|
||||||
|
try:
|
||||||
|
started = dt.datetime.fromisoformat(self.started_at_utc.replace("Z", "+00:00"))
|
||||||
|
except ValueError as error:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError(
|
||||||
|
"runtime start must be an ISO-8601 UTC timestamp"
|
||||||
|
) from error
|
||||||
|
if started.tzinfo != dt.UTC:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("runtime start must use UTC")
|
||||||
|
if not self.source_mount_read_only:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("source mounts must be read-only")
|
||||||
|
if not self.isolated_model_service:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("model service must be isolated")
|
||||||
|
if self.public_worker_port_added:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("shadow must not add a public port")
|
||||||
|
if self.commands_enabled or self.actuation_allowed:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("shadow authority must remain disabled")
|
||||||
|
|
||||||
|
def to_dict(self) -> dict[str, object]:
|
||||||
|
return {
|
||||||
|
"schema_version": REFERENCE_GRAPH_RUNTIME_IDENTITY_SCHEMA,
|
||||||
|
"worker_id": self.worker_id,
|
||||||
|
"worker_node": self.worker_node,
|
||||||
|
"worker_container_id": self.worker_container_id,
|
||||||
|
"worker_image_id": self.worker_image_id,
|
||||||
|
"isolated_triton_container_id": self.isolated_triton_container_id,
|
||||||
|
"isolated_triton_image_id": self.isolated_triton_image_id,
|
||||||
|
"historical_worker_container_id": self.historical_worker_container_id,
|
||||||
|
"historical_worker_running": self.historical_worker_running,
|
||||||
|
"historical_triton_container_id": self.historical_triton_container_id,
|
||||||
|
"historical_triton_running": self.historical_triton_running,
|
||||||
|
"artifact_sha256": self.artifact_sha256,
|
||||||
|
"patch_id": self.patch_id,
|
||||||
|
"code_revision": self.code_revision,
|
||||||
|
"graph_id": self.graph_id,
|
||||||
|
"started_at_utc": self.started_at_utc,
|
||||||
|
"source_mount_read_only": self.source_mount_read_only,
|
||||||
|
"isolated_model_service": self.isolated_model_service,
|
||||||
|
"public_worker_port_added": self.public_worker_port_added,
|
||||||
|
"commands_enabled": self.commands_enabled,
|
||||||
|
"actuation_allowed": self.actuation_allowed,
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, value: object) -> ReferenceGraphRuntimeIdentity:
|
||||||
|
if not isinstance(value, dict) or any(not isinstance(key, str) for key in value):
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("runtime identity must be an object")
|
||||||
|
fields = {
|
||||||
|
"worker_id",
|
||||||
|
"worker_node",
|
||||||
|
"worker_container_id",
|
||||||
|
"worker_image_id",
|
||||||
|
"isolated_triton_container_id",
|
||||||
|
"isolated_triton_image_id",
|
||||||
|
"historical_worker_container_id",
|
||||||
|
"historical_worker_running",
|
||||||
|
"historical_triton_container_id",
|
||||||
|
"historical_triton_running",
|
||||||
|
"artifact_sha256",
|
||||||
|
"patch_id",
|
||||||
|
"code_revision",
|
||||||
|
"graph_id",
|
||||||
|
"started_at_utc",
|
||||||
|
"source_mount_read_only",
|
||||||
|
"isolated_model_service",
|
||||||
|
"public_worker_port_added",
|
||||||
|
"commands_enabled",
|
||||||
|
"actuation_allowed",
|
||||||
|
}
|
||||||
|
if set(value) != fields | {"schema_version"}:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("runtime identity fields changed")
|
||||||
|
if value.get("schema_version") != REFERENCE_GRAPH_RUNTIME_IDENTITY_SCHEMA:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError("runtime identity schema changed")
|
||||||
|
strings = {
|
||||||
|
field: _string(value.get(field), field)
|
||||||
|
for field in fields
|
||||||
|
if field
|
||||||
|
not in {
|
||||||
|
"historical_worker_running",
|
||||||
|
"historical_triton_running",
|
||||||
|
"source_mount_read_only",
|
||||||
|
"isolated_model_service",
|
||||||
|
"public_worker_port_added",
|
||||||
|
"commands_enabled",
|
||||||
|
"actuation_allowed",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
booleans = {
|
||||||
|
field: _boolean(value.get(field), field) for field in fields if field not in strings
|
||||||
|
}
|
||||||
|
return cls(**strings, **booleans)
|
||||||
|
|
||||||
|
|
||||||
|
def _string(value: object, label: str) -> str:
|
||||||
|
if not isinstance(value, str) or not value:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError(f"{label} must be a non-empty string")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def _boolean(value: object, label: str) -> bool:
|
||||||
|
if not isinstance(value, bool):
|
||||||
|
raise ReferenceGraphRuntimeIdentityError(f"{label} must be boolean")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def _identifier(value: str, label: str) -> None:
|
||||||
|
if _IDENTIFIER.fullmatch(value) is None:
|
||||||
|
raise ReferenceGraphRuntimeIdentityError(f"{label} is invalid")
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"REFERENCE_GRAPH_RUNTIME_IDENTITY_SCHEMA",
|
||||||
|
"ReferenceGraphRuntimeIdentity",
|
||||||
|
"ReferenceGraphRuntimeIdentityError",
|
||||||
|
]
|
||||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
import math
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import uuid
|
import uuid
|
||||||
@@ -13,6 +14,7 @@ from pathlib import Path
|
|||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
from .graph_contracts import GraphRunMode, GraphRunResultV2, GraphState, TerminalOutcomeType
|
from .graph_contracts import GraphRunMode, GraphRunResultV2, GraphState, TerminalOutcomeType
|
||||||
|
from .reference_graph_identity import ReferenceGraphRuntimeIdentity
|
||||||
from .reference_graph_parity import ReferenceGraphParityReport
|
from .reference_graph_parity import ReferenceGraphParityReport
|
||||||
|
|
||||||
REFERENCE_GRAPH_RESULT_PREFIX: Final = "m47-reference-graph-"
|
REFERENCE_GRAPH_RESULT_PREFIX: Final = "m47-reference-graph-"
|
||||||
@@ -39,9 +41,15 @@ def seal_reference_graph_result(
|
|||||||
output_root: Path,
|
output_root: Path,
|
||||||
expected_frames: int,
|
expected_frames: int,
|
||||||
parity: ReferenceGraphParityReport,
|
parity: ReferenceGraphParityReport,
|
||||||
|
runtime_identity: ReferenceGraphRuntimeIdentity,
|
||||||
|
execution_elapsed_seconds: float,
|
||||||
) -> SealedReferenceGraphResult:
|
) -> SealedReferenceGraphResult:
|
||||||
if expected_frames < 1:
|
if expected_frames < 1:
|
||||||
raise ReferenceGraphResultError("expected frame count must be positive")
|
raise ReferenceGraphResultError("expected frame count must be positive")
|
||||||
|
if not math.isfinite(execution_elapsed_seconds) or execution_elapsed_seconds < 0.0:
|
||||||
|
raise ReferenceGraphResultError("execution elapsed seconds must be finite and non-negative")
|
||||||
|
if runtime_identity.graph_id != result.graph_id:
|
||||||
|
raise ReferenceGraphResultError("runtime and graph result identities differ")
|
||||||
outcomes = Counter(item.outcome.value for item in result.terminal_outcomes)
|
outcomes = Counter(item.outcome.value for item in result.terminal_outcomes)
|
||||||
gates = {
|
gates = {
|
||||||
"lossless_replay_mode": result.run_mode is GraphRunMode.LOSSLESS_REPLAY,
|
"lossless_replay_mode": result.run_mode is GraphRunMode.LOSSLESS_REPLAY,
|
||||||
@@ -58,6 +66,7 @@ def seal_reference_graph_result(
|
|||||||
"accepted_m45r_m46_parity": parity.accepted,
|
"accepted_m45r_m46_parity": parity.accepted,
|
||||||
}
|
}
|
||||||
accepted = all(gates.values())
|
accepted = all(gates.values())
|
||||||
|
runtime = runtime_identity.to_dict()
|
||||||
report: dict[str, object] = {
|
report: dict[str, object] = {
|
||||||
"schema_version": REFERENCE_GRAPH_REPORT_SCHEMA,
|
"schema_version": REFERENCE_GRAPH_REPORT_SCHEMA,
|
||||||
"graph_id": result.graph_id,
|
"graph_id": result.graph_id,
|
||||||
@@ -73,6 +82,10 @@ def seal_reference_graph_result(
|
|||||||
"accepted_parity": parity.to_dict(),
|
"accepted_parity": parity.to_dict(),
|
||||||
"gates": gates,
|
"gates": gates,
|
||||||
"accepted": accepted,
|
"accepted": accepted,
|
||||||
|
"execution": {
|
||||||
|
"elapsed_seconds": execution_elapsed_seconds,
|
||||||
|
"runtime_identity": runtime,
|
||||||
|
},
|
||||||
"authority": {
|
"authority": {
|
||||||
"physical_live": False,
|
"physical_live": False,
|
||||||
"commands_enabled": False,
|
"commands_enabled": False,
|
||||||
@@ -90,6 +103,7 @@ def seal_reference_graph_result(
|
|||||||
frames_path = staging / "frames.jsonl"
|
frames_path = staging / "frames.jsonl"
|
||||||
outcomes_path = staging / "outcomes.jsonl"
|
outcomes_path = staging / "outcomes.jsonl"
|
||||||
report_path = staging / "report.json"
|
report_path = staging / "report.json"
|
||||||
|
runtime_path = staging / "runtime.json"
|
||||||
_write_json_lines(
|
_write_json_lines(
|
||||||
frames_path,
|
frames_path,
|
||||||
tuple(delivery.canonical_dict() for delivery in result.deliveries),
|
tuple(delivery.canonical_dict() for delivery in result.deliveries),
|
||||||
@@ -99,18 +113,20 @@ def seal_reference_graph_result(
|
|||||||
tuple(outcome.to_dict() for outcome in result.terminal_outcomes),
|
tuple(outcome.to_dict() for outcome in result.terminal_outcomes),
|
||||||
)
|
)
|
||||||
_write_json(report_path, report)
|
_write_json(report_path, report)
|
||||||
|
_write_json(runtime_path, runtime)
|
||||||
file_rows = {
|
file_rows = {
|
||||||
name: {
|
name: {
|
||||||
"sha256": _sha256_file(staging / name),
|
"sha256": _sha256_file(staging / name),
|
||||||
"bytes": (staging / name).stat().st_size,
|
"bytes": (staging / name).stat().st_size,
|
||||||
}
|
}
|
||||||
for name in ("frames.jsonl", "outcomes.jsonl", "report.json")
|
for name in ("frames.jsonl", "outcomes.jsonl", "report.json", "runtime.json")
|
||||||
}
|
}
|
||||||
identity: dict[str, object] = {
|
identity: dict[str, object] = {
|
||||||
"graph_id": result.graph_id,
|
"graph_id": result.graph_id,
|
||||||
"source_profile_id": result.source_profile_id,
|
"source_profile_id": result.source_profile_id,
|
||||||
"run_mode": result.run_mode.value,
|
"run_mode": result.run_mode.value,
|
||||||
"canonical_payload_sha256": result.canonical_payload_sha256,
|
"canonical_payload_sha256": result.canonical_payload_sha256,
|
||||||
|
"runtime": runtime,
|
||||||
"files": file_rows,
|
"files": file_rows,
|
||||||
}
|
}
|
||||||
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
|
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
|
||||||
@@ -156,16 +172,8 @@ def _publish_immutable(staging: Path, target: Path) -> None:
|
|||||||
if target.exists():
|
if target.exists():
|
||||||
if target.is_symlink() or not target.is_dir():
|
if target.is_symlink() or not target.is_dir():
|
||||||
raise ReferenceGraphResultError("immutable result target is not a real directory")
|
raise ReferenceGraphResultError("immutable result target is not a real directory")
|
||||||
expected = {
|
expected = {path.name: _sha256_file(path) for path in staging.iterdir() if path.is_file()}
|
||||||
path.name: _sha256_file(path)
|
observed = {path.name: _sha256_file(path) for path in target.iterdir() if path.is_file()}
|
||||||
for path in staging.iterdir()
|
|
||||||
if path.is_file()
|
|
||||||
}
|
|
||||||
observed = {
|
|
||||||
path.name: _sha256_file(path)
|
|
||||||
for path in target.iterdir()
|
|
||||||
if path.is_file()
|
|
||||||
}
|
|
||||||
if expected != observed:
|
if expected != observed:
|
||||||
raise ReferenceGraphResultError("immutable result identity collision")
|
raise ReferenceGraphResultError("immutable result identity collision")
|
||||||
shutil.rmtree(staging)
|
shutil.rmtree(staging)
|
||||||
|
|||||||
@@ -43,18 +43,16 @@ def test_m47_worker_artifact_is_deterministic_and_self_contained(tmp_path: Path)
|
|||||||
with tarfile.open(first["artifact"], "r:gz") as archive:
|
with tarfile.open(first["artifact"], "r:gz") as archive:
|
||||||
regular = _regular_files(archive)
|
regular = _regular_files(archive)
|
||||||
payload_names = sorted(
|
payload_names = sorted(
|
||||||
name.removeprefix("payload/")
|
name.removeprefix("payload/") for name in regular if name.startswith("payload/")
|
||||||
for name in regular
|
|
||||||
if name.startswith("payload/")
|
|
||||||
)
|
)
|
||||||
assert payload_names == first["payload_files"]
|
assert payload_names == first["payload_files"]
|
||||||
assert regular["files.txt"].decode().splitlines() == first["payload_files"]
|
assert regular["files.txt"].decode().splitlines() == first["payload_files"]
|
||||||
assert _sha256(regular[f"payload/{BUILDER.WHEEL_NAME}"]) == first["wheel_sha256"]
|
assert _sha256(regular[f"payload/{BUILDER.WHEEL_NAME}"]) == first["wheel_sha256"]
|
||||||
assert regular[f"payload/{BUILDER.RUNNER.name}"] == BUILDER.RUNNER.read_bytes()
|
assert regular[f"payload/{BUILDER.RUNNER.name}"] == BUILDER.RUNNER.read_bytes()
|
||||||
for relative in BUILDER.CONFIG_PATHS:
|
for relative in BUILDER.CONFIG_PATHS:
|
||||||
assert regular[f"payload/{relative.name}"] == (
|
assert (
|
||||||
BUILDER.REPOSITORY_ROOT / relative
|
regular[f"payload/{relative.name}"] == (BUILDER.REPOSITORY_ROOT / relative).read_bytes()
|
||||||
).read_bytes()
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_m47_descriptor_preserves_nonparticipants_and_separates_readiness() -> None:
|
def test_m47_descriptor_preserves_nonparticipants_and_separates_readiness() -> None:
|
||||||
@@ -70,9 +68,7 @@ def test_m47_descriptor_preserves_nonparticipants_and_separates_readiness() -> N
|
|||||||
assert descriptor["transition"] == "m47-canonical-graph-isolated-shadow-v1"
|
assert descriptor["transition"] == "m47-canonical-graph-isolated-shadow-v1"
|
||||||
assert descriptor["boundary"]["external_deploy_registry"] is False
|
assert descriptor["boundary"]["external_deploy_registry"] is False
|
||||||
assert descriptor["container"]["public_ports"] is False
|
assert descriptor["container"]["public_ports"] is False
|
||||||
assert descriptor["container"]["triton_name"] == (
|
assert descriptor["container"]["triton_name"] == ("ndc-mission-core-m47-triton-shadow")
|
||||||
"ndc-mission-core-m47-triton-shadow"
|
|
||||||
)
|
|
||||||
assert descriptor["container"]["model_repository_host_path"] == (
|
assert descriptor["container"]["model_repository_host_path"] == (
|
||||||
"D:\\NDC_MISSIONCORE\\runtime\\models"
|
"D:\\NDC_MISSIONCORE\\runtime\\models"
|
||||||
)
|
)
|
||||||
@@ -111,9 +107,7 @@ def test_m47_descriptor_preserves_nonparticipants_and_separates_readiness() -> N
|
|||||||
"terminal_accounting_required": True,
|
"terminal_accounting_required": True,
|
||||||
"actuation_allowed": False,
|
"actuation_allowed": False,
|
||||||
}
|
}
|
||||||
assert set(descriptor["release"]["configs"]) == {
|
assert set(descriptor["release"]["configs"]) == {path.name for path in BUILDER.CONFIG_PATHS}
|
||||||
path.name for path in BUILDER.CONFIG_PATHS
|
|
||||||
}
|
|
||||||
serialized = json.dumps(descriptor).encode()
|
serialized = json.dumps(descriptor).encode()
|
||||||
assert b"PRIVATE KEY" not in serialized
|
assert b"PRIVATE KEY" not in serialized
|
||||||
assert b"password=" not in serialized.lower()
|
assert b"password=" not in serialized.lower()
|
||||||
@@ -127,6 +121,9 @@ def test_m47_runner_calls_only_the_canonical_graph_entrypoint() -> None:
|
|||||||
assert '"--mode", $descriptor.acceptance.run_mode' in runner
|
assert '"--mode", $descriptor.acceptance.run_mode' in runner
|
||||||
assert '"--temporal-parity-frames"' in runner
|
assert '"--temporal-parity-frames"' in runner
|
||||||
assert '"--threat-parity-frames"' in runner
|
assert '"--threat-parity-frames"' in runner
|
||||||
|
assert '"--runtime-identity", "/run/mission-core/runtime-identity.json"' in runner
|
||||||
|
assert 'schema_version = "missioncore.reference-graph-runtime-identity/v3"' in runner
|
||||||
|
assert "patch_id = $descriptor.patch_id" in runner
|
||||||
assert 'Write-Output "PROVIDER_READINESS=accepted"' in runner
|
assert 'Write-Output "PROVIDER_READINESS=accepted"' in runner
|
||||||
assert 'Write-Output "GRAPH_READINESS=accepted"' in runner
|
assert 'Write-Output "GRAPH_READINESS=accepted"' in runner
|
||||||
assert 'Write-Output "DURABLE_WORKER_ACTION=none"' in runner
|
assert 'Write-Output "DURABLE_WORKER_ACTION=none"' in runner
|
||||||
|
|||||||
@@ -14,12 +14,41 @@ from k1link.perception.graph_contracts import (
|
|||||||
build_graph_run_result_v2,
|
build_graph_run_result_v2,
|
||||||
)
|
)
|
||||||
from k1link.perception.providers import ReferencePerceptionGraphConfigV2
|
from k1link.perception.providers import ReferencePerceptionGraphConfigV2
|
||||||
|
from k1link.perception.reference_graph_identity import ReferenceGraphRuntimeIdentity
|
||||||
from k1link.perception.reference_graph_parity import ReferenceGraphParityReport
|
from k1link.perception.reference_graph_parity import ReferenceGraphParityReport
|
||||||
from k1link.perception.reference_graph_result import seal_reference_graph_result
|
from k1link.perception.reference_graph_result import seal_reference_graph_result
|
||||||
|
|
||||||
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
|
REPOSITORY_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
|
||||||
|
|
||||||
|
def _runtime() -> ReferenceGraphRuntimeIdentity:
|
||||||
|
return ReferenceGraphRuntimeIdentity.from_dict(
|
||||||
|
{
|
||||||
|
"schema_version": "missioncore.reference-graph-runtime-identity/v3",
|
||||||
|
"worker_id": "worker-006",
|
||||||
|
"worker_node": "DESKTOP-OPJ8J04",
|
||||||
|
"worker_container_id": "c" * 64,
|
||||||
|
"worker_image_id": "sha256:" + "d" * 64,
|
||||||
|
"isolated_triton_container_id": "e" * 64,
|
||||||
|
"isolated_triton_image_id": "sha256:" + "d" * 64,
|
||||||
|
"historical_worker_container_id": "f" * 64,
|
||||||
|
"historical_worker_running": False,
|
||||||
|
"historical_triton_container_id": "a" * 64,
|
||||||
|
"historical_triton_running": False,
|
||||||
|
"artifact_sha256": "b" * 64,
|
||||||
|
"patch_id": "mission-core-m47-test",
|
||||||
|
"code_revision": "1" * 40,
|
||||||
|
"graph_id": "reference-perception-graph/v2",
|
||||||
|
"started_at_utc": "2026-08-23T12:00:00.000Z",
|
||||||
|
"source_mount_read_only": True,
|
||||||
|
"isolated_model_service": True,
|
||||||
|
"public_worker_port_added": False,
|
||||||
|
"commands_enabled": False,
|
||||||
|
"actuation_allowed": False,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _parity(accepted: bool = True) -> ReferenceGraphParityReport:
|
def _parity(accepted: bool = True) -> ReferenceGraphParityReport:
|
||||||
return ReferenceGraphParityReport(
|
return ReferenceGraphParityReport(
|
||||||
expected_frames=1,
|
expected_frames=1,
|
||||||
@@ -110,12 +139,16 @@ def test_reference_graph_result_is_content_addressed_and_reproducible(tmp_path:
|
|||||||
output_root=tmp_path / "one",
|
output_root=tmp_path / "one",
|
||||||
expected_frames=1,
|
expected_frames=1,
|
||||||
parity=_parity(),
|
parity=_parity(),
|
||||||
|
runtime_identity=_runtime(),
|
||||||
|
execution_elapsed_seconds=1.25,
|
||||||
)
|
)
|
||||||
second = seal_reference_graph_result(
|
second = seal_reference_graph_result(
|
||||||
_result(),
|
_result(),
|
||||||
output_root=tmp_path / "two",
|
output_root=tmp_path / "two",
|
||||||
expected_frames=1,
|
expected_frames=1,
|
||||||
parity=_parity(),
|
parity=_parity(),
|
||||||
|
runtime_identity=_runtime(),
|
||||||
|
execution_elapsed_seconds=1.25,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert first.accepted is True
|
assert first.accepted is True
|
||||||
@@ -134,9 +167,13 @@ def test_reference_graph_result_is_content_addressed_and_reproducible(tmp_path:
|
|||||||
"no_unavailable_frames": True,
|
"no_unavailable_frames": True,
|
||||||
"accepted_m45r_m46_parity": True,
|
"accepted_m45r_m46_parity": True,
|
||||||
}
|
}
|
||||||
assert {
|
assert {path.name: path.read_bytes() for path in first.result_root.iterdir()} == {
|
||||||
path.name: path.read_bytes() for path in first.result_root.iterdir()
|
path.name: path.read_bytes() for path in second.result_root.iterdir()
|
||||||
} == {path.name: path.read_bytes() for path in second.result_root.iterdir()}
|
}
|
||||||
|
runtime = json.loads((first.result_root / "runtime.json").read_text("utf-8"))
|
||||||
|
assert runtime == _runtime().to_dict()
|
||||||
|
assert first.manifest["runtime"] == runtime
|
||||||
|
assert first.manifest["files"]["runtime.json"]["sha256"]
|
||||||
|
|
||||||
|
|
||||||
def test_reference_graph_result_fails_closed_on_supersession(tmp_path: Path) -> None:
|
def test_reference_graph_result_fails_closed_on_supersession(tmp_path: Path) -> None:
|
||||||
@@ -145,6 +182,8 @@ def test_reference_graph_result_fails_closed_on_supersession(tmp_path: Path) ->
|
|||||||
output_root=tmp_path,
|
output_root=tmp_path,
|
||||||
expected_frames=1,
|
expected_frames=1,
|
||||||
parity=_parity(),
|
parity=_parity(),
|
||||||
|
runtime_identity=_runtime(),
|
||||||
|
execution_elapsed_seconds=1.25,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert sealed.accepted is False
|
assert sealed.accepted is False
|
||||||
|
|||||||
Reference in New Issue
Block a user