feat: qualify complete K1 replay on worker

This commit is contained in:
DCCONSTRUCTIONS
2026-07-26 10:11:56 +03:00
parent a1e2cb523f
commit 36ea7ea3d8
17 changed files with 1212 additions and 118 deletions
+2 -2
View File
@@ -1327,8 +1327,8 @@ def build_k1_local_surface(
"status": "replay-experiment-only",
"production_promotion": False,
"next_gate": (
"run the accepted profile through a bounded latest-wins live-shadow "
"queue without commands, free-space or safety authority"
"qualify a separate dynamic-observation layer; physical K1 "
"acquisition remains a later commissioning gate"
),
},
"authority": {
@@ -4,6 +4,7 @@ import math
import threading
import time
from collections import Counter, deque
from collections.abc import Callable
from dataclasses import asdict, dataclass
from typing import Any, Final, Literal
@@ -767,6 +768,7 @@ class K1LocalSurfaceShadowRuntime:
profile: K1LocalSurfaceProfile = DEFAULT_K1_LOCAL_SURFACE_PROFILE,
queue_capacity: int = 2,
result_capacity: int = 8,
result_observer: Callable[[K1LocalSurfaceShadowResult], None] | None = None,
) -> None:
if (
not session_id
@@ -779,6 +781,7 @@ class K1LocalSurfaceShadowRuntime:
self.profile = profile
self._queue = LatestWinsQueue[K1LocalSurfaceShadowInput](queue_capacity)
self._result_capacity = result_capacity
self._result_observer = result_observer
self._results: deque[K1LocalSurfaceShadowResult] = deque(maxlen=result_capacity)
self._result_dropped = 0
self._processed = 0
@@ -788,6 +791,8 @@ class K1LocalSurfaceShadowRuntime:
self._result_age_ms: deque[float] = deque(maxlen=512)
self._last_error: str | None = None
self._inflight = False
self._first_published_monotonic_ns: int | None = None
self._last_published_monotonic_ns: int | None = None
self._condition = threading.Condition()
self._closed = False
self._estimator = K1LocalSurfaceShadowEstimator(profile)
@@ -802,6 +807,9 @@ class K1LocalSurfaceShadowRuntime:
with self._condition:
if self._closed:
raise RuntimeError("K1 local-surface shadow runtime is closed")
if self._first_published_monotonic_ns is None:
self._first_published_monotonic_ns = value.published_monotonic_ns
self._last_published_monotonic_ns = value.published_monotonic_ns
self._queue.publish(value)
def publish_views(
@@ -849,6 +857,16 @@ class K1LocalSurfaceShadowRuntime:
queue_snapshot = self._queue.snapshot()
with self._condition:
latest = self._results[-1] if self._results else None
source_span_seconds = (
0.0
if self._first_published_monotonic_ns is None
or self._last_published_monotonic_ns is None
else (
self._last_published_monotonic_ns
- self._first_published_monotonic_ns
)
/ 1_000_000_000
)
return {
"schema_version": K1_LOCAL_SURFACE_SHADOW_SCHEMA,
"mode": "live-shadow-diagnostic-only",
@@ -856,6 +874,14 @@ class K1LocalSurfaceShadowRuntime:
"profile": self.profile.to_dict(),
"queue_policy": "bounded-latest-wins",
"queue": asdict(queue_snapshot),
"delivery": {
"source_span_seconds": source_span_seconds,
"effective_fps": (
self._processed / source_span_seconds
if source_span_seconds > 0
else 0.0
),
},
"results": {
"capacity": self._result_capacity,
"depth": len(self._results),
@@ -891,7 +917,9 @@ class K1LocalSurfaceShadowRuntime:
self._inflight = True
try:
result = self._estimator.process(value)
except (LidarGroundError, ValueError, np.linalg.LinAlgError) as exc:
if self._result_observer is not None:
self._result_observer(result)
except Exception as exc:
with self._condition:
self._failed += 1
self._last_error = type(exc).__name__
@@ -922,10 +950,12 @@ class K1LocalSurfaceShadowCoordinator:
future_pose_wait_ms: float = 25.0,
retention_seconds: float = 3.0,
result_capacity: int = 8,
result_observer: Callable[[K1LocalSurfaceShadowResult], None] | None = None,
) -> None:
self.profile = profile
self._queue_capacity = point_capacity
self._result_capacity = result_capacity
self._result_observer = result_observer
self._binder = K1LocalSurfacePoseBinder(
maximum_pose_binding_ms=profile.maximum_pose_binding_ms,
point_capacity=point_capacity,
@@ -953,6 +983,7 @@ class K1LocalSurfaceShadowCoordinator:
profile=self.profile,
queue_capacity=self._queue_capacity,
result_capacity=self._result_capacity,
result_observer=self._result_observer,
)
self._session_id = session_id
+1 -1
View File
@@ -363,7 +363,7 @@ class LivePerceptionIngress:
"control": 4,
"camera-init": 1,
"camera-frame": 2,
"lidar": 2,
"lidar": 8,
"pose": 16,
}
_MAX_PAYLOAD_BYTES: Final[dict[LiveIngressModality, int]] = {