feat(perception): enforce six-layer freshness through receipt

This commit is contained in:
DCCONSTRUCTIONS
2026-09-02 10:14:28 +03:00
parent 4e633a662c
commit 097e450a87
9 changed files with 1067 additions and 43 deletions
+17 -2
View File
@@ -181,6 +181,9 @@ class LayerEvidence:
source_time_ns: int | None
state: str
payload_sha256: str | None
# Old callers omit this field. New layered results require it explicitly:
# recomputing a derived layer cannot refresh the age of its required inputs.
oldest_required_input_time_ns: int | None = None
def __post_init__(self) -> None:
if self.layer not in REQUIRED_LAYERS:
@@ -191,13 +194,22 @@ class LayerEvidence:
if self.state == "unavailable":
if any(
x is not None
for x in (self.source_sequence, self.source_time_ns, self.payload_sha256)
for x in (
self.source_sequence,
self.source_time_ns,
self.payload_sha256,
self.oldest_required_input_time_ns,
)
):
raise RealtimeContractError("unavailable evidence cannot claim a payload")
else:
_integer(self.source_sequence, "source_sequence")
_integer(self.source_time_ns, "source_time_ns")
_digest(self.payload_sha256, "payload_sha256")
if self.oldest_required_input_time_ns is not None:
_integer(self.oldest_required_input_time_ns, "oldest_required_input_time_ns")
if self.oldest_required_input_time_ns > cast(int, self.source_time_ns):
raise RealtimeContractError("required input is newer than its layer")
def validate_scene_layers(
@@ -223,7 +235,10 @@ def validate_scene_layers(
raise RealtimeContractError("layer belongs to another stream epoch")
if layer.source_time_ns is None:
continue
age_ns = source_time_ns - layer.source_time_ns
if layer.source_time_ns > source_time_ns:
raise RealtimeContractError("future observations are not causal input")
stamp = layer.oldest_required_input_time_ns
age_ns = source_time_ns - (layer.source_time_ns if stamp is None else stamp)
if age_ns < 0:
raise RealtimeContractError("future observations are not causal input")
if age_ns > maximum_layer_age_ms * 1_000_000 and layer.state in ("current", "held"):