Harden RF handoff and stream OTA decode
This commit is contained in:
@@ -31,6 +31,7 @@ from tools.rf_handoff_smoke import run_smoke
|
||||
from tools.rx_agent_watcher import (
|
||||
WatcherState as RxWatcherState,
|
||||
publish_result,
|
||||
require_live_ready_window,
|
||||
save_state as save_rx_state,
|
||||
)
|
||||
from tools.tx_agent_watcher import (
|
||||
@@ -59,7 +60,7 @@ def ready_result(**changes: object) -> RxHandoffResult:
|
||||
capture_pid=1234,
|
||||
published_at=NOW.isoformat(),
|
||||
capture_started_at=NOW.isoformat(),
|
||||
expected_capture_end=(NOW + timedelta(seconds=120)).isoformat(),
|
||||
expected_capture_end=(NOW + timedelta(seconds=60)).isoformat(),
|
||||
capture_path=r"C:\captures\rf001a_ota_capture.cs8",
|
||||
common_clock_verified=True,
|
||||
source_head=HEAD,
|
||||
@@ -97,10 +98,10 @@ def complete_result(
|
||||
rx_ready_for_tx=False,
|
||||
process_alive=False,
|
||||
file_growing=False,
|
||||
published_at=(NOW + timedelta(seconds=121)).isoformat(),
|
||||
published_at=(NOW + timedelta(seconds=61)).isoformat(),
|
||||
exit_code=0,
|
||||
file_size=1_920_000_000,
|
||||
duration_seconds=120.01,
|
||||
file_size=960_000_000,
|
||||
duration_seconds=60.01,
|
||||
overruns=0,
|
||||
usb_errors=0,
|
||||
file_errors=0,
|
||||
@@ -278,7 +279,7 @@ def test_complete_result_accepts_explicit_unreported_counters() -> None:
|
||||
ready_result(
|
||||
published_at=(NOW - timedelta(seconds=31)).isoformat(),
|
||||
capture_started_at=(NOW - timedelta(seconds=31)).isoformat(),
|
||||
expected_capture_end=(NOW + timedelta(seconds=89)).isoformat(),
|
||||
expected_capture_end=(NOW + timedelta(seconds=29)).isoformat(),
|
||||
),
|
||||
NOW,
|
||||
"STALE_READY",
|
||||
@@ -290,7 +291,7 @@ def test_complete_result_accepts_explicit_unreported_counters() -> None:
|
||||
),
|
||||
(
|
||||
ready_result(
|
||||
capture_started_at=(NOW - timedelta(seconds=111)).isoformat(),
|
||||
capture_started_at=(NOW - timedelta(seconds=51)).isoformat(),
|
||||
expected_capture_end=(NOW + timedelta(seconds=9)).isoformat(),
|
||||
),
|
||||
NOW,
|
||||
@@ -329,7 +330,7 @@ def test_ready_evaluation_passes_with_more_than_ten_seconds() -> None:
|
||||
)
|
||||
assert evaluation.ready
|
||||
assert evaluation.reason == "READY"
|
||||
assert evaluation.seconds_remaining == pytest.approx(118.0)
|
||||
assert evaluation.seconds_remaining == pytest.approx(58.0)
|
||||
|
||||
|
||||
def test_red_approval_and_duplicate_suppression(tmp_path: Path) -> None:
|
||||
@@ -378,7 +379,7 @@ def test_window_and_commit_are_rechecked_after_exact_approval(tmp_path: Path) ->
|
||||
digest = result_digest(result)
|
||||
source = FakeSource(result, digest)
|
||||
executor = FakeExecutor(tmp_path / "fake_tx.txt")
|
||||
times = iter((NOW + timedelta(seconds=2), NOW + timedelta(seconds=111)))
|
||||
times = iter((NOW + timedelta(seconds=2), NOW + timedelta(seconds=51)))
|
||||
|
||||
status, _ = handle_result(
|
||||
result,
|
||||
@@ -600,7 +601,7 @@ def test_expired_historical_ready_is_observed_without_authorization(
|
||||
started = NOW - timedelta(seconds=200)
|
||||
expired = ready_result(
|
||||
capture_started_at=started.isoformat(),
|
||||
expected_capture_end=(started + timedelta(seconds=120)).isoformat(),
|
||||
expected_capture_end=(started + timedelta(seconds=60)).isoformat(),
|
||||
published_at=(NOW - timedelta(seconds=100)).isoformat(),
|
||||
)
|
||||
expired_outcome = channel.publish(expired)
|
||||
@@ -796,9 +797,16 @@ Fake task used only by the local coordination test.
|
||||
)
|
||||
source_head = _git(["rev-parse", "HEAD"], work)
|
||||
|
||||
fresh_start = datetime.now(timezone.utc)
|
||||
fresh_result = ready_result(
|
||||
source_head=source_head,
|
||||
published_at=fresh_start.isoformat(),
|
||||
capture_started_at=fresh_start.isoformat(),
|
||||
expected_capture_end=(fresh_start + timedelta(seconds=60)).isoformat(),
|
||||
)
|
||||
result_path = tmp_path / "ready.json"
|
||||
result_path.write_text(
|
||||
canonical_result_json(ready_result(source_head=source_head)),
|
||||
canonical_result_json(fresh_result),
|
||||
encoding="utf-8",
|
||||
)
|
||||
state_path = tmp_path / "rx_state.json"
|
||||
@@ -824,4 +832,12 @@ Fake task used only by the local coordination test.
|
||||
assert "RF TX = 0" in output
|
||||
|
||||
published, _digest, _head = GitResultChannel(work).read()
|
||||
assert published == ready_result(source_head=source_head)
|
||||
assert published == fresh_result
|
||||
|
||||
|
||||
def test_rx_publisher_refuses_ready_after_capture_window() -> None:
|
||||
with pytest.raises(ValueError, match="window has already ended"):
|
||||
require_live_ready_window(
|
||||
ready_result(),
|
||||
now=NOW + timedelta(seconds=60),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user