From 64eba05e62036366aae640468287376de04afac7 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Fri, 30 Oct 2026 19:27:50 -0500 Subject: [PATCH] Capture genuine FLM checkpoints before the reconstruction age ceiling --- openpilot/starpilot/flm/global_runtime.py | 4 +- .../flm/tests/test_capture_gap_recovery.py | 42 +++++++++++++++++++ .../flm/tests/test_pid_global_capture.py | 2 +- prebuilt.json | 2 +- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/openpilot/starpilot/flm/global_runtime.py b/openpilot/starpilot/flm/global_runtime.py index 10803c0ecc..72a2ebbf22 100644 --- a/openpilot/starpilot/flm/global_runtime.py +++ b/openpilot/starpilot/flm/global_runtime.py @@ -563,11 +563,11 @@ class GlobalRuntime: self.snapshot = self.replay_inputs = () return try: - from openpilot.starpilot.flm.controller_replay import capture_snapshot, frame_input + from openpilot.starpilot.flm.controller_replay import MAX_CHECKPOINT_NS, capture_snapshot, frame_input self.snapshot = () if self.identity and self.descriptor.domain != 'ford_curvature' and (not self.snapshot_ns or self.frame_sequence != self.last_capture_frame + 1 or - self.now_ns - self.snapshot_ns >= 1_000_000_000): + self.now_ns - self.snapshot_ns >= MAX_CHECKPOINT_NS // 2): if self.descriptor.domain in ('torque', 'torque_pid'): self.snapshot = capture_snapshot(self.controller, vm).values else: diff --git a/openpilot/starpilot/flm/tests/test_capture_gap_recovery.py b/openpilot/starpilot/flm/tests/test_capture_gap_recovery.py index 9b557f711d..300ff9a7dd 100644 --- a/openpilot/starpilot/flm/tests/test_capture_gap_recovery.py +++ b/openpilot/starpilot/flm/tests/test_capture_gap_recovery.py @@ -73,3 +73,45 @@ def test_actual_capture_resumes_with_original_checkpoint(vehicle, mode, missing) assert adapter is not None and len(adapter.replay.records) >= 30 assert controls.CP.as_builder().to_bytes() == before assert runtime.applied_coordinates == (0., 0.) + + +@pytest.mark.parametrize('vehicle,mode', [(HKG.HYUNDAI_IONIQ_6, 'starpilot'), (HONDA.HONDA_CIVIC, None)]) +def test_original_checkpoints_stay_inside_existing_bound_with_publication_jitter(vehicle, mode): + from openpilot.starpilot.flm.controller_replay import MAX_CHECKPOINT_NS + assert MAX_CHECKPOINT_NS == 1_000_000_000 + cp = interfaces[vehicle].get_non_essential_params(vehicle) + with controls_for(cp, mode, True) as controls: + adapter = None + snapshots = 0 + previous_publication = 0 + for tick in range(351): + jitter = 8_000_000 if tick in (199, 200) else 0 + now = BASE + tick * 10_000_000 + jitter + with mock.patch('openpilot.starpilot.flm.tests.test_live_calibration_paths.BASE', BASE + jitter): + output = live_frame(controls, tick, 'a' * 32) + runtime = controls.global_learning + # Both delays fit the unchanged30ms capture bound. A capture taken at + # the full1s reconstruction ceiling can expire before the next capture. + published = now + (1_000_000 if runtime.snapshot else 4_759_900) + assert published > previous_publication + previous_publication = published + controls.pm.send.reset_mock() + with (mock.patch('openpilot.selfdrive.controls.controlsd.time.monotonic_ns', return_value=published), + mock.patch('openpilot.cereal.messaging.time.monotonic', return_value=published / 1e9)): + controls.publish(*output) + event = next(call.args[1] for call in controls.pm.send.call_args_list if call.args[0] == 'starpilotLateralState') + event = messaging.log_from_bytes(event.to_bytes()) + if tick < 100: + continue + assert event.starpilotLateralState.learningEvidence.version + evidence = read_control(event) + if adapter is None: + if not evidence.replay_snapshot: + continue + adapter = production_adapter_for_evidence(controls.CP, evidence, objective_key(evidence), source=runtime.source) + assert adapter is not None + snapshots += bool(evidence.replay_snapshot) + assert adapter.prepare_control(evidence) is not None, (tick, evidence.control_ns - adapter.replay.checkpoint_ns) + assert evidence.control_ns - adapter.replay.checkpoint_ns <= MAX_CHECKPOINT_NS + assert adapter is not None and len(adapter.replay.records) >= 200 + assert 4 <= snapshots <= 7, 'Original checkpoints stay periodic rather than copying the controller at100Hz' diff --git a/openpilot/starpilot/flm/tests/test_pid_global_capture.py b/openpilot/starpilot/flm/tests/test_pid_global_capture.py index 64c4d5d489..9839f7db79 100644 --- a/openpilot/starpilot/flm/tests/test_pid_global_capture.py +++ b/openpilot/starpilot/flm/tests/test_pid_global_capture.py @@ -50,7 +50,7 @@ def test_actual_controls_pid_collects_own_trace_without_changing_disabled_baseli assert evidence.domain=='normalized_torque' assert evidence.effect_trace is None # Check the actual emitted checkpoint, not an arbitrary inter-checkpoint - # frame: the production wire publishes frozen state once per second. + # frame: the production wire publishes frozen state periodically. assert emitted_snapshots and runtime.snapshot_sequence>0 assert all(any(name=='controller.ff_factor' for name,_ in snapshot) for snapshot in emitted_snapshots) assert all(not any(name.startswith('tune.') for name,_ in snapshot) for snapshot in emitted_snapshots) diff --git a/prebuilt.json b/prebuilt.json index 5e1838c81c..3ee98fe06b 100644 --- a/prebuilt.json +++ b/prebuilt.json @@ -1 +1 @@ -{"protected_inventory_sha256": "768d4c513a5bd1dc0e9fc9bd1edfb0c41ed744835fae3a50dc21e83f377b0240", "schema_version": 1} +{"protected_inventory_sha256": "3859ba9b1e2e03ab97c992fb59a88cb029558b0d3374fcf72fa4949260cd0b53", "schema_version": 1}