feat(perception): export bounded runtime observations outside heartbeat lane
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
"""Observability is bounded and cannot become model ownership/readiness."""
|
||||
|
||||
import json
|
||||
import threading
|
||||
|
||||
from k1link.perception.realtime_contract import StreamStart
|
||||
from k1link.perception.runtime_telemetry import MAX_BYTES, RuntimeTelemetryPublisher, observation
|
||||
from k1link.perception.streaming_lifecycle import StreamingLifecycle
|
||||
from k1link.perception.streaming_queue import StreamMailbox
|
||||
|
||||
|
||||
def test_observation_tracks_wait_without_renewing_or_stopping_runtime(tmp_path):
|
||||
start = StreamStart(
|
||||
"run",
|
||||
"source",
|
||||
"worker-006",
|
||||
"epoch",
|
||||
1,
|
||||
"a" * 64,
|
||||
"b" * 64,
|
||||
"c" * 64,
|
||||
"d" * 64,
|
||||
"clock",
|
||||
"live",
|
||||
)
|
||||
runtime = StreamingLifecycle(
|
||||
start,
|
||||
tmp_path / "lease",
|
||||
StreamMailbox(),
|
||||
threading.Event(),
|
||||
recover_input=True,
|
||||
source_clock_ns=lambda: 1000,
|
||||
)
|
||||
try:
|
||||
runtime.ready()
|
||||
before = runtime.lease.renewals
|
||||
assert observation(runtime, "Profile")["service_state"] == "running"
|
||||
runtime.pause_input(start, "input-timeout")
|
||||
waiting = observation(runtime, "Profile")
|
||||
assert waiting["service_state"] == "waiting"
|
||||
assert waiting["input_pauses"] == 1
|
||||
assert waiting["actuation_allowed"] is False
|
||||
assert len(json.dumps(waiting).encode()) < MAX_BYTES
|
||||
assert runtime.lease.renewals == before and not runtime.stop_event.is_set()
|
||||
runtime.begin_input(start)
|
||||
assert observation(runtime, "Profile")["service_state"] == "synchronizing"
|
||||
publisher = RuntimeTelemetryPublisher(runtime, tmp_path / "current.json", "Profile")
|
||||
try:
|
||||
runtime.renew(start)
|
||||
assert runtime.close()
|
||||
finally:
|
||||
assert publisher.close()
|
||||
assert json.loads((tmp_path / "current.json").read_text())["service_state"] == "stopped"
|
||||
finally:
|
||||
runtime.close()
|
||||
|
||||
|
||||
def test_export_failure_is_lossy_not_terminal(tmp_path):
|
||||
start = StreamStart(
|
||||
"run",
|
||||
"source",
|
||||
"worker-006",
|
||||
"epoch",
|
||||
1,
|
||||
"a" * 64,
|
||||
"b" * 64,
|
||||
"c" * 64,
|
||||
"d" * 64,
|
||||
"clock",
|
||||
"live",
|
||||
)
|
||||
runtime = StreamingLifecycle(start, tmp_path / "lease", StreamMailbox(), threading.Event())
|
||||
(tmp_path / "current.json").mkdir() # os.replace cannot replace this directory.
|
||||
publisher = RuntimeTelemetryPublisher(runtime, tmp_path / "current.json", "Profile")
|
||||
try:
|
||||
assert publisher.close()
|
||||
assert publisher.failures > 0
|
||||
runtime.ready()
|
||||
runtime.renew(start)
|
||||
assert not runtime.stop_event.is_set()
|
||||
finally:
|
||||
runtime.close()
|
||||
Reference in New Issue
Block a user