Files
StarPilot/openpilot/starpilot/flm/tests/test_full_surface_reporting.py
T
firestar5683 2cd7728be2 FLM Auto-Weave
2026-10-17 18:38:27 -05:00

146 lines
6.1 KiB
Python

from dataclasses import replace
from types import SimpleNamespace
from openpilot.cereal import messaging
from openpilot.starpilot.flm.adaptive_profile import ApplicationOutcome
from openpilot.starpilot.flm.application_wire import write_application, read_application
from openpilot.starpilot.flm.selected_effects import EffectOwner
from openpilot.starpilot.flm.tests.test_selected_effect_owner import fixture as owner_fixture, BASE
from openpilot.starpilot.flm.tests.test_training_report import fixture, publish, NOW
from openpilot.starpilot.flm.training_report import read_report
from openpilot.starpilot.flm.torque_adapter import Admission
def trace():
old, p, v, _ = owner_fixture(accumulated=True)
envelope = replace(p.effect_envelope, coordinates=p.effect_envelope.prior_coordinates, full_profile_sha256=p.effect_envelope.prior_full_profile_sha256)
p = replace(p, observed_ns=NOW, expires_ns=NOW + 500_000_000, coefficients=(0.0,), effect_envelope=envelope)
v = replace(v, profile=p)
owner = EffectOwner(
p.identity, old.objective, selected_baseline_revision=BASE, physical_model_revision=v.physical_model_revision, original_anchor=envelope.replay_anchor()
)
context = {
'cp_sha256': envelope.cp_sha256,
'controller_revision': envelope.controller_revision,
'source_epoch': envelope.source_epoch,
'reset_generation': envelope.reset_generation,
'selected_baseline_revision': BASE,
'context_key': envelope.context_key,
'current_full_profile_sha256': envelope.prior_full_profile_sha256,
'persistent_source_epoch': envelope.persistent_source_epoch,
}
owner.prepare(Admission(p, NOW, True, False, True, v), active=True, current_context=context)
assert owner.applied_coordinates == (0.0,) and any(owner.applied_full.values())
return owner, p, v
def test_zero_current_group_nonzero_actual_other_group_reports_truthful_full30(tmp_path):
owner, p, v = trace()
collector, control, reporter, source, path = fixture(tmp_path)
actual = owner.trace
control = replace(
control,
identity=p.identity,
source_epoch=p.effect_envelope.source_epoch,
baseline_revision=BASE,
applied_coordinates=(0.0, 0.0),
effect_trace=actual,
effect_prepare_ns=NOW,
applied_profile_sequence=p.sequence,
applied_profile_observed_ns=p.observed_ns,
applied_profile_expires_ns=p.expires_ns,
)
collector.ready[-1] = (control, collector.ready[-1][1])
source.source_epoch = control.source_epoch
outcome = ApplicationOutcome(
p.identity,
p.sequence,
NOW,
'applied',
(0.0,),
'actual_stage_used',
BASE,
v.physical_model_revision,
actual.envelope.manifest_sha256,
actual.envelope.full_original_anchor,
actual.applied_full_profile_sha256,
)
event = messaging.new_message('starpilotLateralState', valid=True, logMonoTime=NOW)
write_application(event.starpilotLateralState, outcome)
assert read_application(event.starpilotLateralState, now_ns=NOW) == outcome
reporter.control = (event.as_reader(), control)
publish(reporter, collector, source)
current = read_report(path, now_ns=NOW)['current']
assert current['application']['applied']
assert current['details']['Actual full surface coordinates'] == [[n, v] for n, v in actual.applied]
assert current['details']['Actual full profile hash'] == actual.applied_full_profile_sha256
assert len(current['details']['Applied correction coordinates']) == 1
def test_hash_mismatch_never_claims_applied(tmp_path):
owner, p, v = trace()
collector, control, reporter, source, path = fixture(tmp_path)
actual = owner.trace
control = replace(
control,
identity=p.identity,
source_epoch=p.effect_envelope.source_epoch,
baseline_revision=BASE,
effect_trace=actual,
effect_prepare_ns=NOW,
applied_profile_sequence=p.sequence,
)
collector.ready[-1] = (control, collector.ready[-1][1])
source.source_epoch = control.source_epoch
outcome = ApplicationOutcome(
p.identity,
p.sequence,
NOW,
'applied',
(0.0,),
'actual_stage_used',
BASE,
v.physical_model_revision,
actual.envelope.manifest_sha256,
actual.envelope.full_original_anchor,
'0' * 64,
)
event = messaging.new_message('starpilotLateralState', valid=True, logMonoTime=NOW)
write_application(event.starpilotLateralState, outcome)
reporter.control = (event.as_reader(), control)
publish(reporter, collector, source)
current = read_report(path, now_ns=NOW)['current']
assert not current['application']['applied']
assert 'Actual full profile hash' not in current['details']
def test_actual_controller_changed_outside_group_sets_global_applied_status():
from opendbc.car import structs
from opendbc.car.car_helpers import interfaces
from openpilot.starpilot.flm.controller_replay import SelectedControllerFactory
from openpilot.starpilot.flm.global_runtime import GlobalRuntime
from openpilot.starpilot.flm.tests.test_selected_effect_callers import actual_paths
owner, p, v = trace()
key, raw = actual_paths()[0]
with structs.CarParams.from_bytes(raw) as cp:
factory = SelectedControllerFactory(cp, key[1], turn_assist=False)
controller, vm = factory.create()
runtime = GlobalRuntime(cp, interfaces[cp.carFingerprint](cp), controller)
runtime.effect_owner = owner
runtime.identity = p.identity
runtime.profile, runtime.validation = p, v
runtime.baseline_revision = BASE
runtime.now_ns = NOW
runtime.eligible = runtime.active = runtime.healthy = True
runtime.reason = 'qualified'
controller.automatic_flm_effects = owner
cs = structs.CarState.new_message(vEgo=30.0, canValid=True, steeringAngleDeg=0.0, steeringRateDeg=0.0, gearShifter='drive')
params = SimpleNamespace(angleOffsetDeg=0.0, roll=0.0)
output, _, log = controller.update(True, cs, vm, params, False, 0.00001, False, 0.15)
assert owner.used and owner.changed
runtime._finish_frame(cs, vm, params, log, desired_curvature=0.00001, curvature_limited=False, lat_delay=0.15, requested=output, selected_command=output)
assert runtime.outcome.status == 'applied'
assert runtime.outcome.actual_coordinates == (0.0,)
assert runtime.outcome.effect_applied_profile_sha256 == owner.trace.applied_full_profile_sha256