feat(perception): stabilize pre-capture methodology
This commit is contained in:
@@ -254,7 +254,7 @@ def build_e30_materialization(
|
||||
source=source,
|
||||
)
|
||||
|
||||
identity = {
|
||||
identity: dict[str, object] = {
|
||||
"schema_version": E30_MATERIALIZATION_SCHEMA,
|
||||
"review_pack": {
|
||||
"result_id": _required_string(review.manifest, "result_id"),
|
||||
@@ -635,7 +635,14 @@ def _engineering_triage(
|
||||
) -> dict[str, object]:
|
||||
"""Route evidence without pretending that a rule is a semantic verdict."""
|
||||
|
||||
selected_count = int(metadata["selected_point_count"])
|
||||
selected_count_value = metadata["selected_point_count"]
|
||||
if (
|
||||
not isinstance(selected_count_value, int)
|
||||
or isinstance(selected_count_value, bool)
|
||||
or selected_count_value < 0
|
||||
):
|
||||
raise E30MaterializationError("selected point count is invalid")
|
||||
selected_count = selected_count_value
|
||||
detector_score = metadata.get("detector_score")
|
||||
stratum = _required_string(item, "stratum")
|
||||
locator = _required_object(item, "e29_locator")
|
||||
|
||||
@@ -44,7 +44,6 @@ from .e32_track_geometry_storage import (
|
||||
E32_POINT_SLAB_REFERENCE_SCHEMA,
|
||||
E32_POINTS_NAME,
|
||||
E32_SOURCE_INDICES_NAME,
|
||||
E32_TRACK_GEOMETRY_RECORD_SCHEMA,
|
||||
E32TrackGeometryStorageError,
|
||||
frame_from_record,
|
||||
load_point_storage,
|
||||
@@ -52,6 +51,9 @@ from .e32_track_geometry_storage import (
|
||||
validate_storage,
|
||||
write_point_storage,
|
||||
)
|
||||
from .e32_track_geometry_storage import (
|
||||
E32_TRACK_GEOMETRY_RECORD_SCHEMA as E32_TRACK_GEOMETRY_RECORD_SCHEMA,
|
||||
)
|
||||
from .lidar_field_review import E10LidarFieldSource
|
||||
from .lidar_local_surface import K1LocalSurfaceV1
|
||||
from .semantic_geometry_fusion import (
|
||||
|
||||
@@ -790,24 +790,45 @@ def _finalize_report(
|
||||
== occupancy.get("e34_consumed_current_point_rows")
|
||||
),
|
||||
"active_component_bound": (
|
||||
components.get("peak_active")
|
||||
<= layer.get("maximum_active_components")
|
||||
_nonnegative_int(components.get("peak_active"), "E34 peak active components")
|
||||
<= _positive_int(
|
||||
layer.get("maximum_active_components"),
|
||||
"E34 maximum active components",
|
||||
)
|
||||
),
|
||||
"component_cell_bound": (
|
||||
occupancy.get("peak_cells_per_component")
|
||||
<= layer.get("maximum_cells_per_component")
|
||||
_nonnegative_int(
|
||||
occupancy.get("peak_cells_per_component"),
|
||||
"E34 peak cells per component",
|
||||
)
|
||||
<= _positive_int(
|
||||
layer.get("maximum_cells_per_component"),
|
||||
"E34 maximum cells per component",
|
||||
)
|
||||
),
|
||||
"held_age_within_ttl": (
|
||||
aging.get("maximum_held_age_seconds")
|
||||
_nonnegative_float(
|
||||
aging.get("maximum_held_age_seconds"),
|
||||
"E34 maximum held age",
|
||||
)
|
||||
<= float(layer["occupied_ttl_seconds"]) + 1e-9
|
||||
),
|
||||
"expiry_delay_within_gate": (
|
||||
aging.get("maximum_expiry_delay_seconds")
|
||||
_nonnegative_float(
|
||||
aging.get("maximum_expiry_delay_seconds"),
|
||||
"E34 maximum expiry delay",
|
||||
)
|
||||
<= float(acceptance["maximum_expiry_delay_seconds"]) + 1e-9
|
||||
),
|
||||
"map_frame_jump_candidates_within_gate": (
|
||||
map_frame.get("jump_candidates")
|
||||
<= acceptance.get("maximum_map_frame_jump_candidates")
|
||||
_nonnegative_int(
|
||||
map_frame.get("jump_candidates"),
|
||||
"E34 map-frame jump candidates",
|
||||
)
|
||||
<= _nonnegative_int(
|
||||
acceptance.get("maximum_map_frame_jump_candidates"),
|
||||
"E34 maximum map-frame jump candidates",
|
||||
)
|
||||
),
|
||||
"upstream_artifacts_unchanged": upstream_unchanged,
|
||||
"no_free_space_publication": occupancy.get("free_cell_rows") == 0,
|
||||
@@ -1010,6 +1031,17 @@ def _positive_float(value: object, label: str) -> float:
|
||||
return float(value)
|
||||
|
||||
|
||||
def _nonnegative_float(value: object, label: str) -> float:
|
||||
if (
|
||||
not isinstance(value, (int, float))
|
||||
or isinstance(value, bool)
|
||||
or not math.isfinite(float(value))
|
||||
or float(value) < 0.0
|
||||
):
|
||||
raise E34TemporalOccupiedReplayError(f"{label} is invalid")
|
||||
return float(value)
|
||||
|
||||
|
||||
def _positive_int(value: object, label: str) -> int:
|
||||
result = _nonnegative_int(value, label)
|
||||
if result == 0:
|
||||
|
||||
@@ -142,6 +142,9 @@ def assign_split(
|
||||
range_bucket,
|
||||
)):
|
||||
raise E37AcceptanceContractError("E37 split source row is invalid")
|
||||
assert isinstance(item_id, str)
|
||||
assert isinstance(stratum, str)
|
||||
assert isinstance(range_bucket, str)
|
||||
grouped[(stratum, range_bucket)].append(row)
|
||||
|
||||
assignments: dict[str, SplitName] = {}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
"""Development-qualified RAVNOVES00 R1 perception refinement.
|
||||
"""Historical RAVNOVES00 R1 perception refinement.
|
||||
|
||||
E39 keeps the E37 denominator and validation split immutable. It enriches the
|
||||
E39 keeps the nominal E37 denominator and split immutable. It enriches the
|
||||
E38 tabular baseline with source-scoped camera and LiDAR shape features, chooses
|
||||
the fixed model contract through development-only cross-validation, fits only
|
||||
on development labels, and evaluates the sealed validation partition once.
|
||||
on development labels, and evaluates the then-designated validation partition.
|
||||
E41 later proved that this partition is visible engineering evidence with
|
||||
connected group overlap, not an independent sealed accuracy gate.
|
||||
|
||||
The result is diagnostic. It grants no navigation, command, or safety
|
||||
authority and makes no claim about another route, rig, camera, or mount.
|
||||
@@ -92,7 +94,7 @@ def build_e39_perception_refinement(
|
||||
output_root: Path,
|
||||
worker_node: str | None = None,
|
||||
) -> E39PerceptionRefinement:
|
||||
"""Fit the frozen E39 contract and evaluate the sealed validation split."""
|
||||
"""Fit E39 and evaluate the historical visible E37 validation slice."""
|
||||
|
||||
profile_file = profile_path.resolve(strict=True)
|
||||
profile = _read_json(profile_file)
|
||||
@@ -814,7 +816,10 @@ def _transform(
|
||||
scale: np.ndarray[Any, Any],
|
||||
clip: float,
|
||||
) -> np.ndarray[Any, Any]:
|
||||
return np.clip((matrix - median) / scale, -clip, clip)
|
||||
return np.asarray(
|
||||
np.clip((matrix - median) / scale, -clip, clip),
|
||||
dtype=np.float64,
|
||||
)
|
||||
|
||||
|
||||
def _predict_presence(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,908 @@
|
||||
"""Physically separate frozen E40 prediction from visible contract evaluation.
|
||||
|
||||
The predictor package contains a trained model, a feature matrix and stripped
|
||||
item metadata. It contains no acceptance rows, split assignments, reference
|
||||
labels, severity or scoring state. The predictor therefore cannot inspect
|
||||
truth. A separate evaluator joins the immutable prediction artifact to E37
|
||||
after inference and reports source-scoped engineering-contract conformance.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import uuid
|
||||
from collections import Counter, defaultdict
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Final
|
||||
|
||||
import numpy as np
|
||||
|
||||
from k1link.compute.e37_acceptance_contract import (
|
||||
E37_ITEMS_NAME,
|
||||
read_e37_acceptance_contract,
|
||||
)
|
||||
from k1link.compute.e40_perception_product_gate import (
|
||||
_LABELS,
|
||||
_predict_product_presence,
|
||||
_project_dimensions,
|
||||
)
|
||||
from k1link.compute.e41_methodology_audit import (
|
||||
_load_feature_cache,
|
||||
_validate_e40_package,
|
||||
)
|
||||
|
||||
E41_PREDICTOR_PACKAGE_SCHEMA: Final = "missioncore.e41-predictor-package/v1"
|
||||
E41_PREDICTION_RESULT_SCHEMA: Final = "missioncore.e41-prediction-result/v1"
|
||||
E41_PREDICTION_ROW_SCHEMA: Final = "missioncore.e41-prediction-row/v1"
|
||||
E41_VISIBLE_EVALUATION_SCHEMA: Final = "missioncore.e41-visible-evaluation/v1"
|
||||
|
||||
E41_PACKAGE_MANIFEST_NAME: Final = "manifest.json"
|
||||
E41_MODEL_NAME: Final = "model.json"
|
||||
E41_ITEMS_NAME: Final = "items.jsonl"
|
||||
E41_FEATURE_MANIFEST_NAME: Final = "feature-cache.json"
|
||||
E41_FEATURE_ARRAYS_NAME: Final = "feature-vectors.npz"
|
||||
E41_PREDICTIONS_NAME: Final = "predictions.jsonl"
|
||||
E41_EVALUATION_NAME: Final = "evaluation.json"
|
||||
|
||||
_AUTHORITY: Final = {
|
||||
"commands_enabled": False,
|
||||
"navigation_or_safety_accepted": False,
|
||||
}
|
||||
_STRATA: Final = {"agree", "camera-only", "conflict", "geometry-only", "unknown"}
|
||||
_DIMENSIONS: Final = ("presence", "geometry_association", "freshness")
|
||||
_PREDICTION_FORBIDDEN_KEYS: Final = frozenset(
|
||||
{
|
||||
"acceptance",
|
||||
"reference",
|
||||
"scored",
|
||||
"severity",
|
||||
"split",
|
||||
"truth",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class E41EvaluationBoundaryError(RuntimeError):
|
||||
"""An E41 predictor package, prediction, or visible evaluation is invalid."""
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class E41PredictionResult:
|
||||
result_id: str
|
||||
result_root: Path
|
||||
manifest: dict[str, Any]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class E41VisibleEvaluation:
|
||||
result_id: str
|
||||
result_root: Path
|
||||
manifest: dict[str, Any]
|
||||
evaluation: dict[str, Any]
|
||||
|
||||
|
||||
def build_e41_predictor_package(
|
||||
*,
|
||||
materialization_root: Path,
|
||||
e40_package_root: Path,
|
||||
e40_model_path: Path,
|
||||
output_root: Path,
|
||||
) -> Path:
|
||||
"""Build a content-addressed predictor-only package with no truth material."""
|
||||
|
||||
materialization = materialization_root.resolve(strict=True)
|
||||
package_root = e40_package_root.resolve(strict=True)
|
||||
e40_package, package_artifacts = _validate_e40_package(package_root)
|
||||
model_source = e40_model_path.resolve(strict=True)
|
||||
model = _read_json(model_source)
|
||||
materialization_rows = _read_jsonl(materialization / "materialized-items.jsonl")
|
||||
materialization_by_id = _unique_by_item_id(materialization_rows, "materialization")
|
||||
feature_root = (
|
||||
package_root / "input" / "materialization" / materialization.name
|
||||
)
|
||||
item_ids, feature_names, feature_matrix, feature_binding = _load_feature_cache(
|
||||
feature_root,
|
||||
package_artifacts=package_artifacts,
|
||||
)
|
||||
_validate_frozen_model(model, feature_names)
|
||||
items = []
|
||||
for sequence, item_id in enumerate(item_ids):
|
||||
row = materialization_by_id.get(item_id)
|
||||
if row is None:
|
||||
raise E41EvaluationBoundaryError("E41 predictor item denominator changed")
|
||||
stratum = row.get("stratum")
|
||||
if stratum not in _STRATA:
|
||||
raise E41EvaluationBoundaryError("E41 predictor item stratum is invalid")
|
||||
items.append(
|
||||
{
|
||||
"schema_version": "missioncore.e41-predictor-item/v1",
|
||||
"sequence": sequence,
|
||||
"item_id": item_id,
|
||||
"source_stratum": stratum,
|
||||
}
|
||||
)
|
||||
_assert_truth_free(items, "E41 predictor item metadata")
|
||||
|
||||
arrays_payload = _npz_payload(item_ids, feature_matrix)
|
||||
feature_manifest = {
|
||||
"schema_version": "missioncore.e41-predictor-feature-cache/v1",
|
||||
"item_count": len(item_ids),
|
||||
"dimensions": len(feature_names),
|
||||
"feature_names": feature_names,
|
||||
"feature_names_sha256": hashlib.sha256(_canonical_json(feature_names)).hexdigest(),
|
||||
"arrays_path": E41_FEATURE_ARRAYS_NAME,
|
||||
"arrays_byte_length": len(arrays_payload),
|
||||
"arrays_sha256": hashlib.sha256(arrays_payload).hexdigest(),
|
||||
}
|
||||
items_payload = _jsonl_payload(items)
|
||||
model_payload = _json_payload(model)
|
||||
feature_manifest_payload = _json_payload(feature_manifest)
|
||||
sources = {
|
||||
E41_MODEL_NAME: model_payload,
|
||||
E41_ITEMS_NAME: items_payload,
|
||||
E41_FEATURE_MANIFEST_NAME: feature_manifest_payload,
|
||||
E41_FEATURE_ARRAYS_NAME: arrays_payload,
|
||||
}
|
||||
source_artifacts = [
|
||||
{
|
||||
"path": name,
|
||||
"byte_length": len(payload),
|
||||
"sha256": hashlib.sha256(payload).hexdigest(),
|
||||
}
|
||||
for name, payload in sorted(sources.items())
|
||||
]
|
||||
identity = {
|
||||
"schema_version": E41_PREDICTOR_PACKAGE_SCHEMA,
|
||||
"classification": "truth-free-frozen-e40-predictor-input",
|
||||
"source": {
|
||||
"materialization_id": materialization.name,
|
||||
"materialization_index_sha256": _sha256(
|
||||
materialization / "materialized-items.jsonl"
|
||||
),
|
||||
"e40_worker_package_id": e40_package["package_id"],
|
||||
"e40_worker_package_identity_sha256": e40_package["identity_sha256"],
|
||||
"e40_model_sha256": _sha256(model_source),
|
||||
"feature_cache": feature_binding,
|
||||
},
|
||||
"runtime_contract": {
|
||||
"python": "3.12",
|
||||
"numpy_api": "numpy-1.26-or-newer",
|
||||
"determinism": "frozen-weights-no-randomness",
|
||||
},
|
||||
"source_artifacts": source_artifacts,
|
||||
"truth_material_included": False,
|
||||
"producer_sha256": _sha256(Path(__file__).resolve(strict=True)),
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
|
||||
package_id = f"e41-predictor-package-{identity_sha256}"
|
||||
destination = output_root.expanduser().absolute() / package_id
|
||||
if destination.exists():
|
||||
validate_e41_predictor_package(destination)
|
||||
return destination
|
||||
destination.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
staging = destination.parent / f".{package_id}.{uuid.uuid4().hex}.tmp"
|
||||
staging.mkdir(mode=0o700, exist_ok=False)
|
||||
try:
|
||||
for name, payload in sources.items():
|
||||
_write_bytes(staging / name, payload)
|
||||
manifest = {
|
||||
"schema_version": E41_PREDICTOR_PACKAGE_SCHEMA,
|
||||
"package_id": package_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"identity": identity,
|
||||
"created_at_utc": _utc_now(),
|
||||
"artifacts": [
|
||||
{
|
||||
**row,
|
||||
"role": "predictor-only-input",
|
||||
}
|
||||
for row in source_artifacts
|
||||
],
|
||||
}
|
||||
_write_json(staging / E41_PACKAGE_MANIFEST_NAME, manifest)
|
||||
validate_e41_predictor_package(staging, allow_staging=True)
|
||||
os.replace(staging, destination)
|
||||
except BaseException:
|
||||
shutil.rmtree(staging, ignore_errors=True)
|
||||
raise
|
||||
validate_e41_predictor_package(destination)
|
||||
return destination
|
||||
|
||||
|
||||
def validate_e41_predictor_package(
|
||||
root: Path,
|
||||
*,
|
||||
allow_staging: bool = False,
|
||||
) -> dict[str, Any]:
|
||||
"""Validate exact package identity, artifacts, and the truth-free boundary."""
|
||||
|
||||
resolved = root.resolve(strict=True)
|
||||
manifest = _read_json(resolved / E41_PACKAGE_MANIFEST_NAME)
|
||||
identity = _object(manifest.get("identity"), "E41 predictor identity")
|
||||
identity_sha256 = manifest.get("identity_sha256")
|
||||
package_id = manifest.get("package_id")
|
||||
expected_name = isinstance(package_id, str) and (
|
||||
resolved.name == package_id
|
||||
or (
|
||||
allow_staging
|
||||
and resolved.name.startswith(f".{package_id}.")
|
||||
and resolved.name.endswith(".tmp")
|
||||
)
|
||||
)
|
||||
if (
|
||||
manifest.get("schema_version") != E41_PREDICTOR_PACKAGE_SCHEMA
|
||||
or not isinstance(identity_sha256, str)
|
||||
or hashlib.sha256(_canonical_json(identity)).hexdigest() != identity_sha256
|
||||
or package_id != f"e41-predictor-package-{identity_sha256}"
|
||||
or not expected_name
|
||||
or identity.get("classification") != "truth-free-frozen-e40-predictor-input"
|
||||
or identity.get("truth_material_included") is not False
|
||||
or identity.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 predictor package identity is invalid")
|
||||
expected_rows = identity.get("source_artifacts")
|
||||
artifacts = manifest.get("artifacts")
|
||||
if not isinstance(expected_rows, list) or not isinstance(artifacts, list):
|
||||
raise E41EvaluationBoundaryError("E41 predictor package catalog is invalid")
|
||||
expected: dict[str, tuple[int, str]] = {}
|
||||
for row in expected_rows:
|
||||
if (
|
||||
not isinstance(row, dict)
|
||||
or not isinstance((name := row.get("path")), str)
|
||||
or name in expected
|
||||
or Path(name).is_absolute()
|
||||
or ".." in Path(name).parts
|
||||
or not isinstance((length := row.get("byte_length")), int)
|
||||
or not isinstance((sha256 := row.get("sha256")), str)
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 predictor source artifact is invalid")
|
||||
expected[name] = (length, sha256)
|
||||
actual_files = {
|
||||
path.relative_to(resolved).as_posix()
|
||||
for path in resolved.rglob("*")
|
||||
if path.is_file()
|
||||
}
|
||||
if actual_files != set(expected) | {E41_PACKAGE_MANIFEST_NAME}:
|
||||
raise E41EvaluationBoundaryError("E41 predictor package file set changed")
|
||||
observed: set[str] = set()
|
||||
for row in artifacts:
|
||||
if not isinstance(row, dict):
|
||||
raise E41EvaluationBoundaryError("E41 predictor artifact is invalid")
|
||||
name = row.get("path")
|
||||
path = resolved / str(name)
|
||||
if (
|
||||
not isinstance(name, str)
|
||||
or name in observed
|
||||
or row.get("role") != "predictor-only-input"
|
||||
or expected.get(name) != (row.get("byte_length"), row.get("sha256"))
|
||||
or not path.is_file()
|
||||
or path.is_symlink()
|
||||
or row.get("byte_length") != path.stat().st_size
|
||||
or row.get("sha256") != _sha256(path)
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 predictor artifact changed")
|
||||
observed.add(name)
|
||||
if observed != set(expected):
|
||||
raise E41EvaluationBoundaryError("E41 predictor artifact coverage changed")
|
||||
|
||||
items = _read_jsonl(resolved / E41_ITEMS_NAME)
|
||||
_assert_truth_free(items, "E41 predictor package")
|
||||
feature_manifest = _read_json(resolved / E41_FEATURE_MANIFEST_NAME)
|
||||
with np.load(resolved / E41_FEATURE_ARRAYS_NAME, allow_pickle=False) as arrays:
|
||||
item_ids = [str(value) for value in arrays["item_ids"]]
|
||||
matrix = np.asarray(arrays["features"], dtype=np.float64)
|
||||
model = _read_json(resolved / E41_MODEL_NAME)
|
||||
names = feature_manifest.get("feature_names")
|
||||
if (
|
||||
not isinstance(names, list)
|
||||
or not all(isinstance(name, str) for name in names)
|
||||
or feature_manifest.get("item_count") != len(items)
|
||||
or feature_manifest.get("dimensions") != len(names)
|
||||
or feature_manifest.get("feature_names_sha256")
|
||||
!= hashlib.sha256(_canonical_json(names)).hexdigest()
|
||||
or feature_manifest.get("arrays_byte_length")
|
||||
!= (resolved / E41_FEATURE_ARRAYS_NAME).stat().st_size
|
||||
or feature_manifest.get("arrays_sha256")
|
||||
!= _sha256(resolved / E41_FEATURE_ARRAYS_NAME)
|
||||
or matrix.shape != (len(items), len(names))
|
||||
or item_ids != [str(row.get("item_id")) for row in items]
|
||||
or not np.isfinite(matrix).all()
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 predictor feature cache is invalid")
|
||||
_validate_frozen_model(model, names)
|
||||
return manifest
|
||||
|
||||
|
||||
def run_e41_predictor(
|
||||
*,
|
||||
package_root: Path,
|
||||
output_root: Path,
|
||||
runtime_identity: dict[str, str],
|
||||
) -> E41PredictionResult:
|
||||
"""Run the frozen predictor without accepting an acceptance/truth input."""
|
||||
|
||||
package = validate_e41_predictor_package(package_root)
|
||||
resolved = package_root.resolve(strict=True)
|
||||
items = _read_jsonl(resolved / E41_ITEMS_NAME)
|
||||
model = _read_json(resolved / E41_MODEL_NAME)
|
||||
feature_manifest = _read_json(resolved / E41_FEATURE_MANIFEST_NAME)
|
||||
names = [str(value) for value in feature_manifest["feature_names"]]
|
||||
with np.load(resolved / E41_FEATURE_ARRAYS_NAME, allow_pickle=False) as arrays:
|
||||
matrix = np.asarray(arrays["features"], dtype=np.float64)
|
||||
predictions = predict_from_frozen_e40_model(
|
||||
items=items,
|
||||
feature_names=names,
|
||||
feature_matrix=matrix,
|
||||
model=model,
|
||||
)
|
||||
_assert_truth_free(predictions, "E41 prediction result")
|
||||
content_sha256 = hashlib.sha256(_canonical_json(predictions)).hexdigest()
|
||||
identity = {
|
||||
"schema_version": E41_PREDICTION_RESULT_SCHEMA,
|
||||
"predictor_package_id": package["package_id"],
|
||||
"predictor_package_identity_sha256": package["identity_sha256"],
|
||||
"runtime": _validated_runtime_identity(runtime_identity),
|
||||
"prediction_content_sha256": content_sha256,
|
||||
"truth_material_available_to_predictor": False,
|
||||
"producer_sha256": _sha256(Path(__file__).resolve(strict=True)),
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
|
||||
result_id = f"e41-predictions-{identity_sha256}"
|
||||
destination = output_root.expanduser().absolute() / result_id
|
||||
if destination.exists():
|
||||
return read_e41_prediction_result(destination)
|
||||
destination.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
staging = destination.parent / f".{result_id}.{uuid.uuid4().hex}.tmp"
|
||||
staging.mkdir(mode=0o700, exist_ok=False)
|
||||
try:
|
||||
_write_jsonl(staging / E41_PREDICTIONS_NAME, predictions)
|
||||
manifest = {
|
||||
"schema_version": E41_PREDICTION_RESULT_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"identity": identity,
|
||||
"created_at_utc": _utc_now(),
|
||||
"item_count": len(predictions),
|
||||
"truth_material_included": False,
|
||||
"artifacts": [
|
||||
_artifact(
|
||||
staging / E41_PREDICTIONS_NAME,
|
||||
"truth-free-predictions",
|
||||
)
|
||||
],
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
_write_json(staging / E41_PACKAGE_MANIFEST_NAME, manifest)
|
||||
os.replace(staging, destination)
|
||||
except BaseException:
|
||||
shutil.rmtree(staging, ignore_errors=True)
|
||||
raise
|
||||
return read_e41_prediction_result(destination)
|
||||
|
||||
|
||||
def read_e41_prediction_result(root: Path) -> E41PredictionResult:
|
||||
"""Read and validate one immutable truth-free prediction result."""
|
||||
|
||||
resolved = root.resolve(strict=True)
|
||||
manifest = _read_json(resolved / E41_PACKAGE_MANIFEST_NAME)
|
||||
identity = _object(manifest.get("identity"), "E41 prediction identity")
|
||||
identity_sha256 = manifest.get("identity_sha256")
|
||||
if (
|
||||
manifest.get("schema_version") != E41_PREDICTION_RESULT_SCHEMA
|
||||
or not isinstance(identity_sha256, str)
|
||||
or hashlib.sha256(_canonical_json(identity)).hexdigest() != identity_sha256
|
||||
or manifest.get("result_id") != f"e41-predictions-{identity_sha256}"
|
||||
or resolved.name != manifest.get("result_id")
|
||||
or identity.get("truth_material_available_to_predictor") is not False
|
||||
or manifest.get("truth_material_included") is not False
|
||||
or manifest.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 prediction identity is invalid")
|
||||
_validate_single_artifact(
|
||||
resolved,
|
||||
manifest.get("artifacts"),
|
||||
name=E41_PREDICTIONS_NAME,
|
||||
role="truth-free-predictions",
|
||||
)
|
||||
predictions = _read_jsonl(resolved / E41_PREDICTIONS_NAME)
|
||||
_assert_truth_free(predictions, "E41 prediction result")
|
||||
if (
|
||||
manifest.get("item_count") != len(predictions)
|
||||
or identity.get("prediction_content_sha256")
|
||||
!= hashlib.sha256(_canonical_json(predictions)).hexdigest()
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 prediction content is invalid")
|
||||
return E41PredictionResult(
|
||||
result_id=resolved.name,
|
||||
result_root=resolved,
|
||||
manifest=manifest,
|
||||
)
|
||||
|
||||
|
||||
def build_e41_visible_evaluation(
|
||||
*,
|
||||
prediction_root: Path,
|
||||
acceptance_root: Path,
|
||||
output_root: Path,
|
||||
) -> E41VisibleEvaluation:
|
||||
"""Evaluate immutable predictions against the already-visible E37 substrate."""
|
||||
|
||||
prediction = read_e41_prediction_result(prediction_root)
|
||||
acceptance = read_e37_acceptance_contract(acceptance_root)
|
||||
predictions = _read_jsonl(prediction.result_root / E41_PREDICTIONS_NAME)
|
||||
acceptance_rows = _read_jsonl(acceptance.result_root / E37_ITEMS_NAME)
|
||||
evaluation = evaluate_visible_engineering_contract(
|
||||
predictions=predictions,
|
||||
acceptance_rows=acceptance_rows,
|
||||
targets=_object(acceptance.contract.get("targets"), "E37 targets"),
|
||||
label_provenance=_object(
|
||||
acceptance.contract.get("label_provenance"),
|
||||
"E37 label provenance",
|
||||
),
|
||||
)
|
||||
content_sha256 = hashlib.sha256(_canonical_json(evaluation)).hexdigest()
|
||||
identity = {
|
||||
"schema_version": E41_VISIBLE_EVALUATION_SCHEMA,
|
||||
"prediction_result_id": prediction.result_id,
|
||||
"prediction_identity_sha256": prediction.manifest["identity_sha256"],
|
||||
"acceptance_result_id": acceptance.result_id,
|
||||
"acceptance_identity_sha256": acceptance.manifest["identity_sha256"],
|
||||
"acceptance_items_sha256": _sha256(acceptance.result_root / E37_ITEMS_NAME),
|
||||
"evaluation_content_sha256": content_sha256,
|
||||
"evaluation_semantics": "historical-evaluated-visible-validation",
|
||||
"producer_sha256": _sha256(Path(__file__).resolve(strict=True)),
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
|
||||
result_id = f"e41-visible-evaluation-{identity_sha256}"
|
||||
destination = output_root.expanduser().absolute() / result_id
|
||||
if destination.exists():
|
||||
return read_e41_visible_evaluation(destination)
|
||||
destination.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
staging = destination.parent / f".{result_id}.{uuid.uuid4().hex}.tmp"
|
||||
staging.mkdir(mode=0o700, exist_ok=False)
|
||||
document = {
|
||||
"schema_version": E41_VISIBLE_EVALUATION_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"status": "completed-visible-engineering-contract-evaluation",
|
||||
"evaluation": evaluation,
|
||||
"decision": {
|
||||
"blind_gate_eligible": False,
|
||||
"independent_perception_accuracy_proved": False,
|
||||
"source_scoped_engineering_contract_conformance_measured": True,
|
||||
},
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
try:
|
||||
_write_json(staging / E41_EVALUATION_NAME, document)
|
||||
manifest = {
|
||||
"schema_version": E41_VISIBLE_EVALUATION_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"identity": identity,
|
||||
"created_at_utc": _utc_now(),
|
||||
"blind_gate_eligible": False,
|
||||
"artifacts": [
|
||||
_artifact(
|
||||
staging / E41_EVALUATION_NAME,
|
||||
"visible-engineering-contract-evaluation",
|
||||
)
|
||||
],
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
_write_json(staging / E41_PACKAGE_MANIFEST_NAME, manifest)
|
||||
os.replace(staging, destination)
|
||||
except BaseException:
|
||||
shutil.rmtree(staging, ignore_errors=True)
|
||||
raise
|
||||
return read_e41_visible_evaluation(destination)
|
||||
|
||||
|
||||
def read_e41_visible_evaluation(root: Path) -> E41VisibleEvaluation:
|
||||
"""Read and validate one immutable visible engineering evaluation."""
|
||||
|
||||
resolved = root.resolve(strict=True)
|
||||
manifest = _read_json(resolved / E41_PACKAGE_MANIFEST_NAME)
|
||||
identity = _object(manifest.get("identity"), "E41 evaluation identity")
|
||||
identity_sha256 = manifest.get("identity_sha256")
|
||||
if (
|
||||
manifest.get("schema_version") != E41_VISIBLE_EVALUATION_SCHEMA
|
||||
or not isinstance(identity_sha256, str)
|
||||
or hashlib.sha256(_canonical_json(identity)).hexdigest() != identity_sha256
|
||||
or manifest.get("result_id") != f"e41-visible-evaluation-{identity_sha256}"
|
||||
or resolved.name != manifest.get("result_id")
|
||||
or identity.get("evaluation_semantics")
|
||||
!= "historical-evaluated-visible-validation"
|
||||
or manifest.get("blind_gate_eligible") is not False
|
||||
or manifest.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 visible evaluation identity is invalid")
|
||||
_validate_single_artifact(
|
||||
resolved,
|
||||
manifest.get("artifacts"),
|
||||
name=E41_EVALUATION_NAME,
|
||||
role="visible-engineering-contract-evaluation",
|
||||
)
|
||||
document = _read_json(resolved / E41_EVALUATION_NAME)
|
||||
evaluation = _object(document.get("evaluation"), "E41 visible evaluation")
|
||||
if (
|
||||
document.get("schema_version") != E41_VISIBLE_EVALUATION_SCHEMA
|
||||
or document.get("result_id") != resolved.name
|
||||
or document.get("identity_sha256") != identity_sha256
|
||||
or document.get("decision", {}).get("blind_gate_eligible") is not False
|
||||
or hashlib.sha256(_canonical_json(evaluation)).hexdigest()
|
||||
!= identity.get("evaluation_content_sha256")
|
||||
or document.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 visible evaluation content is invalid")
|
||||
return E41VisibleEvaluation(
|
||||
result_id=resolved.name,
|
||||
result_root=resolved,
|
||||
manifest=manifest,
|
||||
evaluation=document,
|
||||
)
|
||||
|
||||
|
||||
def predict_from_frozen_e40_model(
|
||||
*,
|
||||
items: list[dict[str, Any]],
|
||||
feature_names: list[str],
|
||||
feature_matrix: np.ndarray[Any, Any],
|
||||
model: dict[str, Any],
|
||||
) -> list[dict[str, Any]]:
|
||||
"""Predict from frozen weights without accepting reference labels."""
|
||||
|
||||
_assert_truth_free(items, "E41 predictor items")
|
||||
_validate_frozen_model(model, feature_names)
|
||||
if feature_matrix.shape != (len(items), len(feature_names)):
|
||||
raise E41EvaluationBoundaryError("E41 predictor feature accounting changed")
|
||||
classifier = _object(model.get("classifier"), "E40 frozen classifier")
|
||||
scaler = _object(classifier.get("scaler"), "E40 frozen scaler")
|
||||
median = np.asarray(scaler["median"], dtype=np.float64)
|
||||
scale = np.asarray(scaler["scale"], dtype=np.float64)
|
||||
weights = np.asarray(classifier["weights"], dtype=np.float64)
|
||||
clip = float(model["robust_clip"])
|
||||
predictions = []
|
||||
for index, (item, features) in enumerate(zip(items, feature_matrix, strict=True)):
|
||||
if item.get("sequence") != index:
|
||||
raise E41EvaluationBoundaryError("E41 predictor item order changed")
|
||||
stratum = str(item.get("source_stratum"))
|
||||
presence, confidence = _predict_product_presence(
|
||||
stratum=stratum,
|
||||
features=np.asarray(features, dtype=np.float64),
|
||||
median=median,
|
||||
scale=scale,
|
||||
weights=weights,
|
||||
clip=clip,
|
||||
)
|
||||
predictions.append(
|
||||
{
|
||||
"schema_version": E41_PREDICTION_ROW_SCHEMA,
|
||||
"sequence": index,
|
||||
"item_id": item["item_id"],
|
||||
"source_stratum": stratum,
|
||||
"prediction": _project_dimensions(stratum, presence),
|
||||
"presence_confidence": round(confidence, 6),
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
)
|
||||
_assert_truth_free(predictions, "E41 predictions")
|
||||
return predictions
|
||||
|
||||
|
||||
def evaluate_visible_engineering_contract(
|
||||
*,
|
||||
predictions: list[dict[str, Any]],
|
||||
acceptance_rows: list[dict[str, Any]],
|
||||
targets: dict[str, Any],
|
||||
label_provenance: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
"""Join truth-free predictions to the evaluated E37 validation rows."""
|
||||
|
||||
_assert_truth_free(predictions, "E41 evaluator input predictions")
|
||||
prediction_by_id = _unique_by_item_id(predictions, "prediction")
|
||||
acceptance_by_id = _unique_by_item_id(acceptance_rows, "acceptance")
|
||||
if set(prediction_by_id) != set(acceptance_by_id):
|
||||
raise E41EvaluationBoundaryError("E41 evaluation denominator changed")
|
||||
joined: list[dict[str, Any]] = []
|
||||
for item_id, acceptance in acceptance_by_id.items():
|
||||
if acceptance.get("split") != "validation":
|
||||
continue
|
||||
prediction = prediction_by_id[item_id]
|
||||
joined.append(
|
||||
{
|
||||
"item_id": item_id,
|
||||
"source_stratum": acceptance["source_stratum"],
|
||||
"severity": acceptance["severity"],
|
||||
"prediction": prediction["prediction"],
|
||||
"reference": acceptance["reference"],
|
||||
}
|
||||
)
|
||||
if not joined:
|
||||
raise E41EvaluationBoundaryError("E41 visible evaluation slice is empty")
|
||||
dimensions = {
|
||||
dimension: _dimension_metrics(
|
||||
joined,
|
||||
dimension=dimension,
|
||||
target=float(targets[f"{dimension}_target"]),
|
||||
)
|
||||
for dimension in _DIMENSIONS
|
||||
}
|
||||
high_severity_failures = sum(
|
||||
row["severity"] == "high"
|
||||
and any(
|
||||
row["prediction"][dimension] != row["reference"][dimension]
|
||||
for dimension in _DIMENSIONS
|
||||
)
|
||||
for row in joined
|
||||
)
|
||||
false_free_claims = sum(
|
||||
value == "free"
|
||||
for row in predictions
|
||||
for value in _object(row.get("prediction"), "E41 prediction dimensions").values()
|
||||
)
|
||||
checks = {
|
||||
"presence_target_reached": dimensions["presence"]["passed"],
|
||||
"geometry_association_target_reached": dimensions["geometry_association"]["passed"],
|
||||
"freshness_target_reached": dimensions["freshness"]["passed"],
|
||||
"accounting_complete": len(joined)
|
||||
== sum(row.get("split") == "validation" for row in acceptance_rows),
|
||||
"false_free_claims_zero": false_free_claims == 0,
|
||||
"high_severity_failures_zero": high_severity_failures == 0,
|
||||
"authority_remains_diagnostic": True,
|
||||
}
|
||||
return {
|
||||
"evaluation_semantics": "historical-evaluated-visible-validation",
|
||||
"label_provenance": {
|
||||
**label_provenance,
|
||||
"independent_accuracy_authority": False,
|
||||
},
|
||||
"metrics": {
|
||||
"validation_items": len(joined),
|
||||
"terminal_outcomes": len(joined),
|
||||
"accounting_fraction": 1.0,
|
||||
"false_free_claims": false_free_claims,
|
||||
"high_severity_failures": high_severity_failures,
|
||||
"dimensions": dimensions,
|
||||
},
|
||||
"checks": checks,
|
||||
"engineering_contract_targets_reached": all(checks.values()),
|
||||
"blocking_checks": [name for name, passed in checks.items() if not passed],
|
||||
"blind_gate_eligible": False,
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
|
||||
|
||||
def _dimension_metrics(
|
||||
rows: list[dict[str, Any]],
|
||||
*,
|
||||
dimension: str,
|
||||
target: float,
|
||||
) -> dict[str, Any]:
|
||||
confusion: Counter[tuple[str, str]] = Counter()
|
||||
strata: dict[str, Counter[str]] = defaultdict(Counter)
|
||||
correct = 0
|
||||
for row in rows:
|
||||
reference = str(row["reference"][dimension])
|
||||
prediction = str(row["prediction"][dimension])
|
||||
confusion[(reference, prediction)] += 1
|
||||
matched = reference == prediction
|
||||
correct += matched
|
||||
strata[str(row["source_stratum"])]["correct" if matched else "incorrect"] += 1
|
||||
total = len(rows)
|
||||
accuracy = correct / total
|
||||
return {
|
||||
"correct": correct,
|
||||
"incorrect": total - correct,
|
||||
"total": total,
|
||||
"accuracy": round(accuracy, 6),
|
||||
"target": target,
|
||||
"passed": accuracy >= target,
|
||||
"confusion": [
|
||||
{
|
||||
"reference": reference,
|
||||
"prediction": prediction,
|
||||
"count": count,
|
||||
}
|
||||
for (reference, prediction), count in sorted(
|
||||
confusion.items(),
|
||||
key=lambda item: (-item[1], item[0]),
|
||||
)
|
||||
],
|
||||
"by_stratum": {
|
||||
stratum: {
|
||||
"correct": counts["correct"],
|
||||
"incorrect": counts["incorrect"],
|
||||
"total": sum(counts.values()),
|
||||
"accuracy": round(counts["correct"] / sum(counts.values()), 6),
|
||||
}
|
||||
for stratum, counts in sorted(strata.items())
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _validate_frozen_model(model: dict[str, Any], feature_names: list[str]) -> None:
|
||||
classifier = _object(model.get("classifier"), "E40 frozen classifier")
|
||||
scaler = _object(classifier.get("scaler"), "E40 frozen scaler")
|
||||
weights = np.asarray(classifier.get("weights"), dtype=np.float64)
|
||||
median = np.asarray(scaler.get("median"), dtype=np.float64)
|
||||
scale = np.asarray(scaler.get("scale"), dtype=np.float64)
|
||||
if (
|
||||
model.get("schema_version") != "missioncore.e40-development-product-model/v1"
|
||||
or model.get("feature_names") != feature_names
|
||||
or model.get("validation_labels_used_for_training") is not False
|
||||
or classifier.get("type") != "deterministic-softmax"
|
||||
or classifier.get("labels") != list(_LABELS)
|
||||
or weights.shape != (len(feature_names) + 1, len(_LABELS))
|
||||
or median.shape != (len(feature_names),)
|
||||
or scale.shape != (len(feature_names),)
|
||||
or not np.isfinite(weights).all()
|
||||
or not np.isfinite(median).all()
|
||||
or not np.isfinite(scale).all()
|
||||
or np.any(scale <= 0.0)
|
||||
or not isinstance(model.get("robust_clip"), int | float)
|
||||
or float(model["robust_clip"]) <= 0.0
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 frozen E40 model is invalid")
|
||||
|
||||
|
||||
def _assert_truth_free(value: object, label: str) -> None:
|
||||
if isinstance(value, dict):
|
||||
forbidden = set(value) & _PREDICTION_FORBIDDEN_KEYS
|
||||
if forbidden:
|
||||
raise E41EvaluationBoundaryError(
|
||||
f"{label} contains truth/evaluation keys: {sorted(forbidden)}"
|
||||
)
|
||||
for child in value.values():
|
||||
_assert_truth_free(child, label)
|
||||
elif isinstance(value, list):
|
||||
for child in value:
|
||||
_assert_truth_free(child, label)
|
||||
|
||||
|
||||
def _validated_runtime_identity(value: dict[str, str]) -> dict[str, str]:
|
||||
required = {"environment_lock", "numpy", "python"}
|
||||
if (
|
||||
set(value) != required
|
||||
or not all(isinstance(item, str) and item for item in value.values())
|
||||
or "@sha256:" not in value["environment_lock"]
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 runtime identity is incomplete")
|
||||
return dict(sorted(value.items()))
|
||||
|
||||
|
||||
def _unique_by_item_id(
|
||||
rows: list[dict[str, Any]],
|
||||
label: str,
|
||||
) -> dict[str, dict[str, Any]]:
|
||||
indexed: dict[str, dict[str, Any]] = {}
|
||||
for row in rows:
|
||||
item_id = row.get("item_id")
|
||||
if not isinstance(item_id, str) or not item_id or item_id in indexed:
|
||||
raise E41EvaluationBoundaryError(f"E41 {label} item identity is invalid")
|
||||
indexed[item_id] = row
|
||||
return indexed
|
||||
|
||||
|
||||
def _validate_single_artifact(
|
||||
root: Path,
|
||||
value: object,
|
||||
*,
|
||||
name: str,
|
||||
role: str,
|
||||
) -> None:
|
||||
if not isinstance(value, list) or len(value) != 1 or not isinstance(value[0], dict):
|
||||
raise E41EvaluationBoundaryError("E41 artifact catalog is invalid")
|
||||
row = value[0]
|
||||
path = root / name
|
||||
if (
|
||||
row.get("path") != name
|
||||
or row.get("role") != role
|
||||
or not path.is_file()
|
||||
or path.is_symlink()
|
||||
or row.get("byte_length") != path.stat().st_size
|
||||
or row.get("sha256") != _sha256(path)
|
||||
):
|
||||
raise E41EvaluationBoundaryError("E41 artifact content changed")
|
||||
|
||||
|
||||
def _npz_payload(item_ids: list[str], matrix: np.ndarray[Any, Any]) -> bytes:
|
||||
import io
|
||||
|
||||
stream = io.BytesIO()
|
||||
np.savez_compressed(
|
||||
stream,
|
||||
item_ids=np.asarray(item_ids, dtype=f"<U{max(map(len, item_ids))}"),
|
||||
features=np.asarray(matrix, dtype=np.float64),
|
||||
)
|
||||
return stream.getvalue()
|
||||
|
||||
|
||||
def _json_payload(value: object) -> bytes:
|
||||
return (json.dumps(value, indent=2, sort_keys=True) + "\n").encode()
|
||||
|
||||
|
||||
def _jsonl_payload(rows: list[dict[str, Any]]) -> bytes:
|
||||
return b"".join(_canonical_json(row) + b"\n" for row in rows)
|
||||
|
||||
|
||||
def _artifact(path: Path, role: str) -> dict[str, Any]:
|
||||
return {
|
||||
"path": path.name,
|
||||
"role": role,
|
||||
"byte_length": path.stat().st_size,
|
||||
"sha256": _sha256(path),
|
||||
}
|
||||
|
||||
|
||||
def _object(value: object, label: str) -> dict[str, Any]:
|
||||
if not isinstance(value, dict):
|
||||
raise E41EvaluationBoundaryError(f"{label} must be an object")
|
||||
return value
|
||||
|
||||
|
||||
def _read_json(path: Path) -> dict[str, Any]:
|
||||
value = json.loads(path.read_text(encoding="utf-8-sig"))
|
||||
if not isinstance(value, dict):
|
||||
raise E41EvaluationBoundaryError(f"JSON object expected: {path.name}")
|
||||
return value
|
||||
|
||||
|
||||
def _read_jsonl(path: Path) -> list[dict[str, Any]]:
|
||||
rows = [json.loads(line) for line in path.read_text(encoding="utf-8-sig").splitlines()]
|
||||
if not all(isinstance(row, dict) for row in rows):
|
||||
raise E41EvaluationBoundaryError(f"JSONL object expected: {path.name}")
|
||||
return rows
|
||||
|
||||
|
||||
def _write_json(path: Path, value: object) -> None:
|
||||
with path.open("x", encoding="utf-8", newline="\n") as stream:
|
||||
json.dump(value, stream, indent=2, sort_keys=True)
|
||||
stream.write("\n")
|
||||
stream.flush()
|
||||
os.fsync(stream.fileno())
|
||||
|
||||
|
||||
def _write_jsonl(path: Path, rows: list[dict[str, Any]]) -> None:
|
||||
with path.open("xb") as stream:
|
||||
for row in rows:
|
||||
stream.write(_canonical_json(row))
|
||||
stream.write(b"\n")
|
||||
stream.flush()
|
||||
os.fsync(stream.fileno())
|
||||
|
||||
|
||||
def _write_bytes(path: Path, value: bytes) -> None:
|
||||
with path.open("xb") as stream:
|
||||
stream.write(value)
|
||||
stream.flush()
|
||||
os.fsync(stream.fileno())
|
||||
|
||||
|
||||
def _canonical_json(value: object) -> bytes:
|
||||
return json.dumps(
|
||||
value,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
allow_nan=False,
|
||||
).encode()
|
||||
|
||||
|
||||
def _sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
while chunk := stream.read(1024 * 1024):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def _utc_now() -> str:
|
||||
return datetime.now(UTC).isoformat(timespec="milliseconds").replace("+00:00", "Z")
|
||||
@@ -0,0 +1,901 @@
|
||||
"""Deterministic methodology audit for the historical RAVNOVES00 E37-E40 chain.
|
||||
|
||||
E41 does not tune a model and does not rewrite an immutable E37 or E40 result.
|
||||
It binds the exact acceptance contract, materialization, E40 worker package and
|
||||
package-bound result, then makes split leakage, feature pressure, label
|
||||
provenance and predictor/evaluator co-location machine-readable.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import uuid
|
||||
from collections.abc import Iterable
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Final
|
||||
|
||||
import numpy as np
|
||||
|
||||
from k1link.compute.e37_acceptance_contract import (
|
||||
E37_ITEMS_NAME,
|
||||
read_e37_acceptance_contract,
|
||||
)
|
||||
from k1link.compute.e40_perception_product_gate import (
|
||||
E40_MODEL_NAME,
|
||||
E40_PREDICTIONS_NAME,
|
||||
E40_REPORT_NAME,
|
||||
read_e40_perception_product_gate,
|
||||
)
|
||||
|
||||
E41_PROFILE_SCHEMA: Final = "missioncore.e41-methodology-audit-profile/v1"
|
||||
E41_RESULT_SCHEMA: Final = "missioncore.e41-methodology-audit/v1"
|
||||
E41_REPORT_SCHEMA: Final = "missioncore.e41-methodology-audit-report/v1"
|
||||
|
||||
E41_REPORT_NAME: Final = "methodology-audit.json"
|
||||
E41_SUMMARY_NAME: Final = "methodology-audit.md"
|
||||
E41_MANIFEST_NAME: Final = "manifest.json"
|
||||
|
||||
_E40_PACKAGE_SCHEMA: Final = "missioncore.e40-worker-package/v1"
|
||||
_FEATURE_CACHE_SCHEMA: Final = "missioncore.e40-feature-cache/v1"
|
||||
_FEATURE_CACHE_MANIFEST: Final = "e40-feature-cache.json"
|
||||
_FEATURE_CACHE_ARRAYS: Final = "e40-feature-vectors.npz"
|
||||
_AUTHORITY: Final = {
|
||||
"commands_enabled": False,
|
||||
"navigation_or_safety_accepted": False,
|
||||
}
|
||||
_SOURCE_DERIVED_PREFIXES: Final = (
|
||||
"association=",
|
||||
"camera_motion=",
|
||||
"geometry=",
|
||||
"label=",
|
||||
"motion=",
|
||||
"reason=",
|
||||
"semantic_current=",
|
||||
"stratum=",
|
||||
)
|
||||
_SOURCE_DERIVED_NAMES: Final = frozenset(
|
||||
{
|
||||
"detector_score",
|
||||
"score",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class E41MethodologyAuditError(RuntimeError):
|
||||
"""An E41 input, policy profile, analysis, or immutable result is invalid."""
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class E41MethodologyAudit:
|
||||
result_id: str
|
||||
result_root: Path
|
||||
manifest: dict[str, Any]
|
||||
report: dict[str, Any]
|
||||
|
||||
@property
|
||||
def blind_gate_eligible(self) -> bool:
|
||||
return self.report.get("decision", {}).get("blind_gate_eligible") is True
|
||||
|
||||
|
||||
def build_e41_methodology_audit(
|
||||
*,
|
||||
acceptance_root: Path,
|
||||
materialization_root: Path,
|
||||
e40_package_root: Path,
|
||||
e40_result_root: Path,
|
||||
profile_path: Path,
|
||||
output_root: Path,
|
||||
) -> E41MethodologyAudit:
|
||||
"""Build or validate one immutable, source-scoped E41 methodology audit."""
|
||||
|
||||
profile_file = profile_path.resolve(strict=True)
|
||||
profile = _read_json(profile_file)
|
||||
_validate_profile(profile)
|
||||
acceptance = read_e37_acceptance_contract(acceptance_root)
|
||||
materialization = materialization_root.resolve(strict=True)
|
||||
e40_result = read_e40_perception_product_gate(e40_result_root)
|
||||
package, package_artifacts = _validate_e40_package(e40_package_root)
|
||||
source = _object(profile.get("source"), "E41 profile source")
|
||||
if (
|
||||
acceptance.result_id != source.get("acceptance_result_id")
|
||||
or materialization.name != source.get("materialization_id")
|
||||
or e40_result.result_id != source.get("e40_result_id")
|
||||
or package.get("package_id") != source.get("e40_package_id")
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 source identity changed")
|
||||
execution_package = _object(
|
||||
_object(e40_result.report.get("execution"), "E40 execution").get("package"),
|
||||
"E40 execution package",
|
||||
)
|
||||
if (
|
||||
execution_package.get("mode") != "verified-worker-package"
|
||||
or execution_package.get("package_id") != package["package_id"]
|
||||
or execution_package.get("identity_sha256") != package["identity_sha256"]
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 requires the package-bound E40 result")
|
||||
|
||||
acceptance_rows = _read_jsonl(acceptance.result_root / E37_ITEMS_NAME)
|
||||
materialization_rows = _read_jsonl(materialization / "materialized-items.jsonl")
|
||||
materialization_manifest = _read_json(materialization / "manifest.json")
|
||||
reviewed_binding = _object(
|
||||
_object(acceptance.manifest.get("identity"), "E37 identity").get(
|
||||
"reviewed_substrate"
|
||||
),
|
||||
"E37 reviewed substrate",
|
||||
)
|
||||
if (
|
||||
len(acceptance_rows) != 486
|
||||
or len(materialization_rows) != 486
|
||||
or materialization_manifest.get("result_id") != materialization.name
|
||||
or reviewed_binding.get("materialization_id") != materialization.name
|
||||
or reviewed_binding.get("materialization_identity_sha256")
|
||||
!= materialization_manifest.get("identity_sha256")
|
||||
or reviewed_binding.get("materialization_index_sha256")
|
||||
!= _sha256(materialization / "materialized-items.jsonl")
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 materialization binding changed")
|
||||
|
||||
feature_root = (
|
||||
e40_package_root.resolve(strict=True)
|
||||
/ "input"
|
||||
/ "materialization"
|
||||
/ materialization.name
|
||||
)
|
||||
item_ids, feature_names, feature_matrix, feature_binding = _load_feature_cache(
|
||||
feature_root,
|
||||
package_artifacts=package_artifacts,
|
||||
)
|
||||
predictions = _read_jsonl(e40_result.result_root / E40_PREDICTIONS_NAME)
|
||||
model = _read_json(e40_result.result_root / E40_MODEL_NAME)
|
||||
historical_report = _read_json(e40_result.result_root / E40_REPORT_NAME)
|
||||
analysis = analyze_e41_methodology(
|
||||
acceptance_rows=acceptance_rows,
|
||||
materialization_rows=materialization_rows,
|
||||
feature_item_ids=item_ids,
|
||||
feature_names=feature_names,
|
||||
feature_matrix=feature_matrix,
|
||||
e40_model=model,
|
||||
e40_report=historical_report,
|
||||
e40_predictions=predictions,
|
||||
label_provenance=_object(
|
||||
acceptance.contract.get("label_provenance"),
|
||||
"E37 label provenance",
|
||||
),
|
||||
time_block_frames=int(profile["policy"]["time_block_frames"]),
|
||||
forbidden_feature_tokens=tuple(profile["policy"]["forbidden_feature_tokens"]),
|
||||
)
|
||||
analysis_sha256 = hashlib.sha256(_canonical_json(analysis)).hexdigest()
|
||||
identity = {
|
||||
"schema_version": E41_RESULT_SCHEMA,
|
||||
"source": {
|
||||
"acceptance_result_id": acceptance.result_id,
|
||||
"acceptance_identity_sha256": acceptance.manifest["identity_sha256"],
|
||||
"acceptance_items_sha256": _sha256(acceptance.result_root / E37_ITEMS_NAME),
|
||||
"materialization_id": materialization.name,
|
||||
"materialization_identity_sha256": materialization_manifest["identity_sha256"],
|
||||
"materialization_index_sha256": _sha256(
|
||||
materialization / "materialized-items.jsonl"
|
||||
),
|
||||
"e40_package_id": package["package_id"],
|
||||
"e40_package_identity_sha256": package["identity_sha256"],
|
||||
"e40_result_id": e40_result.result_id,
|
||||
"e40_result_identity_sha256": e40_result.manifest["identity_sha256"],
|
||||
"feature_cache": feature_binding,
|
||||
},
|
||||
"profile": {
|
||||
"profile_id": profile["profile_id"],
|
||||
"sha256": _sha256(profile_file),
|
||||
},
|
||||
"producer_sha256": _sha256(Path(__file__).resolve(strict=True)),
|
||||
"analysis_sha256": analysis_sha256,
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
|
||||
result_id = f"e41-methodology-audit-{identity_sha256}"
|
||||
destination = output_root.expanduser().absolute() / result_id
|
||||
if destination.exists():
|
||||
return read_e41_methodology_audit(destination)
|
||||
|
||||
report = {
|
||||
"schema_version": E41_REPORT_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"status": "completed-methodology-audit",
|
||||
"evaluation_semantics": "historical-evaluated-visible-validation",
|
||||
"analysis": analysis,
|
||||
"decision": {
|
||||
"blind_gate_eligible": analysis["policy"]["blind_gate_eligible"],
|
||||
"current_146_items": "historical-evaluated-visible-validation",
|
||||
"current_e40_result": "source-scoped-engineering-contract-evaluation",
|
||||
"independent_perception_accuracy_proved": False,
|
||||
"next_gate": (
|
||||
"separate predictor/evaluator and prepare a grouped independent truth island"
|
||||
),
|
||||
},
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
summary = _markdown_summary(report)
|
||||
|
||||
destination.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
staging = destination.parent / f".{result_id}.{uuid.uuid4().hex}.tmp"
|
||||
staging.mkdir(mode=0o700, exist_ok=False)
|
||||
try:
|
||||
_write_json(staging / E41_REPORT_NAME, report)
|
||||
_write_text(staging / E41_SUMMARY_NAME, summary)
|
||||
artifacts = [
|
||||
_artifact(staging / E41_REPORT_NAME, "machine-readable-methodology-audit"),
|
||||
_artifact(staging / E41_SUMMARY_NAME, "human-readable-methodology-summary"),
|
||||
]
|
||||
manifest = {
|
||||
"schema_version": E41_RESULT_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"identity": identity,
|
||||
"created_at_utc": _utc_now(),
|
||||
"acceptance_state": "methodology-blocked-for-blind-gate",
|
||||
"blind_gate_eligible": False,
|
||||
"artifacts": artifacts,
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
_write_json(staging / E41_MANIFEST_NAME, manifest)
|
||||
os.replace(staging, destination)
|
||||
except BaseException:
|
||||
shutil.rmtree(staging, ignore_errors=True)
|
||||
raise
|
||||
return read_e41_methodology_audit(destination)
|
||||
|
||||
|
||||
def read_e41_methodology_audit(root: Path) -> E41MethodologyAudit:
|
||||
"""Read and validate one immutable E41 methodology audit."""
|
||||
|
||||
resolved = root.resolve(strict=True)
|
||||
manifest = _read_json(resolved / E41_MANIFEST_NAME)
|
||||
identity = manifest.get("identity")
|
||||
identity_sha256 = manifest.get("identity_sha256")
|
||||
if (
|
||||
manifest.get("schema_version") != E41_RESULT_SCHEMA
|
||||
or not isinstance(identity, dict)
|
||||
or not isinstance(identity_sha256, str)
|
||||
or hashlib.sha256(_canonical_json(identity)).hexdigest() != identity_sha256
|
||||
or manifest.get("result_id") != f"e41-methodology-audit-{identity_sha256}"
|
||||
or resolved.name != manifest.get("result_id")
|
||||
or manifest.get("acceptance_state") != "methodology-blocked-for-blind-gate"
|
||||
or manifest.get("blind_gate_eligible") is not False
|
||||
or manifest.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 result identity is invalid")
|
||||
expected = {
|
||||
E41_REPORT_NAME: "machine-readable-methodology-audit",
|
||||
E41_SUMMARY_NAME: "human-readable-methodology-summary",
|
||||
}
|
||||
_validate_artifacts(resolved, manifest.get("artifacts"), expected)
|
||||
report = _read_json(resolved / E41_REPORT_NAME)
|
||||
analysis = _object(report.get("analysis"), "E41 report analysis")
|
||||
if (
|
||||
report.get("schema_version") != E41_REPORT_SCHEMA
|
||||
or report.get("result_id") != resolved.name
|
||||
or report.get("identity_sha256") != identity_sha256
|
||||
or hashlib.sha256(_canonical_json(analysis)).hexdigest()
|
||||
!= identity.get("analysis_sha256")
|
||||
or report.get("decision", {}).get("blind_gate_eligible") is not False
|
||||
or report.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 report is invalid")
|
||||
return E41MethodologyAudit(
|
||||
result_id=resolved.name,
|
||||
result_root=resolved,
|
||||
manifest=manifest,
|
||||
report=report,
|
||||
)
|
||||
|
||||
|
||||
def analyze_e41_methodology(
|
||||
*,
|
||||
acceptance_rows: list[dict[str, Any]],
|
||||
materialization_rows: list[dict[str, Any]],
|
||||
feature_item_ids: list[str],
|
||||
feature_names: list[str],
|
||||
feature_matrix: np.ndarray[Any, Any],
|
||||
e40_model: dict[str, Any],
|
||||
e40_report: dict[str, Any],
|
||||
e40_predictions: list[dict[str, Any]],
|
||||
label_provenance: dict[str, Any],
|
||||
time_block_frames: int,
|
||||
forbidden_feature_tokens: tuple[str, ...],
|
||||
) -> dict[str, Any]:
|
||||
"""Return the deterministic E41 analysis for exact in-memory inputs."""
|
||||
|
||||
if time_block_frames <= 0 or not forbidden_feature_tokens:
|
||||
raise E41MethodologyAuditError("E41 methodology policy is invalid")
|
||||
acceptance_by_id = _unique_by_item_id(acceptance_rows, "acceptance")
|
||||
materialization_by_id = _unique_by_item_id(materialization_rows, "materialization")
|
||||
if (
|
||||
set(acceptance_by_id) != set(materialization_by_id)
|
||||
or len(feature_item_ids) != len(set(feature_item_ids))
|
||||
or set(feature_item_ids) != set(acceptance_by_id)
|
||||
or feature_matrix.shape != (len(feature_item_ids), len(feature_names))
|
||||
or len(feature_names) != len(set(feature_names))
|
||||
or not np.isfinite(feature_matrix).all()
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 denominator or feature accounting changed")
|
||||
ordered_acceptance = [acceptance_by_id[item_id] for item_id in feature_item_ids]
|
||||
splits = [str(row.get("split")) for row in ordered_acceptance]
|
||||
if set(splits) != {"development", "validation"}:
|
||||
raise E41MethodologyAuditError("E41 requires development and validation rows")
|
||||
|
||||
split_audit = _split_audit(
|
||||
acceptance_by_id=acceptance_by_id,
|
||||
materialization_by_id=materialization_by_id,
|
||||
time_block_frames=time_block_frames,
|
||||
)
|
||||
feature_audit = _feature_audit(
|
||||
ordered_acceptance=ordered_acceptance,
|
||||
feature_names=feature_names,
|
||||
feature_matrix=feature_matrix,
|
||||
e40_model=e40_model,
|
||||
forbidden_feature_tokens=forbidden_feature_tokens,
|
||||
)
|
||||
reference_co_located = any("reference" in row for row in e40_predictions)
|
||||
scored_co_located = any(row.get("scored") is True for row in e40_predictions)
|
||||
historical_claims = sorted(
|
||||
claim
|
||||
for claim in _strings(e40_report)
|
||||
if "sealed" in claim.lower() or "leakage-resistant-product-gate" in claim.lower()
|
||||
)
|
||||
independent_ground_truth = label_provenance.get("independent_ground_truth") is True
|
||||
overlap_detected = any(
|
||||
split_audit[key]["count"] > 0
|
||||
for key in (
|
||||
"exact_source_frames",
|
||||
"track_ids",
|
||||
"time_blocks",
|
||||
"whole_track_or_scene_groups",
|
||||
)
|
||||
)
|
||||
violations: list[str] = []
|
||||
if not independent_ground_truth:
|
||||
violations.append("labels-are-not-independent-ground-truth")
|
||||
if overlap_detected:
|
||||
violations.append("development-validation-source-groups-overlap")
|
||||
if reference_co_located or scored_co_located:
|
||||
violations.append("prediction-and-evaluation-concerns-are-co-located")
|
||||
if historical_claims:
|
||||
violations.append("historical-e40-still-contains-blind-or-product-gate-claims")
|
||||
if feature_audit["forbidden_features"]:
|
||||
violations.append("forbidden-identity-feature-detected")
|
||||
|
||||
return {
|
||||
"denominator": {
|
||||
"items": len(ordered_acceptance),
|
||||
"development_items": splits.count("development"),
|
||||
"validation_items": splits.count("validation"),
|
||||
"evaluation_semantics": "historical-evaluated-visible-validation",
|
||||
},
|
||||
"label_provenance": {
|
||||
**label_provenance,
|
||||
"accepted_semantics": "engineering-reviewed-source-scoped-substrate",
|
||||
},
|
||||
"split_leakage": split_audit,
|
||||
"features": feature_audit,
|
||||
"predictor_evaluator_boundary": {
|
||||
"prediction_rows": len(e40_predictions),
|
||||
"reference_labels_present_in_prediction_artifact": reference_co_located,
|
||||
"scoring_state_present_in_prediction_artifact": scored_co_located,
|
||||
"physically_separated": not reference_co_located and not scored_co_located,
|
||||
},
|
||||
"metric_semantics": {
|
||||
"dimension_projection": e40_model.get("dimension_projection"),
|
||||
"dimensions_independently_inferred": False,
|
||||
"presence_geometry_accuracy_equal": (
|
||||
e40_report.get("metrics", {})
|
||||
.get("dimensions", {})
|
||||
.get("presence", {})
|
||||
.get("accuracy")
|
||||
== e40_report.get("metrics", {})
|
||||
.get("dimensions", {})
|
||||
.get("geometry_association", {})
|
||||
.get("accuracy")
|
||||
),
|
||||
},
|
||||
"historical_claims_requiring_status_correction": historical_claims,
|
||||
"policy": {
|
||||
"blind_gate_eligible": not violations,
|
||||
"violations": violations,
|
||||
"required_next_actions": [
|
||||
"treat-current-146-as-visible-validation",
|
||||
"separate-prediction-from-evaluation-artifacts",
|
||||
"freeze-grouped-independent-truth-island-before-refinement",
|
||||
"keep-engineering-contract-and-independent-truth-metrics-separate",
|
||||
],
|
||||
},
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
|
||||
|
||||
def _split_audit(
|
||||
*,
|
||||
acceptance_by_id: dict[str, dict[str, Any]],
|
||||
materialization_by_id: dict[str, dict[str, Any]],
|
||||
time_block_frames: int,
|
||||
) -> dict[str, dict[str, Any]]:
|
||||
dimensions: dict[str, dict[str, set[str]]] = {
|
||||
"item_ids": {"development": set(), "validation": set()},
|
||||
"exact_source_frames": {"development": set(), "validation": set()},
|
||||
"track_ids": {"development": set(), "validation": set()},
|
||||
"time_blocks": {"development": set(), "validation": set()},
|
||||
"whole_track_or_scene_groups": {"development": set(), "validation": set()},
|
||||
}
|
||||
for item_id, acceptance in acceptance_by_id.items():
|
||||
split = str(acceptance.get("split"))
|
||||
if split not in {"development", "validation"}:
|
||||
raise E41MethodologyAuditError("E41 split row is invalid")
|
||||
frame_index = acceptance.get("source_frame_index")
|
||||
if not isinstance(frame_index, int) or frame_index < 0:
|
||||
raise E41MethodologyAuditError("E41 source frame is invalid")
|
||||
snapshot = _object(
|
||||
materialization_by_id[item_id].get("e29_snapshot"),
|
||||
"E41 materialization snapshot",
|
||||
)
|
||||
track_id = snapshot.get("track_id")
|
||||
frame_key = str(frame_index)
|
||||
block_key = str(frame_index // time_block_frames)
|
||||
group_key = f"track:{track_id}" if track_id is not None else f"scene:{block_key}"
|
||||
dimensions["item_ids"][split].add(item_id)
|
||||
dimensions["exact_source_frames"][split].add(frame_key)
|
||||
dimensions["time_blocks"][split].add(block_key)
|
||||
dimensions["whole_track_or_scene_groups"][split].add(group_key)
|
||||
if track_id is not None:
|
||||
dimensions["track_ids"][split].add(str(track_id))
|
||||
return {
|
||||
name: _overlap_summary(values["development"], values["validation"])
|
||||
for name, values in dimensions.items()
|
||||
}
|
||||
|
||||
|
||||
def _feature_audit(
|
||||
*,
|
||||
ordered_acceptance: list[dict[str, Any]],
|
||||
feature_names: list[str],
|
||||
feature_matrix: np.ndarray[Any, Any],
|
||||
e40_model: dict[str, Any],
|
||||
forbidden_feature_tokens: tuple[str, ...],
|
||||
) -> dict[str, Any]:
|
||||
development_indices = np.asarray(
|
||||
[
|
||||
index
|
||||
for index, row in enumerate(ordered_acceptance)
|
||||
if row.get("split") == "development"
|
||||
],
|
||||
dtype=np.int64,
|
||||
)
|
||||
validation_indices = np.asarray(
|
||||
[
|
||||
index
|
||||
for index, row in enumerate(ordered_acceptance)
|
||||
if row.get("split") == "validation"
|
||||
],
|
||||
dtype=np.int64,
|
||||
)
|
||||
camera_development_indices = np.asarray(
|
||||
[
|
||||
index
|
||||
for index in development_indices
|
||||
if ordered_acceptance[int(index)].get("source_stratum") == "camera-only"
|
||||
],
|
||||
dtype=np.int64,
|
||||
)
|
||||
if not len(camera_development_indices):
|
||||
raise E41MethodologyAuditError("E41 camera-only development slice is empty")
|
||||
camera_matrix = feature_matrix[camera_development_indices]
|
||||
presence_labels = [
|
||||
str(ordered_acceptance[int(index)]["reference"]["presence"])
|
||||
for index in camera_development_indices
|
||||
]
|
||||
rows: list[dict[str, Any]] = []
|
||||
forbidden_features: list[str] = []
|
||||
variable_features = 0
|
||||
source_derived_features = 0
|
||||
for column, name in enumerate(feature_names):
|
||||
values = camera_matrix[:, column]
|
||||
unique_values = int(np.unique(values).size)
|
||||
variable = unique_values > 1
|
||||
variable_features += variable
|
||||
classification = _classify_feature(name, forbidden_feature_tokens)
|
||||
source_derived_features += classification == "source-derived"
|
||||
if classification == "forbidden":
|
||||
forbidden_features.append(name)
|
||||
development_values = feature_matrix[development_indices, column]
|
||||
validation_values = feature_matrix[validation_indices, column]
|
||||
pooled_std = float(np.std(np.concatenate((development_values, validation_values))))
|
||||
standardized_shift = abs(
|
||||
float(np.mean(development_values)) - float(np.mean(validation_values))
|
||||
) / max(pooled_std, 1e-12)
|
||||
rows.append(
|
||||
{
|
||||
"name": name,
|
||||
"classification": classification,
|
||||
"camera_development_unique_values": unique_values,
|
||||
"camera_development_variable": variable,
|
||||
"camera_development_mean": _rounded_float(float(np.mean(values))),
|
||||
"camera_development_std": _rounded_float(float(np.std(values))),
|
||||
"development_validation_standardized_mean_shift": _rounded_float(
|
||||
standardized_shift
|
||||
),
|
||||
"maximum_absolute_presence_correlation": _maximum_label_correlation(
|
||||
values,
|
||||
presence_labels,
|
||||
),
|
||||
}
|
||||
)
|
||||
model_names = e40_model.get("feature_names")
|
||||
if model_names != feature_names:
|
||||
raise E41MethodologyAuditError("E41 E40 model feature schema changed")
|
||||
camera_items = int(e40_model.get("camera_only_training_items", -1))
|
||||
if camera_items != len(camera_development_indices):
|
||||
raise E41MethodologyAuditError("E41 E40 training denominator changed")
|
||||
top_shift = sorted(
|
||||
(
|
||||
{
|
||||
"name": row["name"],
|
||||
"classification": row["classification"],
|
||||
"standardized_mean_shift": row[
|
||||
"development_validation_standardized_mean_shift"
|
||||
],
|
||||
}
|
||||
for row in rows
|
||||
),
|
||||
key=lambda row: (-float(row["standardized_mean_shift"]), str(row["name"])),
|
||||
)[:12]
|
||||
return {
|
||||
"feature_dimensions": len(feature_names),
|
||||
"camera_only_training_items": camera_items,
|
||||
"camera_only_variable_features": variable_features,
|
||||
"camera_only_constant_features": len(feature_names) - variable_features,
|
||||
"camera_items_per_variable_feature": _rounded_float(
|
||||
camera_items / max(1, variable_features)
|
||||
),
|
||||
"source_derived_feature_count": source_derived_features,
|
||||
"forbidden_features": forbidden_features,
|
||||
"top_development_validation_shifts": top_shift,
|
||||
"registry": rows,
|
||||
}
|
||||
|
||||
|
||||
def _classify_feature(name: str, forbidden_feature_tokens: tuple[str, ...]) -> str:
|
||||
lowered = name.lower()
|
||||
if any(token.lower() in lowered for token in forbidden_feature_tokens):
|
||||
return "forbidden"
|
||||
if name in _SOURCE_DERIVED_NAMES or name.startswith(_SOURCE_DERIVED_PREFIXES):
|
||||
return "source-derived"
|
||||
return "physical-observation"
|
||||
|
||||
|
||||
def _maximum_label_correlation(values: np.ndarray[Any, Any], labels: list[str]) -> float | None:
|
||||
if len(values) < 2 or float(np.std(values)) <= 1e-12:
|
||||
return None
|
||||
maximum = 0.0
|
||||
for label in sorted(set(labels)):
|
||||
target = np.asarray([value == label for value in labels], dtype=np.float64)
|
||||
if float(np.std(target)) <= 1e-12:
|
||||
continue
|
||||
correlation = float(np.corrcoef(values, target)[0, 1])
|
||||
if np.isfinite(correlation):
|
||||
maximum = max(maximum, abs(correlation))
|
||||
return _rounded_float(maximum)
|
||||
|
||||
|
||||
def _overlap_summary(development: set[str], validation: set[str]) -> dict[str, Any]:
|
||||
overlap = sorted(development & validation, key=_natural_key)
|
||||
return {
|
||||
"development_unique": len(development),
|
||||
"validation_unique": len(validation),
|
||||
"count": len(overlap),
|
||||
"sample": overlap[:20],
|
||||
}
|
||||
|
||||
|
||||
def _natural_key(value: str) -> tuple[int, int | str]:
|
||||
try:
|
||||
return (0, int(value))
|
||||
except ValueError:
|
||||
return (1, value)
|
||||
|
||||
|
||||
def _unique_by_item_id(
|
||||
rows: list[dict[str, Any]],
|
||||
label: str,
|
||||
) -> dict[str, dict[str, Any]]:
|
||||
indexed: dict[str, dict[str, Any]] = {}
|
||||
for row in rows:
|
||||
item_id = row.get("item_id")
|
||||
if not isinstance(item_id, str) or not item_id or item_id in indexed:
|
||||
raise E41MethodologyAuditError(f"E41 {label} item identity is invalid")
|
||||
indexed[item_id] = row
|
||||
return indexed
|
||||
|
||||
|
||||
def _validate_e40_package(root: Path) -> tuple[dict[str, Any], dict[str, dict[str, Any]]]:
|
||||
resolved = root.resolve(strict=True)
|
||||
manifest = _read_json(resolved / "manifest.json")
|
||||
identity = _object(manifest.get("identity"), "E40 package identity")
|
||||
identity_sha256 = manifest.get("identity_sha256")
|
||||
if (
|
||||
manifest.get("schema_version") != _E40_PACKAGE_SCHEMA
|
||||
or not isinstance(identity_sha256, str)
|
||||
or hashlib.sha256(_canonical_json(identity)).hexdigest() != identity_sha256
|
||||
or manifest.get("package_id") != f"e40-worker-package-{identity_sha256}"
|
||||
or resolved.name != manifest.get("package_id")
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 E40 package identity is invalid")
|
||||
artifacts = manifest.get("artifacts")
|
||||
if not isinstance(artifacts, list):
|
||||
raise E41MethodologyAuditError("E41 E40 package artifact catalog is invalid")
|
||||
indexed: dict[str, dict[str, Any]] = {}
|
||||
for row in artifacts:
|
||||
if (
|
||||
not isinstance(row, dict)
|
||||
or not isinstance((relative := row.get("path")), str)
|
||||
or relative in indexed
|
||||
or Path(relative).is_absolute()
|
||||
or ".." in Path(relative).parts
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 E40 package artifact is invalid")
|
||||
path = resolved / relative
|
||||
if (
|
||||
not path.is_file()
|
||||
or path.is_symlink()
|
||||
or row.get("byte_length") != path.stat().st_size
|
||||
or row.get("sha256") != _sha256(path)
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 E40 package artifact changed")
|
||||
indexed[relative] = row
|
||||
return manifest, indexed
|
||||
|
||||
|
||||
def _load_feature_cache(
|
||||
root: Path,
|
||||
*,
|
||||
package_artifacts: dict[str, dict[str, Any]],
|
||||
) -> tuple[list[str], list[str], np.ndarray[Any, Any], dict[str, Any]]:
|
||||
manifest_path = root / _FEATURE_CACHE_MANIFEST
|
||||
arrays_path = root / _FEATURE_CACHE_ARRAYS
|
||||
relative_manifest = manifest_path.relative_to(root.parents[2]).as_posix()
|
||||
relative_arrays = arrays_path.relative_to(root.parents[2]).as_posix()
|
||||
manifest_descriptor = package_artifacts.get(relative_manifest)
|
||||
arrays_descriptor = package_artifacts.get(relative_arrays)
|
||||
if (
|
||||
manifest_descriptor is None
|
||||
or arrays_descriptor is None
|
||||
or not manifest_path.is_file()
|
||||
or not arrays_path.is_file()
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 package-bound feature cache is unavailable")
|
||||
manifest = _read_json(manifest_path)
|
||||
if (
|
||||
manifest.get("schema_version") != _FEATURE_CACHE_SCHEMA
|
||||
or manifest.get("arrays_path") != _FEATURE_CACHE_ARRAYS
|
||||
or manifest.get("arrays_byte_length") != arrays_path.stat().st_size
|
||||
or manifest.get("arrays_sha256") != _sha256(arrays_path)
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 feature cache binding changed")
|
||||
with np.load(arrays_path, allow_pickle=False) as arrays:
|
||||
raw_item_ids = arrays["item_ids"]
|
||||
feature_matrix = np.asarray(arrays["features"], dtype=np.float64)
|
||||
item_ids = [str(value) for value in raw_item_ids]
|
||||
feature_names = _feature_names_from_hash(
|
||||
expected_hash=str(manifest.get("feature_names_sha256")),
|
||||
dimensions=int(manifest.get("dimensions", -1)),
|
||||
)
|
||||
if (
|
||||
len(item_ids) != int(manifest.get("items", -1))
|
||||
or feature_matrix.shape != (len(item_ids), len(feature_names))
|
||||
or not np.isfinite(feature_matrix).all()
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 feature cache arrays are invalid")
|
||||
return item_ids, feature_names, feature_matrix, {
|
||||
"manifest_sha256": str(manifest_descriptor["sha256"]),
|
||||
"arrays_sha256": str(arrays_descriptor["sha256"]),
|
||||
"feature_names_sha256": str(manifest["feature_names_sha256"]),
|
||||
"items": len(item_ids),
|
||||
"dimensions": len(feature_names),
|
||||
}
|
||||
|
||||
|
||||
def _feature_names_from_hash(*, expected_hash: str, dimensions: int) -> list[str]:
|
||||
from k1link.compute.e40_perception_product_gate import _feature_names
|
||||
|
||||
names = _feature_names()
|
||||
if (
|
||||
len(names) != dimensions
|
||||
or hashlib.sha256(_canonical_json(names)).hexdigest() != expected_hash
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 feature-name identity changed")
|
||||
return names
|
||||
|
||||
|
||||
def _validate_profile(profile: dict[str, Any]) -> None:
|
||||
source = _object(profile.get("source"), "E41 source")
|
||||
policy = _object(profile.get("policy"), "E41 policy")
|
||||
tokens = policy.get("forbidden_feature_tokens")
|
||||
if (
|
||||
profile.get("schema_version") != E41_PROFILE_SCHEMA
|
||||
or profile.get("profile_id") != "e41-ravnoves00-methodology-audit/v1"
|
||||
or not all(
|
||||
isinstance(source.get(name), str) and source.get(name)
|
||||
for name in (
|
||||
"acceptance_result_id",
|
||||
"materialization_id",
|
||||
"e40_package_id",
|
||||
"e40_result_id",
|
||||
)
|
||||
)
|
||||
or not isinstance(policy.get("time_block_frames"), int)
|
||||
or int(policy["time_block_frames"]) <= 0
|
||||
or not isinstance(tokens, list)
|
||||
or not tokens
|
||||
or not all(isinstance(token, str) and token for token in tokens)
|
||||
or policy.get("current_validation_semantics")
|
||||
!= "historical-evaluated-visible-validation"
|
||||
or policy.get("independent_truth_required_for_blind") is not True
|
||||
or policy.get("predictor_truth_separation_required") is not True
|
||||
or profile.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 profile is invalid")
|
||||
|
||||
|
||||
def _validate_artifacts(
|
||||
root: Path,
|
||||
value: object,
|
||||
expected: dict[str, str],
|
||||
) -> None:
|
||||
if not isinstance(value, list) or len(value) != len(expected):
|
||||
raise E41MethodologyAuditError("E41 artifact catalog is invalid")
|
||||
observed: set[str] = set()
|
||||
for row in value:
|
||||
if not isinstance(row, dict):
|
||||
raise E41MethodologyAuditError("E41 artifact descriptor is invalid")
|
||||
name = row.get("path")
|
||||
path = root / str(name)
|
||||
if (
|
||||
not isinstance(name, str)
|
||||
or name in observed
|
||||
or expected.get(name) != row.get("role")
|
||||
or not path.is_file()
|
||||
or path.is_symlink()
|
||||
or row.get("byte_length") != path.stat().st_size
|
||||
or row.get("sha256") != _sha256(path)
|
||||
):
|
||||
raise E41MethodologyAuditError("E41 artifact content changed")
|
||||
observed.add(name)
|
||||
if observed != set(expected):
|
||||
raise E41MethodologyAuditError("E41 artifact coverage changed")
|
||||
|
||||
|
||||
def _markdown_summary(report: dict[str, Any]) -> str:
|
||||
analysis = report["analysis"]
|
||||
split = analysis["split_leakage"]
|
||||
features = analysis["features"]
|
||||
violations = analysis["policy"]["violations"]
|
||||
lines = [
|
||||
"# E41 methodology audit",
|
||||
"",
|
||||
"Current evaluation semantics: `historical-evaluated-visible-validation`.",
|
||||
"",
|
||||
"## Decision",
|
||||
"",
|
||||
"The current E37/E40 chain is not eligible for a blind or independent product gate.",
|
||||
"",
|
||||
"## Measured split overlap",
|
||||
"",
|
||||
f"- Exact source frames: {split['exact_source_frames']['count']}",
|
||||
f"- Track IDs: {split['track_ids']['count']}",
|
||||
f"- {analysis['denominator']['validation_items']} validation items are already evaluated.",
|
||||
f"- Time blocks: {split['time_blocks']['count']}",
|
||||
(
|
||||
"- Whole-track-or-scene groups: "
|
||||
f"{split['whole_track_or_scene_groups']['count']}"
|
||||
),
|
||||
"",
|
||||
"## Feature pressure",
|
||||
"",
|
||||
f"- Total features: {features['feature_dimensions']}",
|
||||
f"- Camera-only development items: {features['camera_only_training_items']}",
|
||||
f"- Variable camera-only features: {features['camera_only_variable_features']}",
|
||||
(
|
||||
"- Camera items per variable feature: "
|
||||
f"{features['camera_items_per_variable_feature']}"
|
||||
),
|
||||
"",
|
||||
"## Blocking methodology violations",
|
||||
"",
|
||||
*[f"- `{violation}`" for violation in violations],
|
||||
"",
|
||||
"No navigation, command, safety, cross-route, or independent-truth authority is granted.",
|
||||
"",
|
||||
]
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _strings(value: object) -> Iterable[str]:
|
||||
if isinstance(value, str):
|
||||
yield value
|
||||
elif isinstance(value, dict):
|
||||
for item in value.values():
|
||||
yield from _strings(item)
|
||||
elif isinstance(value, list):
|
||||
for item in value:
|
||||
yield from _strings(item)
|
||||
|
||||
|
||||
def _artifact(path: Path, role: str) -> dict[str, Any]:
|
||||
return {
|
||||
"path": path.name,
|
||||
"role": role,
|
||||
"byte_length": path.stat().st_size,
|
||||
"sha256": _sha256(path),
|
||||
}
|
||||
|
||||
|
||||
def _object(value: object, label: str) -> dict[str, Any]:
|
||||
if not isinstance(value, dict):
|
||||
raise E41MethodologyAuditError(f"{label} must be an object")
|
||||
return value
|
||||
|
||||
|
||||
def _read_json(path: Path) -> dict[str, Any]:
|
||||
value = json.loads(path.read_text(encoding="utf-8-sig"))
|
||||
if not isinstance(value, dict):
|
||||
raise E41MethodologyAuditError(f"JSON object expected: {path.name}")
|
||||
return value
|
||||
|
||||
|
||||
def _read_jsonl(path: Path) -> list[dict[str, Any]]:
|
||||
rows = [json.loads(line) for line in path.read_text(encoding="utf-8-sig").splitlines()]
|
||||
if not all(isinstance(row, dict) for row in rows):
|
||||
raise E41MethodologyAuditError(f"JSONL object expected: {path.name}")
|
||||
return rows
|
||||
|
||||
|
||||
def _write_json(path: Path, value: object) -> None:
|
||||
with path.open("x", encoding="utf-8", newline="\n") as stream:
|
||||
json.dump(value, stream, indent=2, sort_keys=True)
|
||||
stream.write("\n")
|
||||
stream.flush()
|
||||
os.fsync(stream.fileno())
|
||||
|
||||
|
||||
def _write_text(path: Path, value: str) -> None:
|
||||
with path.open("x", encoding="utf-8", newline="\n") as stream:
|
||||
stream.write(value)
|
||||
stream.flush()
|
||||
os.fsync(stream.fileno())
|
||||
|
||||
|
||||
def _canonical_json(value: object) -> bytes:
|
||||
return json.dumps(
|
||||
value,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
allow_nan=False,
|
||||
).encode()
|
||||
|
||||
|
||||
def _sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
while chunk := stream.read(1024 * 1024):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def _rounded_float(value: float) -> float:
|
||||
return round(value, 9)
|
||||
|
||||
|
||||
def _utc_now() -> str:
|
||||
return datetime.now(UTC).isoformat(timespec="milliseconds").replace("+00:00", "Z")
|
||||
@@ -0,0 +1,490 @@
|
||||
"""Bounded E42 metamorphic checks over the frozen predictor and PointSlab.
|
||||
|
||||
The suite distinguishes invariance from sensitivity. It proves predictor
|
||||
independence from item naming, row ordering and chunk boundaries, and verifies
|
||||
PointSlab row-order invariance plus explicit SE(3) coordinate equivariance. It
|
||||
does not claim raw-sensor producer invariance or cross-route generalization.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Final
|
||||
|
||||
import numpy as np
|
||||
|
||||
from k1link.compute.e32_track_geometry_replay import (
|
||||
e32_track_geometry_frame,
|
||||
read_e32_track_geometry_replay,
|
||||
)
|
||||
from k1link.compute.e41_evaluation_boundary import (
|
||||
E41_FEATURE_ARRAYS_NAME,
|
||||
E41_FEATURE_MANIFEST_NAME,
|
||||
E41_ITEMS_NAME,
|
||||
E41_MODEL_NAME,
|
||||
predict_from_frozen_e40_model,
|
||||
validate_e41_predictor_package,
|
||||
)
|
||||
from k1link.compute.track_geometry import PointSlab
|
||||
|
||||
E42_RESULT_SCHEMA: Final = "missioncore.e42-metamorphic-suite/v1"
|
||||
E42_REPORT_SCHEMA: Final = "missioncore.e42-metamorphic-report/v1"
|
||||
E42_REPORT_NAME: Final = "metamorphic-report.json"
|
||||
E42_MANIFEST_NAME: Final = "manifest.json"
|
||||
|
||||
_AUTHORITY: Final = {
|
||||
"commands_enabled": False,
|
||||
"navigation_or_safety_accepted": False,
|
||||
}
|
||||
|
||||
|
||||
class E42MetamorphicSuiteError(RuntimeError):
|
||||
"""An E42 source, metamorphic check, or immutable result is invalid."""
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class E42MetamorphicSuite:
|
||||
result_id: str
|
||||
result_root: Path
|
||||
manifest: dict[str, Any]
|
||||
report: dict[str, Any]
|
||||
|
||||
@property
|
||||
def accepted(self) -> bool:
|
||||
return self.report.get("acceptance", {}).get("accepted") is True
|
||||
|
||||
|
||||
def build_e42_metamorphic_suite(
|
||||
*,
|
||||
predictor_package_root: Path,
|
||||
e32_result_root: Path,
|
||||
output_root: Path,
|
||||
) -> E42MetamorphicSuite:
|
||||
"""Run and seal one bounded E42 metamorphic suite."""
|
||||
|
||||
predictor_package = validate_e41_predictor_package(predictor_package_root)
|
||||
package_root = predictor_package_root.resolve(strict=True)
|
||||
e32 = read_e32_track_geometry_replay(e32_result_root)
|
||||
items = _read_jsonl(package_root / E41_ITEMS_NAME)
|
||||
model = _read_json(package_root / E41_MODEL_NAME)
|
||||
feature_manifest = _read_json(package_root / E41_FEATURE_MANIFEST_NAME)
|
||||
feature_names = [str(value) for value in feature_manifest["feature_names"]]
|
||||
with np.load(package_root / E41_FEATURE_ARRAYS_NAME, allow_pickle=False) as arrays:
|
||||
feature_matrix = np.asarray(arrays["features"], dtype=np.float64)
|
||||
|
||||
predictor_checks = _predictor_metamorphics(
|
||||
items=items,
|
||||
feature_names=feature_names,
|
||||
feature_matrix=feature_matrix,
|
||||
model=model,
|
||||
)
|
||||
point_slab_checks = _point_slab_metamorphics(e32)
|
||||
checks = {
|
||||
**predictor_checks,
|
||||
**point_slab_checks,
|
||||
}
|
||||
accepted = all(checks.values())
|
||||
if not accepted:
|
||||
raise E42MetamorphicSuiteError("E42 metamorphic invariant failed")
|
||||
analysis = {
|
||||
"classification": "bounded-current-source-contract-metamorphics",
|
||||
"checks": checks,
|
||||
"predictor": {
|
||||
"items": len(items),
|
||||
"feature_dimensions": len(feature_names),
|
||||
"item_identity_used_as_model_input": False,
|
||||
"path_used_as_model_input": False,
|
||||
"absolute_time_origin_used_as_model_input": False,
|
||||
"track_identity_used_as_model_input": False,
|
||||
},
|
||||
"point_slab": point_slab_checks["point_slab_details"],
|
||||
"sensitivity_not_invariance": {
|
||||
"timestamp_offset": "covered-by-e31-offset-sweep-not-claimed-invariant",
|
||||
"calibration_perturbation": "must-fail-binding-or-change-projection",
|
||||
"density_thinning": "must-reduce-evidence-never-create-free-space",
|
||||
},
|
||||
"limitations": [
|
||||
(
|
||||
"the suite proves the frozen E41 predictor boundary and one real "
|
||||
"E32 PointSlab contract, not the complete raw camera/LiDAR producer"
|
||||
),
|
||||
"no claim is made for another route, weather condition, rig, mount, or camera",
|
||||
"SE(3) is a coordinate-contract check, not a new model-quality result",
|
||||
],
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
analysis_sha256 = hashlib.sha256(_canonical_json(analysis)).hexdigest()
|
||||
identity = {
|
||||
"schema_version": E42_RESULT_SCHEMA,
|
||||
"predictor_package_id": predictor_package["package_id"],
|
||||
"predictor_package_identity_sha256": predictor_package["identity_sha256"],
|
||||
"e32_result_id": e32.result_id,
|
||||
"e32_identity_sha256": e32.manifest["identity_sha256"],
|
||||
"analysis_sha256": analysis_sha256,
|
||||
"producer_sha256": _sha256(Path(__file__).resolve(strict=True)),
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
|
||||
result_id = f"e42-metamorphic-suite-{identity_sha256}"
|
||||
destination = output_root.expanduser().absolute() / result_id
|
||||
if destination.exists():
|
||||
return read_e42_metamorphic_suite(destination)
|
||||
report = {
|
||||
"schema_version": E42_REPORT_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"status": "accepted-bounded-metamorphic-suite",
|
||||
"analysis": analysis,
|
||||
"acceptance": {
|
||||
"accepted": True,
|
||||
"checks": checks,
|
||||
},
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
destination.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
staging = destination.parent / f".{result_id}.{uuid.uuid4().hex}.tmp"
|
||||
staging.mkdir(mode=0o700, exist_ok=False)
|
||||
try:
|
||||
_write_json(staging / E42_REPORT_NAME, report)
|
||||
manifest = {
|
||||
"schema_version": E42_RESULT_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"identity": identity,
|
||||
"created_at_utc": _utc_now(),
|
||||
"acceptance_state": "accepted-bounded-metamorphic-suite",
|
||||
"artifacts": [
|
||||
_artifact(staging / E42_REPORT_NAME, "metamorphic-report"),
|
||||
],
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
_write_json(staging / E42_MANIFEST_NAME, manifest)
|
||||
os.replace(staging, destination)
|
||||
except BaseException:
|
||||
shutil.rmtree(staging, ignore_errors=True)
|
||||
raise
|
||||
return read_e42_metamorphic_suite(destination)
|
||||
|
||||
|
||||
def read_e42_metamorphic_suite(root: Path) -> E42MetamorphicSuite:
|
||||
"""Read and validate one immutable E42 result."""
|
||||
|
||||
resolved = root.resolve(strict=True)
|
||||
manifest = _read_json(resolved / E42_MANIFEST_NAME)
|
||||
identity = _object(manifest.get("identity"), "E42 identity")
|
||||
identity_sha256 = manifest.get("identity_sha256")
|
||||
if (
|
||||
manifest.get("schema_version") != E42_RESULT_SCHEMA
|
||||
or not isinstance(identity_sha256, str)
|
||||
or hashlib.sha256(_canonical_json(identity)).hexdigest() != identity_sha256
|
||||
or manifest.get("result_id") != f"e42-metamorphic-suite-{identity_sha256}"
|
||||
or resolved.name != manifest.get("result_id")
|
||||
or manifest.get("acceptance_state") != "accepted-bounded-metamorphic-suite"
|
||||
or manifest.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E42MetamorphicSuiteError("E42 result identity is invalid")
|
||||
artifacts = manifest.get("artifacts")
|
||||
report_path = resolved / E42_REPORT_NAME
|
||||
if (
|
||||
not isinstance(artifacts, list)
|
||||
or len(artifacts) != 1
|
||||
or not isinstance(artifacts[0], dict)
|
||||
or artifacts[0].get("path") != E42_REPORT_NAME
|
||||
or artifacts[0].get("role") != "metamorphic-report"
|
||||
or artifacts[0].get("byte_length") != report_path.stat().st_size
|
||||
or artifacts[0].get("sha256") != _sha256(report_path)
|
||||
):
|
||||
raise E42MetamorphicSuiteError("E42 artifact content changed")
|
||||
report = _read_json(report_path)
|
||||
analysis = _object(report.get("analysis"), "E42 analysis")
|
||||
checks = _object(
|
||||
_object(report.get("acceptance"), "E42 acceptance").get("checks"),
|
||||
"E42 checks",
|
||||
)
|
||||
if (
|
||||
report.get("schema_version") != E42_REPORT_SCHEMA
|
||||
or report.get("result_id") != resolved.name
|
||||
or report.get("identity_sha256") != identity_sha256
|
||||
or not checks
|
||||
or not all(value is True or isinstance(value, dict) for value in checks.values())
|
||||
or report.get("acceptance", {}).get("accepted") is not True
|
||||
or hashlib.sha256(_canonical_json(analysis)).hexdigest()
|
||||
!= identity.get("analysis_sha256")
|
||||
or report.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E42MetamorphicSuiteError("E42 report is invalid")
|
||||
return E42MetamorphicSuite(
|
||||
result_id=resolved.name,
|
||||
result_root=resolved,
|
||||
manifest=manifest,
|
||||
report=report,
|
||||
)
|
||||
|
||||
|
||||
def _predictor_metamorphics(
|
||||
*,
|
||||
items: list[dict[str, Any]],
|
||||
feature_names: list[str],
|
||||
feature_matrix: np.ndarray[Any, Any],
|
||||
model: dict[str, Any],
|
||||
) -> dict[str, bool]:
|
||||
baseline = predict_from_frozen_e40_model(
|
||||
items=items,
|
||||
feature_names=feature_names,
|
||||
feature_matrix=feature_matrix,
|
||||
model=model,
|
||||
)
|
||||
baseline_by_id = _prediction_by_id(baseline)
|
||||
|
||||
renamed_items = [
|
||||
{
|
||||
**item,
|
||||
"item_id": f"renamed-{index:06d}",
|
||||
}
|
||||
for index, item in enumerate(items)
|
||||
]
|
||||
renamed = predict_from_frozen_e40_model(
|
||||
items=renamed_items,
|
||||
feature_names=feature_names,
|
||||
feature_matrix=feature_matrix,
|
||||
model=model,
|
||||
)
|
||||
identity_rename_invariant = _ordered_prediction_semantics(baseline) == (
|
||||
_ordered_prediction_semantics(renamed)
|
||||
)
|
||||
|
||||
order = np.arange(len(items) - 1, -1, -1, dtype=np.int64)
|
||||
reordered_items = [
|
||||
{
|
||||
**items[int(source_index)],
|
||||
"sequence": new_index,
|
||||
}
|
||||
for new_index, source_index in enumerate(order)
|
||||
]
|
||||
reordered = predict_from_frozen_e40_model(
|
||||
items=reordered_items,
|
||||
feature_names=feature_names,
|
||||
feature_matrix=feature_matrix[order],
|
||||
model=model,
|
||||
)
|
||||
row_order_invariant = baseline_by_id == _prediction_by_id(reordered)
|
||||
|
||||
chunked: list[dict[str, Any]] = []
|
||||
chunk_sizes = (1, 7, 31, 97)
|
||||
offset = 0
|
||||
chunk_index = 0
|
||||
while offset < len(items):
|
||||
size = chunk_sizes[chunk_index % len(chunk_sizes)]
|
||||
end = min(len(items), offset + size)
|
||||
chunk_items = [
|
||||
{
|
||||
**item,
|
||||
"sequence": local_index,
|
||||
}
|
||||
for local_index, item in enumerate(items[offset:end])
|
||||
]
|
||||
chunked.extend(
|
||||
predict_from_frozen_e40_model(
|
||||
items=chunk_items,
|
||||
feature_names=feature_names,
|
||||
feature_matrix=feature_matrix[offset:end],
|
||||
model=model,
|
||||
)
|
||||
)
|
||||
offset = end
|
||||
chunk_index += 1
|
||||
chunk_boundary_invariant = baseline_by_id == _prediction_by_id(chunked)
|
||||
allowed_keys = {
|
||||
"schema_version",
|
||||
"sequence",
|
||||
"item_id",
|
||||
"source_stratum",
|
||||
}
|
||||
metadata_minimized = all(set(item) == allowed_keys for item in items)
|
||||
return {
|
||||
"predictor_item_identity_rename_invariant": identity_rename_invariant,
|
||||
"predictor_row_order_invariant": row_order_invariant,
|
||||
"predictor_chunk_boundary_invariant": chunk_boundary_invariant,
|
||||
"predictor_path_time_track_metadata_absent": metadata_minimized,
|
||||
}
|
||||
|
||||
|
||||
def _point_slab_metamorphics(e32: Any) -> dict[str, Any]:
|
||||
offsets = np.load(
|
||||
e32.result_root / "frame-point-offsets.npy",
|
||||
allow_pickle=False,
|
||||
mmap_mode="r",
|
||||
)
|
||||
sizes = np.diff(offsets)
|
||||
nonempty = np.flatnonzero(sizes > 1)
|
||||
if not len(nonempty):
|
||||
raise E42MetamorphicSuiteError("E42 E32 source has no non-empty PointSlab")
|
||||
frame_index = int(nonempty[0])
|
||||
frame = e32_track_geometry_frame(e32, frame_index)
|
||||
slab = frame.point_slab
|
||||
order = np.arange(slab.row_count - 1, -1, -1, dtype=np.int64)
|
||||
permuted = PointSlab(
|
||||
frame_index=slab.frame_index,
|
||||
source_frame_index=slab.source_frame_index,
|
||||
source_point_count=slab.source_point_count,
|
||||
coordinate_frame=slab.coordinate_frame,
|
||||
owner_keys=slab.owner_keys,
|
||||
source_indices=slab.source_indices[order],
|
||||
points_xyz_m=slab.points_xyz_m[order],
|
||||
owner_indices=slab.owner_indices[order],
|
||||
)
|
||||
row_order_invariant = _point_slab_signature(slab) == _point_slab_signature(permuted)
|
||||
|
||||
angle = np.deg2rad(90.0)
|
||||
rotation = np.asarray(
|
||||
[
|
||||
[np.cos(angle), -np.sin(angle), 0.0],
|
||||
[np.sin(angle), np.cos(angle), 0.0],
|
||||
[0.0, 0.0, 1.0],
|
||||
],
|
||||
dtype=np.float64,
|
||||
)
|
||||
translation = np.asarray([1.0, -2.0, 0.5], dtype=np.float64)
|
||||
transformed_points = (
|
||||
np.asarray(slab.points_xyz_m, dtype=np.float64) @ rotation.T + translation
|
||||
).astype("<f4")
|
||||
transformed = PointSlab(
|
||||
frame_index=slab.frame_index,
|
||||
source_frame_index=slab.source_frame_index,
|
||||
source_point_count=slab.source_point_count,
|
||||
coordinate_frame=slab.coordinate_frame,
|
||||
owner_keys=slab.owner_keys,
|
||||
source_indices=slab.source_indices,
|
||||
points_xyz_m=transformed_points,
|
||||
owner_indices=slab.owner_indices,
|
||||
)
|
||||
expected = (
|
||||
np.asarray(slab.points_xyz_m, dtype=np.float64) @ rotation.T + translation
|
||||
)
|
||||
se3_equivariant = bool(
|
||||
np.allclose(
|
||||
np.asarray(transformed.points_xyz_m, dtype=np.float64),
|
||||
expected,
|
||||
rtol=0.0,
|
||||
atol=1e-5,
|
||||
)
|
||||
and np.array_equal(transformed.source_indices, slab.source_indices)
|
||||
and np.array_equal(transformed.owner_indices, slab.owner_indices)
|
||||
and transformed.owner_keys == slab.owner_keys
|
||||
)
|
||||
details = {
|
||||
"frame_index": frame_index,
|
||||
"row_count": slab.row_count,
|
||||
"owner_count": len(slab.owner_keys),
|
||||
"coordinate_frame": slab.coordinate_frame,
|
||||
"row_permutation": "reverse",
|
||||
"se3_rotation": "z-plus-90-degrees",
|
||||
"se3_translation_m": translation.tolist(),
|
||||
}
|
||||
return {
|
||||
"point_slab_row_order_invariant": row_order_invariant,
|
||||
"point_slab_se3_coordinate_equivariant": se3_equivariant,
|
||||
"point_slab_details": details,
|
||||
}
|
||||
|
||||
|
||||
def _prediction_by_id(rows: list[dict[str, Any]]) -> dict[str, tuple[object, ...]]:
|
||||
indexed: dict[str, tuple[object, ...]] = {}
|
||||
for row in rows:
|
||||
item_id = str(row["item_id"])
|
||||
if item_id in indexed:
|
||||
raise E42MetamorphicSuiteError("E42 prediction item identity collided")
|
||||
indexed[item_id] = (
|
||||
row["source_stratum"],
|
||||
row["prediction"],
|
||||
row["presence_confidence"],
|
||||
)
|
||||
return indexed
|
||||
|
||||
|
||||
def _ordered_prediction_semantics(rows: list[dict[str, Any]]) -> list[tuple[object, ...]]:
|
||||
return [
|
||||
(
|
||||
row["source_stratum"],
|
||||
row["prediction"],
|
||||
row["presence_confidence"],
|
||||
)
|
||||
for row in rows
|
||||
]
|
||||
|
||||
|
||||
def _point_slab_signature(slab: PointSlab) -> tuple[tuple[object, ...], ...]:
|
||||
order = np.argsort(slab.source_indices, kind="stable")
|
||||
return tuple(
|
||||
(
|
||||
int(slab.source_indices[index]),
|
||||
slab.owner_keys[int(slab.owner_indices[index])],
|
||||
*(round(float(value), 6) for value in slab.points_xyz_m[index]),
|
||||
)
|
||||
for index in order
|
||||
)
|
||||
|
||||
|
||||
def _artifact(path: Path, role: str) -> dict[str, Any]:
|
||||
return {
|
||||
"path": path.name,
|
||||
"role": role,
|
||||
"byte_length": path.stat().st_size,
|
||||
"sha256": _sha256(path),
|
||||
}
|
||||
|
||||
|
||||
def _object(value: object, label: str) -> dict[str, Any]:
|
||||
if not isinstance(value, dict):
|
||||
raise E42MetamorphicSuiteError(f"{label} must be an object")
|
||||
return value
|
||||
|
||||
|
||||
def _read_json(path: Path) -> dict[str, Any]:
|
||||
value = json.loads(path.read_text(encoding="utf-8-sig"))
|
||||
if not isinstance(value, dict):
|
||||
raise E42MetamorphicSuiteError(f"JSON object expected: {path.name}")
|
||||
return value
|
||||
|
||||
|
||||
def _read_jsonl(path: Path) -> list[dict[str, Any]]:
|
||||
rows = [json.loads(line) for line in path.read_text(encoding="utf-8-sig").splitlines()]
|
||||
if not all(isinstance(row, dict) for row in rows):
|
||||
raise E42MetamorphicSuiteError(f"JSONL object expected: {path.name}")
|
||||
return rows
|
||||
|
||||
|
||||
def _write_json(path: Path, value: object) -> None:
|
||||
with path.open("x", encoding="utf-8", newline="\n") as stream:
|
||||
json.dump(value, stream, indent=2, sort_keys=True)
|
||||
stream.write("\n")
|
||||
stream.flush()
|
||||
os.fsync(stream.fileno())
|
||||
|
||||
|
||||
def _canonical_json(value: object) -> bytes:
|
||||
return json.dumps(
|
||||
value,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
allow_nan=False,
|
||||
).encode()
|
||||
|
||||
|
||||
def _sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
while chunk := stream.read(1024 * 1024):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def _utc_now() -> str:
|
||||
return datetime.now(UTC).isoformat(timespec="milliseconds").replace("+00:00", "Z")
|
||||
@@ -0,0 +1,518 @@
|
||||
"""Pre-register the next-route capture and independent truth-island protocol."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Final, cast
|
||||
|
||||
E43_PROFILE_SCHEMA: Final = "missioncore.e43-future-capture-profile/v1"
|
||||
E43_PROTOCOL_SCHEMA: Final = "missioncore.e43-future-capture-protocol/v1"
|
||||
E43_CAPTURE_MANIFEST_SCHEMA: Final = "missioncore.future-capture-manifest/v1"
|
||||
E43_CANDIDATE_SCHEMA: Final = "missioncore.future-truth-candidate/v1"
|
||||
|
||||
E43_PROTOCOL_NAME: Final = "future-capture-protocol.json"
|
||||
E43_MANIFEST_NAME: Final = "manifest.json"
|
||||
|
||||
_SHA256 = re.compile(r"^[a-f0-9]{64}$")
|
||||
_IDENTIFIER = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._:/-]{1,159}$")
|
||||
_AUTHORITY: Final = {
|
||||
"commands_enabled": False,
|
||||
"navigation_or_safety_accepted": False,
|
||||
}
|
||||
|
||||
|
||||
class E43FutureCaptureProtocolError(RuntimeError):
|
||||
"""An E43 profile, capture manifest, grouped split, or result is invalid."""
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class E43FutureCaptureProtocol:
|
||||
result_id: str
|
||||
result_root: Path
|
||||
manifest: dict[str, Any]
|
||||
protocol: dict[str, Any]
|
||||
|
||||
|
||||
def build_e43_future_capture_protocol(
|
||||
*,
|
||||
profile_path: Path,
|
||||
output_root: Path,
|
||||
) -> E43FutureCaptureProtocol:
|
||||
"""Freeze the protocol before a new physical recording exists."""
|
||||
|
||||
profile_file = profile_path.resolve(strict=True)
|
||||
profile = _read_json(profile_file)
|
||||
_validate_profile(profile)
|
||||
protocol = {
|
||||
"schema_version": E43_PROTOCOL_SCHEMA,
|
||||
"profile_id": profile["profile_id"],
|
||||
"capture_contract": profile["capture_contract"],
|
||||
"blind_truth_contract": profile["blind_truth_contract"],
|
||||
"acceptance_contract": profile["acceptance_contract"],
|
||||
"decisions_frozen_before_capture": [
|
||||
"required-streams-and-source-identities",
|
||||
"control-bridge-and-new-route-segment-policy",
|
||||
"grouped-blind-partition-algorithm-and-seed",
|
||||
"independent-human-review-requirement",
|
||||
"acceptance-thresholds-and-forbidden-authority",
|
||||
],
|
||||
"capture_exists": False,
|
||||
"labels_exist": False,
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
protocol_sha256 = hashlib.sha256(_canonical_json(protocol)).hexdigest()
|
||||
identity = {
|
||||
"schema_version": E43_PROTOCOL_SCHEMA,
|
||||
"profile_id": profile["profile_id"],
|
||||
"profile_sha256": _sha256(profile_file),
|
||||
"protocol_sha256": protocol_sha256,
|
||||
"producer_sha256": _sha256(Path(__file__).resolve(strict=True)),
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
|
||||
result_id = f"e43-future-capture-protocol-{identity_sha256}"
|
||||
destination = output_root.expanduser().absolute() / result_id
|
||||
if destination.exists():
|
||||
return read_e43_future_capture_protocol(destination)
|
||||
destination.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
staging = destination.parent / f".{result_id}.{uuid.uuid4().hex}.tmp"
|
||||
staging.mkdir(mode=0o700, exist_ok=False)
|
||||
document = {
|
||||
**protocol,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
}
|
||||
try:
|
||||
_write_json(staging / E43_PROTOCOL_NAME, document)
|
||||
manifest = {
|
||||
"schema_version": E43_PROTOCOL_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"identity": identity,
|
||||
"created_at_utc": _utc_now(),
|
||||
"acceptance_state": "accepted-pre-capture-protocol",
|
||||
"artifacts": [
|
||||
_artifact(staging / E43_PROTOCOL_NAME, "future-capture-protocol"),
|
||||
],
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
_write_json(staging / E43_MANIFEST_NAME, manifest)
|
||||
os.replace(staging, destination)
|
||||
except BaseException:
|
||||
shutil.rmtree(staging, ignore_errors=True)
|
||||
raise
|
||||
return read_e43_future_capture_protocol(destination)
|
||||
|
||||
|
||||
def read_e43_future_capture_protocol(root: Path) -> E43FutureCaptureProtocol:
|
||||
"""Read and validate one immutable pre-capture protocol."""
|
||||
|
||||
resolved = root.resolve(strict=True)
|
||||
manifest = _read_json(resolved / E43_MANIFEST_NAME)
|
||||
identity = _object(manifest.get("identity"), "E43 identity")
|
||||
identity_sha256 = manifest.get("identity_sha256")
|
||||
if (
|
||||
manifest.get("schema_version") != E43_PROTOCOL_SCHEMA
|
||||
or not isinstance(identity_sha256, str)
|
||||
or hashlib.sha256(_canonical_json(identity)).hexdigest() != identity_sha256
|
||||
or manifest.get("result_id") != f"e43-future-capture-protocol-{identity_sha256}"
|
||||
or resolved.name != manifest.get("result_id")
|
||||
or manifest.get("acceptance_state") != "accepted-pre-capture-protocol"
|
||||
or manifest.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E43FutureCaptureProtocolError("E43 protocol identity is invalid")
|
||||
artifacts = manifest.get("artifacts")
|
||||
protocol_path = resolved / E43_PROTOCOL_NAME
|
||||
if (
|
||||
not isinstance(artifacts, list)
|
||||
or len(artifacts) != 1
|
||||
or not isinstance(artifacts[0], dict)
|
||||
or artifacts[0].get("path") != E43_PROTOCOL_NAME
|
||||
or artifacts[0].get("role") != "future-capture-protocol"
|
||||
or artifacts[0].get("byte_length") != protocol_path.stat().st_size
|
||||
or artifacts[0].get("sha256") != _sha256(protocol_path)
|
||||
):
|
||||
raise E43FutureCaptureProtocolError("E43 protocol artifact changed")
|
||||
protocol = _read_json(protocol_path)
|
||||
protocol_identity_payload = dict(protocol)
|
||||
protocol_identity_payload.pop("result_id", None)
|
||||
protocol_identity_payload.pop("identity_sha256", None)
|
||||
if (
|
||||
protocol.get("schema_version") != E43_PROTOCOL_SCHEMA
|
||||
or protocol.get("result_id") != resolved.name
|
||||
or protocol.get("identity_sha256") != identity_sha256
|
||||
or protocol.get("capture_exists") is not False
|
||||
or protocol.get("labels_exist") is not False
|
||||
or hashlib.sha256(_canonical_json(protocol_identity_payload)).hexdigest()
|
||||
!= identity.get("protocol_sha256")
|
||||
or protocol.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E43FutureCaptureProtocolError("E43 protocol content is invalid")
|
||||
return E43FutureCaptureProtocol(
|
||||
result_id=resolved.name,
|
||||
result_root=resolved,
|
||||
manifest=manifest,
|
||||
protocol=protocol,
|
||||
)
|
||||
|
||||
|
||||
def validate_future_capture_manifest(
|
||||
manifest: dict[str, Any],
|
||||
*,
|
||||
protocol: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
"""Fail closed unless a future physical capture satisfies the frozen protocol."""
|
||||
|
||||
capture_contract = _object(protocol.get("capture_contract"), "E43 capture contract")
|
||||
device = _object(manifest.get("device"), "future capture device")
|
||||
capture = _object(manifest.get("capture"), "future capture facts")
|
||||
streams = _object(manifest.get("streams"), "future capture streams")
|
||||
segments = manifest.get("segments")
|
||||
if (
|
||||
manifest.get("schema_version") != E43_CAPTURE_MANIFEST_SCHEMA
|
||||
or not _identifier(manifest.get("source_session_id"))
|
||||
or not _identifier(manifest.get("source_display_name"))
|
||||
or manifest.get("operator_authorized") is not True
|
||||
or manifest.get("authority") != _AUTHORITY
|
||||
or device.get("model") != capture_contract.get("device_model")
|
||||
or not all(
|
||||
_sha256_value(device.get(name))
|
||||
for name in (
|
||||
"device_identity_sha256",
|
||||
"calibration_sha256",
|
||||
"mount_identity_sha256",
|
||||
"configuration_sha256",
|
||||
)
|
||||
)
|
||||
or not _identifier(device.get("firmware"))
|
||||
):
|
||||
raise E43FutureCaptureProtocolError("future capture identity is invalid")
|
||||
duration = capture.get("duration_seconds")
|
||||
monotonic_start = capture.get("monotonic_start_seconds")
|
||||
monotonic_end = capture.get("monotonic_end_seconds")
|
||||
if (
|
||||
not isinstance(duration, int | float)
|
||||
or isinstance(duration, bool)
|
||||
or not float(capture_contract["minimum_duration_seconds"])
|
||||
<= float(duration)
|
||||
<= float(capture_contract["maximum_duration_seconds"])
|
||||
or not isinstance(monotonic_start, int | float)
|
||||
or isinstance(monotonic_start, bool)
|
||||
or not isinstance(monotonic_end, int | float)
|
||||
or isinstance(monotonic_end, bool)
|
||||
or float(monotonic_end) <= float(monotonic_start)
|
||||
or abs((float(monotonic_end) - float(monotonic_start)) - float(duration)) > 1.0
|
||||
or not _utc_timestamp(capture.get("started_at_utc"))
|
||||
or not all(
|
||||
isinstance(capture.get(name), str) and str(capture[name]).strip()
|
||||
for name in ("weather", "illumination", "location_class", "operator_notes")
|
||||
)
|
||||
):
|
||||
raise E43FutureCaptureProtocolError("future capture bounds are invalid")
|
||||
required_streams = capture_contract.get("required_streams")
|
||||
if not isinstance(required_streams, list) or set(streams) != set(required_streams):
|
||||
raise E43FutureCaptureProtocolError("future capture stream set changed")
|
||||
for stream_id, descriptor in streams.items():
|
||||
stream = _object(descriptor, f"future capture stream {stream_id}")
|
||||
if (
|
||||
stream.get("available") is not True
|
||||
or not isinstance(stream.get("item_count"), int)
|
||||
or int(stream["item_count"]) <= 0
|
||||
or not isinstance(stream.get("byte_length"), int)
|
||||
or int(stream["byte_length"]) <= 0
|
||||
or not _sha256_value(stream.get("sha256"))
|
||||
):
|
||||
raise E43FutureCaptureProtocolError("future capture stream is incomplete")
|
||||
_validate_segments(
|
||||
segments,
|
||||
capture_contract=capture_contract,
|
||||
monotonic_start=float(monotonic_start),
|
||||
monotonic_end=float(monotonic_end),
|
||||
)
|
||||
segment_rows = cast(list[dict[str, Any]], segments)
|
||||
return {
|
||||
"accepted": True,
|
||||
"source_session_id": manifest["source_session_id"],
|
||||
"duration_seconds": float(duration),
|
||||
"required_streams": sorted(streams),
|
||||
"segments": [str(row["kind"]) for row in segment_rows],
|
||||
"blind_truth_labels_available": False,
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
|
||||
|
||||
def assign_grouped_future_partitions(
|
||||
candidates: list[dict[str, Any]],
|
||||
*,
|
||||
seed: str,
|
||||
blind_fraction: float,
|
||||
) -> dict[str, str]:
|
||||
"""Assign connected scene/track/time groups without cross-partition leakage."""
|
||||
|
||||
if not seed or not 0.1 <= blind_fraction <= 0.5 or len(candidates) < 2:
|
||||
raise E43FutureCaptureProtocolError("future grouped split policy is invalid")
|
||||
indexed: dict[str, dict[str, Any]] = {}
|
||||
parent: dict[str, str] = {}
|
||||
for row in candidates:
|
||||
item_id = row.get("item_id")
|
||||
if (
|
||||
row.get("schema_version") != E43_CANDIDATE_SCHEMA
|
||||
or not isinstance(item_id, str)
|
||||
or not item_id
|
||||
or item_id in indexed
|
||||
or not _identifier(row.get("scene_id"))
|
||||
or not _identifier(row.get("time_block_id"))
|
||||
or (
|
||||
row.get("track_id") is not None
|
||||
and not _identifier(row.get("track_id"))
|
||||
)
|
||||
or row.get("route_segment") not in {"control-bridge", "new-route"}
|
||||
):
|
||||
raise E43FutureCaptureProtocolError("future truth candidate is invalid")
|
||||
indexed[item_id] = row
|
||||
parent[item_id] = item_id
|
||||
|
||||
def find(item_id: str) -> str:
|
||||
while parent[item_id] != item_id:
|
||||
parent[item_id] = parent[parent[item_id]]
|
||||
item_id = parent[item_id]
|
||||
return item_id
|
||||
|
||||
def union(left: str, right: str) -> None:
|
||||
left_root = find(left)
|
||||
right_root = find(right)
|
||||
if left_root != right_root:
|
||||
parent[max(left_root, right_root)] = min(left_root, right_root)
|
||||
|
||||
group_owner: dict[tuple[str, str], str] = {}
|
||||
for item_id, row in indexed.items():
|
||||
group_keys = [
|
||||
("scene", str(row["scene_id"])),
|
||||
("time", str(row["time_block_id"])),
|
||||
]
|
||||
if row.get("track_id") is not None:
|
||||
group_keys.append(("track", str(row["track_id"])))
|
||||
for key in group_keys:
|
||||
prior = group_owner.get(key)
|
||||
if prior is None:
|
||||
group_owner[key] = item_id
|
||||
else:
|
||||
union(item_id, prior)
|
||||
components: dict[str, list[str]] = {}
|
||||
for item_id in indexed:
|
||||
components.setdefault(find(item_id), []).append(item_id)
|
||||
if len(components) < 2:
|
||||
raise E43FutureCaptureProtocolError(
|
||||
"future candidates collapse into one leakage-connected component"
|
||||
)
|
||||
ordered_components = sorted(
|
||||
(sorted(items) for items in components.values()),
|
||||
key=lambda items: hashlib.sha256(
|
||||
f"{seed}:{','.join(items)}".encode()
|
||||
).hexdigest(),
|
||||
)
|
||||
target = round(len(candidates) * blind_fraction)
|
||||
blind_components: list[list[str]] = []
|
||||
blind_items = 0
|
||||
for component in ordered_components:
|
||||
if blind_components and blind_items >= target:
|
||||
break
|
||||
if len(blind_components) + 1 == len(ordered_components):
|
||||
break
|
||||
blind_components.append(component)
|
||||
blind_items += len(component)
|
||||
if not blind_components:
|
||||
blind_components.append(ordered_components[0])
|
||||
blind_ids = {item_id for component in blind_components for item_id in component}
|
||||
assignments = {
|
||||
item_id: "blind-truth" if item_id in blind_ids else "visible-diagnostic"
|
||||
for item_id in indexed
|
||||
}
|
||||
if set(assignments.values()) != {"blind-truth", "visible-diagnostic"}:
|
||||
raise E43FutureCaptureProtocolError("future grouped split is degenerate")
|
||||
_verify_group_isolation(indexed, assignments)
|
||||
return assignments
|
||||
|
||||
|
||||
def _verify_group_isolation(
|
||||
candidates: dict[str, dict[str, Any]],
|
||||
assignments: dict[str, str],
|
||||
) -> None:
|
||||
observed: dict[tuple[str, str], str] = {}
|
||||
for item_id, row in candidates.items():
|
||||
partition = assignments[item_id]
|
||||
groups = [
|
||||
("scene", str(row["scene_id"])),
|
||||
("time", str(row["time_block_id"])),
|
||||
]
|
||||
if row.get("track_id") is not None:
|
||||
groups.append(("track", str(row["track_id"])))
|
||||
for group in groups:
|
||||
prior = observed.setdefault(group, partition)
|
||||
if prior != partition:
|
||||
raise E43FutureCaptureProtocolError(
|
||||
"future grouped split leaks across partitions"
|
||||
)
|
||||
|
||||
|
||||
def _validate_segments(
|
||||
value: object,
|
||||
*,
|
||||
capture_contract: dict[str, Any],
|
||||
monotonic_start: float,
|
||||
monotonic_end: float,
|
||||
) -> None:
|
||||
if not isinstance(value, list) or len(value) < 2:
|
||||
raise E43FutureCaptureProtocolError("future capture segments are missing")
|
||||
required = {
|
||||
str(row["kind"]): float(row["minimum_duration_seconds"])
|
||||
for row in capture_contract["required_segments"]
|
||||
}
|
||||
observed: dict[str, float] = {}
|
||||
intervals: list[tuple[float, float]] = []
|
||||
for row in value:
|
||||
segment = _object(row, "future capture segment")
|
||||
kind = segment.get("kind")
|
||||
start = segment.get("monotonic_start_seconds")
|
||||
end = segment.get("monotonic_end_seconds")
|
||||
if (
|
||||
kind not in required
|
||||
or kind in observed
|
||||
or not isinstance(start, int | float)
|
||||
or isinstance(start, bool)
|
||||
or not isinstance(end, int | float)
|
||||
or isinstance(end, bool)
|
||||
or not monotonic_start <= float(start) < float(end) <= monotonic_end
|
||||
or float(end) - float(start) < required[str(kind)]
|
||||
):
|
||||
raise E43FutureCaptureProtocolError("future capture segment is invalid")
|
||||
observed[str(kind)] = float(end) - float(start)
|
||||
intervals.append((float(start), float(end)))
|
||||
if set(observed) != set(required):
|
||||
raise E43FutureCaptureProtocolError("future capture segment set changed")
|
||||
intervals.sort()
|
||||
if any(
|
||||
left[1] > right[0]
|
||||
for left, right in zip(intervals, intervals[1:], strict=False)
|
||||
):
|
||||
raise E43FutureCaptureProtocolError("future capture segments overlap")
|
||||
|
||||
|
||||
def _validate_profile(profile: dict[str, Any]) -> None:
|
||||
capture = _object(profile.get("capture_contract"), "E43 capture contract")
|
||||
blind = _object(profile.get("blind_truth_contract"), "E43 blind truth contract")
|
||||
acceptance = _object(profile.get("acceptance_contract"), "E43 acceptance contract")
|
||||
required_segments = capture.get("required_segments")
|
||||
required_streams = capture.get("required_streams")
|
||||
if (
|
||||
profile.get("schema_version") != E43_PROFILE_SCHEMA
|
||||
or profile.get("profile_id") != "e43-same-k1-new-route-truth-island/v1"
|
||||
or capture.get("device_model") != "XGRIDS/LixelKity-K1"
|
||||
or not isinstance(capture.get("minimum_duration_seconds"), int)
|
||||
or not isinstance(capture.get("maximum_duration_seconds"), int)
|
||||
or int(capture["minimum_duration_seconds"])
|
||||
>= int(capture["maximum_duration_seconds"])
|
||||
or not isinstance(required_streams, list)
|
||||
or len(required_streams) < 4
|
||||
or len(required_streams) != len(set(required_streams))
|
||||
or not all(isinstance(value, str) and value for value in required_streams)
|
||||
or not isinstance(required_segments, list)
|
||||
or {row.get("kind") for row in required_segments if isinstance(row, dict)}
|
||||
!= {"control-bridge", "new-route"}
|
||||
or blind.get("partition_strategy")
|
||||
!= "connected-scene-track-time-components/v1"
|
||||
or not isinstance(blind.get("seed"), str)
|
||||
or not 0.1 <= float(blind.get("blind_fraction", 0.0)) <= 0.5
|
||||
or blind.get("independent_human_reviewers") != 2
|
||||
or blind.get("engineering_acceptance_labels_are_truth") is not False
|
||||
or acceptance.get("accounting_target") != 1.0
|
||||
or acceptance.get("maximum_false_free_claims") != 0
|
||||
or acceptance.get("maximum_high_severity_failures") != 0
|
||||
or not all(
|
||||
float(acceptance.get(name, 0.0)) == 0.9
|
||||
for name in (
|
||||
"presence_target",
|
||||
"geometry_association_target",
|
||||
"freshness_target",
|
||||
)
|
||||
)
|
||||
or profile.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E43FutureCaptureProtocolError("E43 profile is invalid")
|
||||
|
||||
|
||||
def _identifier(value: object) -> bool:
|
||||
return isinstance(value, str) and _IDENTIFIER.fullmatch(value) is not None
|
||||
|
||||
|
||||
def _sha256_value(value: object) -> bool:
|
||||
return isinstance(value, str) and _SHA256.fullmatch(value) is not None
|
||||
|
||||
|
||||
def _utc_timestamp(value: object) -> bool:
|
||||
if not isinstance(value, str) or not value.endswith("Z"):
|
||||
return False
|
||||
try:
|
||||
datetime.fromisoformat(value.replace("Z", "+00:00"))
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _artifact(path: Path, role: str) -> dict[str, Any]:
|
||||
return {
|
||||
"path": path.name,
|
||||
"role": role,
|
||||
"byte_length": path.stat().st_size,
|
||||
"sha256": _sha256(path),
|
||||
}
|
||||
|
||||
|
||||
def _object(value: object, label: str) -> dict[str, Any]:
|
||||
if not isinstance(value, dict):
|
||||
raise E43FutureCaptureProtocolError(f"{label} must be an object")
|
||||
return value
|
||||
|
||||
|
||||
def _read_json(path: Path) -> dict[str, Any]:
|
||||
value = json.loads(path.read_text(encoding="utf-8-sig"))
|
||||
if not isinstance(value, dict):
|
||||
raise E43FutureCaptureProtocolError(f"JSON object expected: {path.name}")
|
||||
return value
|
||||
|
||||
|
||||
def _write_json(path: Path, value: object) -> None:
|
||||
with path.open("x", encoding="utf-8", newline="\n") as stream:
|
||||
json.dump(value, stream, indent=2, sort_keys=True)
|
||||
stream.write("\n")
|
||||
stream.flush()
|
||||
os.fsync(stream.fileno())
|
||||
|
||||
|
||||
def _canonical_json(value: object) -> bytes:
|
||||
return json.dumps(
|
||||
value,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
allow_nan=False,
|
||||
).encode()
|
||||
|
||||
|
||||
def _sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
while chunk := stream.read(1024 * 1024):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def _utc_now() -> str:
|
||||
return datetime.now(UTC).isoformat(timespec="milliseconds").replace("+00:00", "Z")
|
||||
@@ -0,0 +1,383 @@
|
||||
"""Content-based E44 data-amplification audit for immutable LAB artifacts."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import uuid
|
||||
from collections import Counter, defaultdict
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Final
|
||||
|
||||
E44_RESULT_SCHEMA: Final = "missioncore.e44-data-amplification-audit/v1"
|
||||
E44_REPORT_SCHEMA: Final = "missioncore.e44-data-amplification-report/v1"
|
||||
E44_REPORT_NAME: Final = "data-amplification-report.json"
|
||||
E44_MANIFEST_NAME: Final = "manifest.json"
|
||||
|
||||
_LABEL = re.compile(r"^[a-z0-9][a-z0-9._-]{1,63}$")
|
||||
_AUTHORITY: Final = {
|
||||
"commands_enabled": False,
|
||||
"navigation_or_safety_accepted": False,
|
||||
}
|
||||
|
||||
|
||||
class E44DataAmplificationAuditError(RuntimeError):
|
||||
"""An E44 source catalog, measurement, or immutable result is invalid."""
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class E44DataAmplificationAudit:
|
||||
result_id: str
|
||||
result_root: Path
|
||||
manifest: dict[str, Any]
|
||||
report: dict[str, Any]
|
||||
|
||||
|
||||
def build_e44_data_amplification_audit(
|
||||
*,
|
||||
artifact_roots: dict[str, Path],
|
||||
output_root: Path,
|
||||
) -> E44DataAmplificationAudit:
|
||||
"""Measure logical bytes and exact content duplication across named roots."""
|
||||
|
||||
if len(artifact_roots) < 2:
|
||||
raise E44DataAmplificationAuditError("E44 requires at least two artifact roots")
|
||||
resolved_output = output_root.expanduser().absolute()
|
||||
resolved_roots: dict[str, Path] = {}
|
||||
for label, root in artifact_roots.items():
|
||||
if _LABEL.fullmatch(label) is None or label in resolved_roots:
|
||||
raise E44DataAmplificationAuditError("E44 artifact label is invalid")
|
||||
resolved = root.resolve(strict=True)
|
||||
if not resolved.is_dir() or resolved.is_symlink():
|
||||
raise E44DataAmplificationAuditError("E44 artifact root is invalid")
|
||||
if resolved_output == resolved or resolved_output.is_relative_to(resolved):
|
||||
raise E44DataAmplificationAuditError("E44 output cannot be inside an input root")
|
||||
resolved_roots[label] = resolved
|
||||
|
||||
files: list[dict[str, Any]] = []
|
||||
for label, root in sorted(resolved_roots.items()):
|
||||
for path in sorted(root.rglob("*")):
|
||||
if path.is_symlink():
|
||||
raise E44DataAmplificationAuditError("E44 input contains a symlink")
|
||||
if not path.is_file():
|
||||
continue
|
||||
relative = path.relative_to(root).as_posix()
|
||||
files.append(
|
||||
{
|
||||
"root": label,
|
||||
"path": relative,
|
||||
"byte_length": path.stat().st_size,
|
||||
"sha256": _sha256(path),
|
||||
"kind": _artifact_kind(path),
|
||||
}
|
||||
)
|
||||
if not files:
|
||||
raise E44DataAmplificationAuditError("E44 artifact roots are empty")
|
||||
analysis = analyze_data_amplification(files)
|
||||
catalog_identity = [
|
||||
{
|
||||
"label": label,
|
||||
"root_name": root.name,
|
||||
"catalog_sha256": hashlib.sha256(
|
||||
_canonical_json(
|
||||
[
|
||||
row
|
||||
for row in files
|
||||
if row["root"] == label
|
||||
]
|
||||
)
|
||||
).hexdigest(),
|
||||
}
|
||||
for label, root in sorted(resolved_roots.items())
|
||||
]
|
||||
analysis_sha256 = hashlib.sha256(_canonical_json(analysis)).hexdigest()
|
||||
identity = {
|
||||
"schema_version": E44_RESULT_SCHEMA,
|
||||
"artifact_roots": catalog_identity,
|
||||
"analysis_sha256": analysis_sha256,
|
||||
"producer_sha256": _sha256(Path(__file__).resolve(strict=True)),
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
identity_sha256 = hashlib.sha256(_canonical_json(identity)).hexdigest()
|
||||
result_id = f"e44-data-amplification-{identity_sha256}"
|
||||
destination = resolved_output / result_id
|
||||
if destination.exists():
|
||||
return read_e44_data_amplification_audit(destination)
|
||||
report = {
|
||||
"schema_version": E44_REPORT_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"status": "completed-content-amplification-measurement",
|
||||
"analysis": analysis,
|
||||
"decision": {
|
||||
"storage_migration_authorized": False,
|
||||
"measurement_complete": True,
|
||||
"next_gate": (
|
||||
"select deduplication/chunking only from measured dominant duplicate classes"
|
||||
),
|
||||
},
|
||||
"limitations": [
|
||||
"filesystem allocation, compression ratio and browser heap are not inferred from bytes",
|
||||
"identical content is detected only by exact SHA-256 equality",
|
||||
"no MCAP, COPC, PDAL, Rerun or storage migration is authorized by this report",
|
||||
],
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
destination.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
staging = destination.parent / f".{result_id}.{uuid.uuid4().hex}.tmp"
|
||||
staging.mkdir(mode=0o700, exist_ok=False)
|
||||
try:
|
||||
_write_json(staging / E44_REPORT_NAME, report)
|
||||
manifest = {
|
||||
"schema_version": E44_RESULT_SCHEMA,
|
||||
"result_id": result_id,
|
||||
"identity_sha256": identity_sha256,
|
||||
"identity": identity,
|
||||
"created_at_utc": _utc_now(),
|
||||
"acceptance_state": "accepted-measurement-only",
|
||||
"artifacts": [
|
||||
_artifact(staging / E44_REPORT_NAME, "data-amplification-report"),
|
||||
],
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
_write_json(staging / E44_MANIFEST_NAME, manifest)
|
||||
os.replace(staging, destination)
|
||||
except BaseException:
|
||||
shutil.rmtree(staging, ignore_errors=True)
|
||||
raise
|
||||
return read_e44_data_amplification_audit(destination)
|
||||
|
||||
|
||||
def read_e44_data_amplification_audit(root: Path) -> E44DataAmplificationAudit:
|
||||
"""Read and validate one immutable E44 result."""
|
||||
|
||||
resolved = root.resolve(strict=True)
|
||||
manifest = _read_json(resolved / E44_MANIFEST_NAME)
|
||||
identity = _object(manifest.get("identity"), "E44 identity")
|
||||
identity_sha256 = manifest.get("identity_sha256")
|
||||
if (
|
||||
manifest.get("schema_version") != E44_RESULT_SCHEMA
|
||||
or not isinstance(identity_sha256, str)
|
||||
or hashlib.sha256(_canonical_json(identity)).hexdigest() != identity_sha256
|
||||
or manifest.get("result_id") != f"e44-data-amplification-{identity_sha256}"
|
||||
or resolved.name != manifest.get("result_id")
|
||||
or manifest.get("acceptance_state") != "accepted-measurement-only"
|
||||
or manifest.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E44DataAmplificationAuditError("E44 result identity is invalid")
|
||||
artifacts = manifest.get("artifacts")
|
||||
report_path = resolved / E44_REPORT_NAME
|
||||
if (
|
||||
not isinstance(artifacts, list)
|
||||
or len(artifacts) != 1
|
||||
or not isinstance(artifacts[0], dict)
|
||||
or artifacts[0].get("path") != E44_REPORT_NAME
|
||||
or artifacts[0].get("role") != "data-amplification-report"
|
||||
or artifacts[0].get("byte_length") != report_path.stat().st_size
|
||||
or artifacts[0].get("sha256") != _sha256(report_path)
|
||||
):
|
||||
raise E44DataAmplificationAuditError("E44 artifact content changed")
|
||||
report = _read_json(report_path)
|
||||
analysis = _object(report.get("analysis"), "E44 analysis")
|
||||
if (
|
||||
report.get("schema_version") != E44_REPORT_SCHEMA
|
||||
or report.get("result_id") != resolved.name
|
||||
or report.get("identity_sha256") != identity_sha256
|
||||
or report.get("decision", {}).get("storage_migration_authorized") is not False
|
||||
or hashlib.sha256(_canonical_json(analysis)).hexdigest()
|
||||
!= identity.get("analysis_sha256")
|
||||
or report.get("authority") != _AUTHORITY
|
||||
):
|
||||
raise E44DataAmplificationAuditError("E44 report is invalid")
|
||||
return E44DataAmplificationAudit(
|
||||
result_id=resolved.name,
|
||||
result_root=resolved,
|
||||
manifest=manifest,
|
||||
report=report,
|
||||
)
|
||||
|
||||
|
||||
def analyze_data_amplification(files: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
"""Return exact content-amplification metrics for normalized file rows."""
|
||||
|
||||
if not files:
|
||||
raise E44DataAmplificationAuditError("E44 file catalog is empty")
|
||||
by_digest: dict[str, list[dict[str, Any]]] = defaultdict(list)
|
||||
root_totals: Counter[str] = Counter()
|
||||
root_files: Counter[str] = Counter()
|
||||
kind_totals: Counter[str] = Counter()
|
||||
kind_files: Counter[str] = Counter()
|
||||
seen_root_paths: set[tuple[str, str]] = set()
|
||||
for row in files:
|
||||
root = row.get("root")
|
||||
path = row.get("path")
|
||||
byte_length = row.get("byte_length")
|
||||
sha256 = row.get("sha256")
|
||||
kind = row.get("kind")
|
||||
if (
|
||||
not isinstance(root, str)
|
||||
or _LABEL.fullmatch(root) is None
|
||||
or not isinstance(path, str)
|
||||
or not path
|
||||
or (root, path) in seen_root_paths
|
||||
or not isinstance(byte_length, int)
|
||||
or byte_length < 0
|
||||
or not isinstance(sha256, str)
|
||||
or len(sha256) != 64
|
||||
or not isinstance(kind, str)
|
||||
or not kind
|
||||
):
|
||||
raise E44DataAmplificationAuditError("E44 file row is invalid")
|
||||
seen_root_paths.add((root, path))
|
||||
by_digest[sha256].append(row)
|
||||
root_totals[root] += byte_length
|
||||
root_files[root] += 1
|
||||
kind_totals[kind] += byte_length
|
||||
kind_files[kind] += 1
|
||||
for digest, rows in by_digest.items():
|
||||
sizes = {int(row["byte_length"]) for row in rows}
|
||||
if len(sizes) != 1:
|
||||
raise E44DataAmplificationAuditError(
|
||||
f"E44 digest {digest} has inconsistent byte lengths"
|
||||
)
|
||||
|
||||
logical_bytes = sum(root_totals.values())
|
||||
unique_content_bytes = sum(int(rows[0]["byte_length"]) for rows in by_digest.values())
|
||||
duplicate_bytes = logical_bytes - unique_content_bytes
|
||||
duplicate_groups = [
|
||||
{
|
||||
"sha256": digest,
|
||||
"byte_length": int(rows[0]["byte_length"]),
|
||||
"copies": len(rows),
|
||||
"roots": sorted({str(row["root"]) for row in rows}),
|
||||
"paths": [
|
||||
f"{row['root']}:{row['path']}"
|
||||
for row in sorted(rows, key=lambda item: (item["root"], item["path"]))[:12]
|
||||
],
|
||||
"avoidable_duplicate_bytes": int(rows[0]["byte_length"]) * (len(rows) - 1),
|
||||
"kind": str(rows[0]["kind"]),
|
||||
}
|
||||
for digest, rows in by_digest.items()
|
||||
if len(rows) > 1
|
||||
]
|
||||
duplicate_groups.sort(key=_duplicate_sort_key)
|
||||
roots = {}
|
||||
for root in sorted(root_totals):
|
||||
root_rows = [row for row in files if row["root"] == root]
|
||||
root_unique = {
|
||||
str(row["sha256"]): int(row["byte_length"])
|
||||
for row in root_rows
|
||||
}
|
||||
roots[root] = {
|
||||
"files": root_files[root],
|
||||
"logical_bytes": root_totals[root],
|
||||
"unique_content_bytes_within_root": sum(root_unique.values()),
|
||||
"duplicate_bytes_within_root": (
|
||||
root_totals[root] - sum(root_unique.values())
|
||||
),
|
||||
}
|
||||
return {
|
||||
"root_count": len(roots),
|
||||
"file_count": len(files),
|
||||
"logical_bytes": logical_bytes,
|
||||
"unique_content_bytes": unique_content_bytes,
|
||||
"duplicate_bytes": duplicate_bytes,
|
||||
"amplification_ratio": round(
|
||||
logical_bytes / max(1, unique_content_bytes),
|
||||
6,
|
||||
),
|
||||
"duplicate_fraction": round(
|
||||
duplicate_bytes / max(1, logical_bytes),
|
||||
6,
|
||||
),
|
||||
"duplicate_content_groups": len(duplicate_groups),
|
||||
"roots": roots,
|
||||
"by_kind": {
|
||||
kind: {
|
||||
"files": kind_files[kind],
|
||||
"logical_bytes": kind_totals[kind],
|
||||
}
|
||||
for kind in sorted(kind_totals)
|
||||
},
|
||||
"largest_duplicate_groups": duplicate_groups[:30],
|
||||
}
|
||||
|
||||
|
||||
def _artifact_kind(path: Path) -> str:
|
||||
suffix = path.suffix.lower()
|
||||
if suffix in {".jpg", ".jpeg", ".png", ".webp"}:
|
||||
return "camera-image"
|
||||
if suffix in {".npy", ".npz", ".las", ".laz", ".pcd", ".ply"}:
|
||||
return "point-or-array"
|
||||
if suffix in {".mp4", ".mkv", ".mov"}:
|
||||
return "video"
|
||||
if suffix == ".rrd":
|
||||
return "rerun"
|
||||
if suffix in {".json", ".jsonl", ".md", ".txt", ".yaml", ".yml"}:
|
||||
return "metadata-or-report"
|
||||
if suffix in {".py", ".ps1", ".sh"}:
|
||||
return "runtime-source"
|
||||
return "other"
|
||||
|
||||
|
||||
def _duplicate_sort_key(row: dict[str, Any]) -> tuple[int, str]:
|
||||
return (
|
||||
-int(row["avoidable_duplicate_bytes"]),
|
||||
str(row["sha256"]),
|
||||
)
|
||||
|
||||
|
||||
def _artifact(path: Path, role: str) -> dict[str, Any]:
|
||||
return {
|
||||
"path": path.name,
|
||||
"role": role,
|
||||
"byte_length": path.stat().st_size,
|
||||
"sha256": _sha256(path),
|
||||
}
|
||||
|
||||
|
||||
def _object(value: object, label: str) -> dict[str, Any]:
|
||||
if not isinstance(value, dict):
|
||||
raise E44DataAmplificationAuditError(f"{label} must be an object")
|
||||
return value
|
||||
|
||||
|
||||
def _read_json(path: Path) -> dict[str, Any]:
|
||||
value = json.loads(path.read_text(encoding="utf-8-sig"))
|
||||
if not isinstance(value, dict):
|
||||
raise E44DataAmplificationAuditError(f"JSON object expected: {path.name}")
|
||||
return value
|
||||
|
||||
|
||||
def _write_json(path: Path, value: object) -> None:
|
||||
with path.open("x", encoding="utf-8", newline="\n") as stream:
|
||||
json.dump(value, stream, indent=2, sort_keys=True)
|
||||
stream.write("\n")
|
||||
stream.flush()
|
||||
os.fsync(stream.fileno())
|
||||
|
||||
|
||||
def _canonical_json(value: object) -> bytes:
|
||||
return json.dumps(
|
||||
value,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
allow_nan=False,
|
||||
).encode()
|
||||
|
||||
|
||||
def _sha256(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
while chunk := stream.read(1024 * 1024):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def _utc_now() -> str:
|
||||
return datetime.now(UTC).isoformat(timespec="milliseconds").replace("+00:00", "Z")
|
||||
@@ -237,7 +237,7 @@ class TemporalStabilizer:
|
||||
state.score = float(source["score"])
|
||||
state.template = json.loads(json.dumps(source))
|
||||
|
||||
normalized = json.loads(json.dumps(source))
|
||||
normalized: dict[str, Any] = json.loads(json.dumps(source))
|
||||
source_id = int(source["track_id"])
|
||||
normalized["track_id"] = state.canonical_id
|
||||
normalized["temporal_source_track_id"] = source_id
|
||||
@@ -371,9 +371,9 @@ class StreamingSemanticStabilizer:
|
||||
self.minimum_same_label_neighbors = int(profile["semantic"]["minimum_same_label_neighbors"])
|
||||
self.previous_raw: np.ndarray | None = None
|
||||
self.previous_stabilized: np.ndarray | None = None
|
||||
self.baseline_unsupported = deque(maxlen=4096)
|
||||
self.stabilized_unsupported = deque(maxlen=4096)
|
||||
self.processing_ms = deque(maxlen=4096)
|
||||
self.baseline_unsupported: deque[float] = deque(maxlen=4096)
|
||||
self.stabilized_unsupported: deque[float] = deque(maxlen=4096)
|
||||
self.processing_ms: deque[float] = deque(maxlen=4096)
|
||||
self.frames = 0
|
||||
|
||||
def update(self, mask: np.ndarray) -> np.ndarray:
|
||||
@@ -436,21 +436,28 @@ def read_inline_profile(path: Path) -> tuple[dict[str, Any], str]:
|
||||
bounds = profile.get("bounds")
|
||||
acceptance = profile.get("acceptance")
|
||||
authority = profile.get("authority")
|
||||
if not all(
|
||||
isinstance(value, dict)
|
||||
for value in (
|
||||
source,
|
||||
tracking,
|
||||
cuboids,
|
||||
semantic,
|
||||
bounds,
|
||||
acceptance,
|
||||
)
|
||||
):
|
||||
raise RuntimeError("LAB E23 inline temporal profile is invalid")
|
||||
assert isinstance(source, dict)
|
||||
assert isinstance(tracking, dict)
|
||||
assert isinstance(cuboids, dict)
|
||||
assert isinstance(semantic, dict)
|
||||
assert isinstance(bounds, dict)
|
||||
assert isinstance(acceptance, dict)
|
||||
if (
|
||||
profile.get("schema_version") != PROFILE_SCHEMA
|
||||
or profile.get("mode") != "inline-shadow-qualification"
|
||||
or profile.get("stage") != "warm-worker-after-fusion-before-result-publication"
|
||||
or not all(
|
||||
isinstance(value, dict)
|
||||
for value in (
|
||||
source,
|
||||
tracking,
|
||||
cuboids,
|
||||
semantic,
|
||||
bounds,
|
||||
acceptance,
|
||||
)
|
||||
)
|
||||
or source.get("source_id") != "sensor.camera.right"
|
||||
or source.get("resolution") != [800, 600]
|
||||
or source.get("calibration_slot") != "camera_1"
|
||||
@@ -493,7 +500,7 @@ def stabilize_world_state(
|
||||
fusion_objects: list[dict[str, Any]],
|
||||
memory: dict[int, dict[str, Any]],
|
||||
) -> dict[str, Any]:
|
||||
world = json.loads(json.dumps(source))
|
||||
world: dict[str, Any] = json.loads(json.dumps(source))
|
||||
source_objects = {
|
||||
int(item["track_id"]): item
|
||||
for item in source.get("objects", [])
|
||||
@@ -507,7 +514,7 @@ def stabilize_world_state(
|
||||
canonical = int(fusion["track_id"])
|
||||
source_id = int(fusion.get("temporal_source_track_id", canonical))
|
||||
template = source_objects.get(source_id) or memory.get(canonical) or {}
|
||||
item = json.loads(json.dumps(template))
|
||||
item: dict[str, Any] = json.loads(json.dumps(template))
|
||||
item.update(
|
||||
{
|
||||
"track_id": canonical,
|
||||
|
||||
@@ -91,9 +91,11 @@ def _laboratory_method(
|
||||
profile_sha256: str | None,
|
||||
source_result_id: str,
|
||||
) -> dict[str, object]:
|
||||
source_identity: str | None = source_result_id.rsplit("-", 1)[-1]
|
||||
if len(source_identity) != 64 or any(
|
||||
character not in "0123456789abcdef" for character in source_identity
|
||||
source_identity_candidate = source_result_id.rsplit("-", 1)[-1]
|
||||
source_identity: str | None = source_identity_candidate
|
||||
if len(source_identity_candidate) != 64 or any(
|
||||
character not in "0123456789abcdef"
|
||||
for character in source_identity_candidate
|
||||
):
|
||||
source_identity = None
|
||||
return {
|
||||
|
||||
@@ -15,11 +15,7 @@ import numpy as np
|
||||
import numpy.typing as npt
|
||||
|
||||
from k1link.ground_segmentation import (
|
||||
DEFAULT_GROUND_BENCHMARK_PROFILE,
|
||||
GroundBenchmarkProfile,
|
||||
GroundSegmentation,
|
||||
GroundSegmenter,
|
||||
LocalPercentileGroundSegmenter,
|
||||
DEFAULT_GROUND_BENCHMARK_PROFILE as DEFAULT_GROUND_BENCHMARK_PROFILE,
|
||||
)
|
||||
from k1link.ground_segmentation import (
|
||||
PATCHWORKPP_SOURCE_COMMIT as PATCHWORKPP_SOURCE_COMMIT,
|
||||
@@ -31,7 +27,19 @@ from k1link.ground_segmentation import (
|
||||
PATCHWORKPP_SOURCE_URL as PATCHWORKPP_SOURCE_URL,
|
||||
)
|
||||
from k1link.ground_segmentation import (
|
||||
GroundSegmentationError as LidarGroundError,
|
||||
GroundBenchmarkProfile as GroundBenchmarkProfile,
|
||||
)
|
||||
from k1link.ground_segmentation import (
|
||||
GroundSegmentation as GroundSegmentation,
|
||||
)
|
||||
from k1link.ground_segmentation import (
|
||||
GroundSegmentationError,
|
||||
)
|
||||
from k1link.ground_segmentation import (
|
||||
GroundSegmenter as GroundSegmenter,
|
||||
)
|
||||
from k1link.ground_segmentation import (
|
||||
LocalPercentileGroundSegmenter as LocalPercentileGroundSegmenter,
|
||||
)
|
||||
from k1link.ground_segmentation import (
|
||||
PatchworkPPGroundSegmenter as PatchworkPPGroundSegmenter,
|
||||
@@ -40,6 +48,8 @@ from k1link.ground_segmentation import (
|
||||
from .lidar_contract import LidarContractError, sensor_frame_xyzi
|
||||
from .lidar_replay import LidarReplayPackV2
|
||||
|
||||
LidarGroundError = GroundSegmentationError
|
||||
|
||||
LIDAR_GROUND_BENCHMARK_SCHEMA: Final = "missioncore.lidar-ground-benchmark/v1"
|
||||
LIDAR_GROUND_BENCHMARK_REPORT_SCHEMA: Final = "missioncore.lidar-ground-benchmark-report/v1"
|
||||
LIDAR_GROUND_ANNOTATION_TEMPLATE_SCHEMA: Final = "missioncore.lidar-ground-annotation-template/v1"
|
||||
|
||||
@@ -0,0 +1,377 @@
|
||||
"""Native, transport-independent telemetry for Mission Core compute stages.
|
||||
|
||||
The compute layer owns the meaning of a stage event. Transport ownership stays
|
||||
outside the stage implementation: a durable worker can inject an already-connected
|
||||
MQTT client, while a laboratory runner can record the exact same documents to JSONL.
|
||||
No sink is created implicitly and telemetry never grants command authority.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import threading
|
||||
import time
|
||||
from collections.abc import Iterator
|
||||
from contextlib import contextmanager
|
||||
from dataclasses import dataclass
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Final, Protocol
|
||||
|
||||
PIPELINE_TELEMETRY_SCHEMA: Final = "missioncore.agent-pipeline-telemetry/v1"
|
||||
PIPELINE_TELEMETRY_RECORD_SCHEMA: Final = "missioncore.pipeline-telemetry-record/v1"
|
||||
PIPELINE_TOPIC_TEMPLATE: Final = (
|
||||
"mission-core/v1/contours/{contour_id}/agents/{agent_id}/pipeline"
|
||||
)
|
||||
SAFE_TOPIC_IDENTIFIER: Final = re.compile(
|
||||
r"^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$"
|
||||
)
|
||||
MAX_TEXT_LENGTH: Final = 256
|
||||
MAX_PAYLOAD_BYTES: Final = 1024 * 1024
|
||||
STAGE_STATES: Final = frozenset({"started", "completed", "failed"})
|
||||
_AUTHORITY: Final = {
|
||||
"commands_enabled": False,
|
||||
"navigation_or_safety_accepted": False,
|
||||
}
|
||||
|
||||
|
||||
class PipelineTelemetryError(RuntimeError):
|
||||
"""A pipeline telemetry identity, event, or transport operation is invalid."""
|
||||
|
||||
|
||||
class PipelineTelemetrySink(Protocol):
|
||||
"""Transport boundary used by a compute-stage telemetry emitter."""
|
||||
|
||||
def publish(self, topic: str, payload: bytes) -> None:
|
||||
"""Publish one already-validated telemetry document."""
|
||||
|
||||
|
||||
class ConnectedMqttClient(Protocol):
|
||||
"""Minimal surface required from an already-connected MQTT client."""
|
||||
|
||||
def publish(
|
||||
self,
|
||||
topic: str,
|
||||
payload: bytes,
|
||||
qos: int,
|
||||
retain: bool,
|
||||
) -> Any:
|
||||
"""Publish one MQTT message and return an object exposing ``rc``."""
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class PipelineTelemetryIdentity:
|
||||
contour_id: str
|
||||
agent_id: str
|
||||
node_id: str
|
||||
lab_id: str
|
||||
run_id: str
|
||||
source_id: str
|
||||
source_package_id: str
|
||||
method_id: str
|
||||
request_id: str | None = None
|
||||
frame_index: int | None = None
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
for name in ("contour_id", "agent_id"):
|
||||
value = getattr(self, name)
|
||||
if SAFE_TOPIC_IDENTIFIER.fullmatch(value) is None:
|
||||
raise PipelineTelemetryError(f"{name} is not a safe topic identifier")
|
||||
for name in (
|
||||
"node_id",
|
||||
"lab_id",
|
||||
"run_id",
|
||||
"source_id",
|
||||
"source_package_id",
|
||||
"method_id",
|
||||
):
|
||||
_validate_text(getattr(self, name), name)
|
||||
if self.request_id is not None:
|
||||
_validate_text(self.request_id, "request_id")
|
||||
if self.frame_index is not None and self.frame_index < 0:
|
||||
raise PipelineTelemetryError("frame_index must be non-negative")
|
||||
|
||||
@property
|
||||
def topic(self) -> str:
|
||||
return PIPELINE_TOPIC_TEMPLATE.format(
|
||||
contour_id=self.contour_id,
|
||||
agent_id=self.agent_id,
|
||||
)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class PipelineStageOutcome:
|
||||
"""Mutable counters a stage can complete before its terminal event is emitted."""
|
||||
|
||||
input_count: int | None = None
|
||||
output_count: int | None = None
|
||||
queue_wait_ms: float | None = None
|
||||
|
||||
|
||||
class PipelineTelemetryEmitter:
|
||||
"""Emit bounded lifecycle events around actual compute work."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
identity: PipelineTelemetryIdentity,
|
||||
sink: PipelineTelemetrySink,
|
||||
clock_ns: Any = time.monotonic_ns,
|
||||
) -> None:
|
||||
self.identity = identity
|
||||
self.sink = sink
|
||||
self._clock_ns = clock_ns
|
||||
|
||||
@contextmanager
|
||||
def stage(
|
||||
self,
|
||||
stage_id: str,
|
||||
*,
|
||||
input_count: int | None = None,
|
||||
queue_wait_ms: float | None = None,
|
||||
) -> Iterator[PipelineStageOutcome]:
|
||||
"""Publish a lifecycle pair and preserve the stage exception unchanged."""
|
||||
|
||||
_validate_text(stage_id, "stage_id")
|
||||
outcome = PipelineStageOutcome(
|
||||
input_count=_optional_count(input_count, "input_count"),
|
||||
queue_wait_ms=_optional_duration(queue_wait_ms, "queue_wait_ms"),
|
||||
)
|
||||
started_ns = int(self._clock_ns())
|
||||
self._emit(stage_id=stage_id, state="started", outcome=outcome)
|
||||
try:
|
||||
yield outcome
|
||||
except BaseException as exc:
|
||||
duration_ms = max(0.0, (int(self._clock_ns()) - started_ns) / 1_000_000)
|
||||
self._emit(
|
||||
stage_id=stage_id,
|
||||
state="failed",
|
||||
outcome=outcome,
|
||||
duration_ms=duration_ms,
|
||||
error_type=type(exc).__name__,
|
||||
)
|
||||
raise
|
||||
else:
|
||||
duration_ms = max(0.0, (int(self._clock_ns()) - started_ns) / 1_000_000)
|
||||
self._emit(
|
||||
stage_id=stage_id,
|
||||
state="completed",
|
||||
outcome=outcome,
|
||||
duration_ms=duration_ms,
|
||||
)
|
||||
|
||||
def _emit(
|
||||
self,
|
||||
*,
|
||||
stage_id: str,
|
||||
state: str,
|
||||
outcome: PipelineStageOutcome,
|
||||
duration_ms: float | None = None,
|
||||
error_type: str | None = None,
|
||||
) -> None:
|
||||
outcome.input_count = _optional_count(outcome.input_count, "input_count")
|
||||
outcome.output_count = _optional_count(outcome.output_count, "output_count")
|
||||
outcome.queue_wait_ms = _optional_duration(
|
||||
outcome.queue_wait_ms,
|
||||
"queue_wait_ms",
|
||||
)
|
||||
document = build_pipeline_telemetry_document(
|
||||
identity=self.identity,
|
||||
stage_id=stage_id,
|
||||
state=state,
|
||||
duration_ms=duration_ms,
|
||||
input_count=outcome.input_count,
|
||||
output_count=outcome.output_count,
|
||||
queue_wait_ms=outcome.queue_wait_ms,
|
||||
error_type=error_type,
|
||||
)
|
||||
payload = _canonical_json(document)
|
||||
if len(payload) > MAX_PAYLOAD_BYTES:
|
||||
raise PipelineTelemetryError("pipeline telemetry exceeds the 1 MiB contract")
|
||||
self.sink.publish(self.identity.topic, payload)
|
||||
|
||||
|
||||
class JsonlPipelineTelemetrySink:
|
||||
"""Append topic-bound telemetry records for local, auditable execution evidence."""
|
||||
|
||||
def __init__(self, path: Path) -> None:
|
||||
self.path = path.expanduser().absolute()
|
||||
self._lock = threading.Lock()
|
||||
|
||||
def publish(self, topic: str, payload: bytes) -> None:
|
||||
document = json.loads(payload.decode("utf-8"))
|
||||
if not isinstance(document, dict):
|
||||
raise PipelineTelemetryError("pipeline telemetry payload must be an object")
|
||||
record = {
|
||||
"schema_version": PIPELINE_TELEMETRY_RECORD_SCHEMA,
|
||||
"topic": topic,
|
||||
"payload": document,
|
||||
}
|
||||
encoded = _canonical_json(record) + b"\n"
|
||||
with self._lock:
|
||||
self.path.parent.mkdir(mode=0o700, parents=True, exist_ok=True)
|
||||
descriptor = os.open(
|
||||
self.path,
|
||||
os.O_APPEND | os.O_CREAT | os.O_WRONLY,
|
||||
0o600,
|
||||
)
|
||||
try:
|
||||
os.write(descriptor, encoded)
|
||||
os.fsync(descriptor)
|
||||
finally:
|
||||
os.close(descriptor)
|
||||
|
||||
|
||||
class MqttPipelineTelemetrySink:
|
||||
"""Publish through a worker-owned, already-connected Paho-compatible client."""
|
||||
|
||||
def __init__(self, client: ConnectedMqttClient) -> None:
|
||||
self.client = client
|
||||
|
||||
def publish(self, topic: str, payload: bytes) -> None:
|
||||
result = self.client.publish(topic, payload, qos=1, retain=False)
|
||||
return_code = getattr(result, "rc", None)
|
||||
if return_code != 0:
|
||||
raise PipelineTelemetryError(
|
||||
f"MQTT pipeline telemetry publish failed with code {return_code!r}"
|
||||
)
|
||||
|
||||
|
||||
def build_pipeline_telemetry_document(
|
||||
*,
|
||||
identity: PipelineTelemetryIdentity,
|
||||
stage_id: str,
|
||||
state: str,
|
||||
duration_ms: float | None = None,
|
||||
input_count: int | None = None,
|
||||
output_count: int | None = None,
|
||||
queue_wait_ms: float | None = None,
|
||||
error_type: str | None = None,
|
||||
observed_at_utc: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Build the canonical document accepted by the telemetry-plane normalizer."""
|
||||
|
||||
_validate_text(stage_id, "stage_id")
|
||||
if state not in STAGE_STATES:
|
||||
raise PipelineTelemetryError("stage telemetry state is invalid")
|
||||
duration_ms = _optional_duration(duration_ms, "duration_ms")
|
||||
input_count = _optional_count(input_count, "input_count")
|
||||
output_count = _optional_count(output_count, "output_count")
|
||||
queue_wait_ms = _optional_duration(queue_wait_ms, "queue_wait_ms")
|
||||
if state == "started" and duration_ms is not None:
|
||||
raise PipelineTelemetryError("a started stage cannot have a duration")
|
||||
if state != "started" and duration_ms is None:
|
||||
raise PipelineTelemetryError("a terminal stage requires duration_ms")
|
||||
if error_type is not None:
|
||||
_validate_text(error_type, "error_type")
|
||||
if state == "failed" and error_type is None:
|
||||
raise PipelineTelemetryError("a failed stage requires error_type")
|
||||
if state != "failed" and error_type is not None:
|
||||
raise PipelineTelemetryError("only a failed stage can have error_type")
|
||||
|
||||
tags = {
|
||||
"agent_id": identity.agent_id,
|
||||
"contour_id": identity.contour_id,
|
||||
"lab_id": identity.lab_id,
|
||||
"method_id": identity.method_id,
|
||||
"node_id": identity.node_id,
|
||||
"run_id": identity.run_id,
|
||||
"source_id": identity.source_id,
|
||||
"source_package_id": identity.source_package_id,
|
||||
"stage_id": stage_id,
|
||||
"stage_state": state,
|
||||
}
|
||||
if identity.request_id is not None:
|
||||
tags["request_id"] = identity.request_id
|
||||
stage_metric = {
|
||||
"elapsed_seconds": (
|
||||
round(duration_ms / 1000.0, 9) if duration_ms is not None else None
|
||||
),
|
||||
"activations": 1,
|
||||
"input_count": input_count,
|
||||
"output_count": output_count,
|
||||
"queue_wait_ms": queue_wait_ms,
|
||||
}
|
||||
event = {
|
||||
"stage_id": stage_id,
|
||||
"state": state,
|
||||
"duration_ms": duration_ms,
|
||||
"input_count": input_count,
|
||||
"output_count": output_count,
|
||||
"queue_wait_ms": queue_wait_ms,
|
||||
"error_type": error_type,
|
||||
}
|
||||
document: dict[str, Any] = {
|
||||
"schema_version": PIPELINE_TELEMETRY_SCHEMA,
|
||||
"observed_at_utc": observed_at_utc or _utc_now(),
|
||||
"node_id": identity.node_id,
|
||||
"lab_id": identity.lab_id,
|
||||
"run_id": identity.run_id,
|
||||
"source_id": identity.source_id,
|
||||
"source_package_id": identity.source_package_id,
|
||||
"method_id": identity.method_id,
|
||||
"stage_id": stage_id,
|
||||
"stage_state": state,
|
||||
"tags": tags,
|
||||
"payload": {
|
||||
"state": (
|
||||
"busy"
|
||||
if state == "started"
|
||||
else ("failed" if state == "failed" else "ready")
|
||||
),
|
||||
"current_stage": stage_id,
|
||||
"active_request_id": identity.request_id or identity.run_id,
|
||||
"active_stages": [stage_id] if state == "started" else [],
|
||||
"stage_metrics": {stage_id: stage_metric},
|
||||
"event": event,
|
||||
},
|
||||
"authority": _AUTHORITY,
|
||||
}
|
||||
if identity.request_id is not None:
|
||||
document["request_id"] = identity.request_id
|
||||
if identity.frame_index is not None:
|
||||
document["frame_index"] = identity.frame_index
|
||||
return document
|
||||
|
||||
|
||||
def _validate_text(value: object, name: str) -> str:
|
||||
if (
|
||||
not isinstance(value, str)
|
||||
or not value
|
||||
or len(value) > MAX_TEXT_LENGTH
|
||||
or any(ord(character) < 32 for character in value)
|
||||
):
|
||||
raise PipelineTelemetryError(f"{name} is invalid")
|
||||
return value
|
||||
|
||||
|
||||
def _optional_count(value: int | None, name: str) -> int | None:
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, bool) or not isinstance(value, int) or value < 0:
|
||||
raise PipelineTelemetryError(f"{name} must be a non-negative integer")
|
||||
return value
|
||||
|
||||
|
||||
def _optional_duration(value: float | None, name: str) -> float | None:
|
||||
if value is None:
|
||||
return None
|
||||
normalized = float(value)
|
||||
if normalized < 0 or normalized != normalized or normalized == float("inf"):
|
||||
raise PipelineTelemetryError(f"{name} must be finite and non-negative")
|
||||
return round(normalized, 6)
|
||||
|
||||
|
||||
def _canonical_json(value: object) -> bytes:
|
||||
return json.dumps(
|
||||
value,
|
||||
ensure_ascii=False,
|
||||
sort_keys=True,
|
||||
separators=(",", ":"),
|
||||
).encode("utf-8")
|
||||
|
||||
|
||||
def _utc_now() -> str:
|
||||
return datetime.now(UTC).isoformat(timespec="microseconds").replace("+00:00", "Z")
|
||||
@@ -261,7 +261,7 @@ class TemporalStabilizer:
|
||||
state.score = float(source["score"])
|
||||
state.template = json.loads(json.dumps(source))
|
||||
|
||||
normalized = json.loads(json.dumps(source))
|
||||
normalized: dict[str, Any] = json.loads(json.dumps(source))
|
||||
source_id = int(source["track_id"])
|
||||
normalized["track_id"] = state.canonical_id
|
||||
normalized["temporal_source_track_id"] = source_id
|
||||
@@ -405,13 +405,20 @@ def read_profile(path: Path) -> tuple[dict[str, Any], str]:
|
||||
bounds = profile.get("bounds")
|
||||
acceptance = profile.get("acceptance")
|
||||
authority = profile.get("authority")
|
||||
if not all(
|
||||
isinstance(value, dict)
|
||||
for value in (source, tracking, cuboids, semantic, bounds, acceptance)
|
||||
):
|
||||
raise SessionIntegrityError("LAB E22 temporal profile is invalid")
|
||||
assert isinstance(source, dict)
|
||||
assert isinstance(tracking, dict)
|
||||
assert isinstance(cuboids, dict)
|
||||
assert isinstance(semantic, dict)
|
||||
assert isinstance(bounds, dict)
|
||||
assert isinstance(acceptance, dict)
|
||||
if (
|
||||
profile.get("schema_version") != PROFILE_SCHEMA
|
||||
or profile.get("mode") != "recorded-streaming-qualification"
|
||||
or not all(
|
||||
isinstance(value, dict)
|
||||
for value in (source, tracking, cuboids, semantic, bounds, acceptance)
|
||||
)
|
||||
or source.get("source_id") != "sensor.camera.right"
|
||||
or source.get("resolution") != [800, 600]
|
||||
or semantic.get("mode")
|
||||
@@ -575,7 +582,7 @@ def build_temporal_stability_result(
|
||||
semantic_metrics["stabilized_unsupported_change_fraction"]["mean"],
|
||||
),
|
||||
}
|
||||
runtime = {
|
||||
runtime: dict[str, Any] = {
|
||||
"camera_frame_processing_ms": _percentiles(frame_ms),
|
||||
"semantic_frame_processing_ms": _percentiles(semantic_ms),
|
||||
"peak_track_states": stabilizer.peak_states,
|
||||
@@ -586,7 +593,7 @@ def build_temporal_stability_result(
|
||||
+ 600 * 800
|
||||
),
|
||||
}
|
||||
criteria = profile["acceptance"]
|
||||
criteria: dict[str, Any] = profile["acceptance"]
|
||||
checks = {
|
||||
"minimum_2d_acceleration_reduction": reductions[
|
||||
"tracking_2d_acceleration_p95_fraction"
|
||||
@@ -791,7 +798,7 @@ def _stabilize_world(
|
||||
fusion_objects: list[dict[str, Any]],
|
||||
memory: dict[int, dict[str, Any]],
|
||||
) -> dict[str, Any]:
|
||||
world = json.loads(json.dumps(source))
|
||||
world: dict[str, Any] = json.loads(json.dumps(source))
|
||||
source_objects = {
|
||||
int(item["track_id"]): item
|
||||
for item in source.get("objects", [])
|
||||
@@ -804,7 +811,7 @@ def _stabilize_world(
|
||||
canonical = int(fusion["track_id"])
|
||||
source_id = int(fusion.get("temporal_source_track_id", canonical))
|
||||
template = source_objects.get(source_id) or memory.get(canonical) or {}
|
||||
item = json.loads(json.dumps(template))
|
||||
item: dict[str, Any] = json.loads(json.dumps(template))
|
||||
item.update(
|
||||
{
|
||||
"track_id": canonical,
|
||||
@@ -861,10 +868,10 @@ def _quality_metrics(
|
||||
)
|
||||
acceleration: list[float] = []
|
||||
size_steps: list[float] = []
|
||||
for values in tracks.values():
|
||||
for track_values in tracks.values():
|
||||
previous_step: np.ndarray | None = None
|
||||
for (left_frame, left_box), (right_frame, right_box) in zip(
|
||||
values, values[1:], strict=False
|
||||
track_values, track_values[1:], strict=False
|
||||
):
|
||||
if right_frame - left_frame != 1:
|
||||
previous_step = None
|
||||
@@ -882,8 +889,12 @@ def _quality_metrics(
|
||||
cuboid_size_steps: list[float] = []
|
||||
yaw_steps: list[float] = []
|
||||
gaps = 0
|
||||
for values in cuboids.values():
|
||||
for left, right in zip(values, values[1:], strict=False):
|
||||
for cuboid_values in cuboids.values():
|
||||
for left, right in zip(
|
||||
cuboid_values,
|
||||
cuboid_values[1:],
|
||||
strict=False,
|
||||
):
|
||||
if right[0] - left[0] != 1:
|
||||
gaps += 1
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user