feat(perception): integrate calibrated operator pipeline
Add calibrated K1 projection, recorded and near-live perception qualification, unified Rerun operator layers, bounded replay admission, audited viewer controls, worker experiments, and lab evidence.
This commit is contained in:
@@ -23,15 +23,18 @@ from .plugin_contract import (
|
||||
RecordingExporter,
|
||||
)
|
||||
|
||||
# v9 derives both real RRD boundary rows from the durable capture-clock
|
||||
# envelope. v8 used the first/last MQTT message and could still exclude a
|
||||
# camera fragment produced between source startup/shutdown and those packets.
|
||||
CACHE_SCHEMA = "missioncore.derived-rerun-recording-cache/v9"
|
||||
# v12 publishes a 2 Hz point-cloud operator projection while retaining complete
|
||||
# normal K1 point batches. v11 also spatially thinned every ~2.4k-point frame;
|
||||
# the latest-at AI view therefore looked visibly bald even though the raw
|
||||
# capture was complete. Frames above the explicit emergency threshold remain
|
||||
# bounded, and the native capture stays the source of record and AI input.
|
||||
CACHE_SCHEMA = "missioncore.derived-rerun-recording-cache/v12"
|
||||
COMPATIBLE_CACHE_SCHEMAS = frozenset({CACHE_SCHEMA})
|
||||
RECORDING_CACHE_FILENAME = "scene.operator-v12.rrd"
|
||||
RECORDING_CACHE_SIDECAR_FILENAME = f"{RECORDING_CACHE_FILENAME}.cache.json"
|
||||
RERUN_RECORDING_MEDIA_TYPE = "application/vnd.rerun.rrd"
|
||||
RERUN_SESSION_TIMELINE = "session_time"
|
||||
SESSION_ID_PATTERN = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$")
|
||||
DEFAULT_CACHE_MAX_BYTES = 8 * 1024 * 1024 * 1024
|
||||
DEFAULT_FREE_SPACE_RESERVE_BYTES = 2 * 1024 * 1024 * 1024
|
||||
|
||||
RrdExporter = Callable[..., Mapping[str, object]]
|
||||
@@ -154,10 +157,9 @@ class SessionRecordingMaterializer:
|
||||
self._exporters = dict(exporters or {})
|
||||
if len(self._exporters) != len(set(self._exporters)):
|
||||
raise ValueError("recording exporter plugin ids must be unique")
|
||||
self.cache_max_bytes = _positive_configuration(
|
||||
self.cache_max_bytes = _optional_positive_configuration(
|
||||
cache_max_bytes,
|
||||
environment_name="MISSIONCORE_RRD_CACHE_MAX_BYTES",
|
||||
default=DEFAULT_CACHE_MAX_BYTES,
|
||||
)
|
||||
self.free_space_reserve_bytes = _non_negative_configuration(
|
||||
free_space_reserve_bytes,
|
||||
@@ -198,7 +200,7 @@ class SessionRecordingMaterializer:
|
||||
return False
|
||||
return (
|
||||
path.parent.parent == self.recordings_root
|
||||
and path.name == "scene.rrd"
|
||||
and path.name == RECORDING_CACHE_FILENAME
|
||||
and stat.S_ISREG(path_stat.st_mode)
|
||||
and not stat.S_ISLNK(path_stat.st_mode)
|
||||
and path_stat.st_size == recording.byte_length
|
||||
@@ -425,7 +427,10 @@ class SessionRecordingMaterializer:
|
||||
and name.endswith(".tmp")
|
||||
)
|
||||
or (name.startswith(".source.") and name.endswith(".tmp"))
|
||||
or (name.startswith(".scene.rrd.cache.json.") and name.endswith(".tmp"))
|
||||
or (
|
||||
name.startswith(f".{RECORDING_CACHE_SIDECAR_FILENAME}.")
|
||||
and name.endswith(".tmp")
|
||||
)
|
||||
)
|
||||
if not stale:
|
||||
continue
|
||||
@@ -464,8 +469,8 @@ class SessionRecordingMaterializer:
|
||||
_chmod_best_effort(resolved_session_root, 0o700)
|
||||
return (
|
||||
resolved_session_root,
|
||||
resolved_session_root / "scene.rrd",
|
||||
resolved_session_root / "scene.rrd.cache.json",
|
||||
resolved_session_root / RECORDING_CACHE_FILENAME,
|
||||
resolved_session_root / RECORDING_CACHE_SIDECAR_FILENAME,
|
||||
)
|
||||
|
||||
def _load_cached_recording(
|
||||
@@ -609,7 +614,10 @@ class SessionRecordingMaterializer:
|
||||
candidate_path,
|
||||
"derived recording candidate",
|
||||
)
|
||||
if candidate_stat.st_size > self.cache_max_bytes:
|
||||
if (
|
||||
self.cache_max_bytes is not None
|
||||
and candidate_stat.st_size > self.cache_max_bytes
|
||||
):
|
||||
raise RecordingMaterializationError("derived recording exceeds the cache quota")
|
||||
self._ensure_cache_capacity(
|
||||
required_bytes=4 * 1024,
|
||||
@@ -802,7 +810,10 @@ class SessionRecordingMaterializer:
|
||||
while True:
|
||||
total_bytes, entries = _cache_entries(self.recordings_root)
|
||||
free_bytes = shutil.disk_usage(self.recordings_root).free
|
||||
quota_ok = total_bytes + required_bytes <= self.cache_max_bytes
|
||||
quota_ok = (
|
||||
self.cache_max_bytes is None
|
||||
or total_bytes + required_bytes <= self.cache_max_bytes
|
||||
)
|
||||
reserve_ok = free_bytes >= self.free_space_reserve_bytes + required_bytes
|
||||
if quota_ok and reserve_ok:
|
||||
return
|
||||
@@ -1372,16 +1383,17 @@ def _touch_lru(path: Path) -> None:
|
||||
return
|
||||
|
||||
|
||||
def _positive_configuration(
|
||||
def _optional_positive_configuration(
|
||||
configured: int | None,
|
||||
*,
|
||||
environment_name: str,
|
||||
default: int,
|
||||
) -> int:
|
||||
) -> int | None:
|
||||
value = configured
|
||||
if value is None:
|
||||
raw = os.environ.get(environment_name, "").strip()
|
||||
value = int(raw) if raw else default
|
||||
value = int(raw) if raw else None
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, bool) or value <= 0:
|
||||
raise ValueError(f"{environment_name} must be a positive integer")
|
||||
return value
|
||||
|
||||
Reference in New Issue
Block a user