"""Feedback chronology units plus actual registered controller/native paths. Mocked original-tape seals in caller units grant NO original/current admission. Fresh actual owner capture remains required for complete qualification. """ from types import SimpleNamespace import pickle import pytest from openpilot.starpilot.flm.candidate_feedback import CandidateFeedbackLoop,CLOSED_POLICY,LEGACY_POLICY,policy from openpilot.starpilot.flm.feedback_observation import f32 from openpilot.starpilot.flm.torque_emission_replay import EmissionHistory def arithmetic_fixture(monkeypatch, *, context=False, two_windows=False): from openpilot.starpilot.flm import feedback_replay stamps = (100,110,120,130) if not two_windows else (100,110,200,210) rows = [] for index,stamp in enumerate(stamps): previous = stamps[index-1] if index else 0 row = SimpleNamespace(control_ns=stamp,prior_publish_ns=previous,publication_ns=stamp-1, recv_frame=index+1,receipt_ns=stamp,co_body_sha256='1'*64, reported_torque=f32(.18199999630451202),requested_torque=f32(.17206627130508423), lat_active=True,input_limited=False,published_limited=False) pub = SimpleNamespace(output_control_ns=stamp-10,output_apply_ns=stamp-9, publication_ns=stamp-1,output_carrier_sequence=index+1,native_identity='2'*64, applied_sha256='3'*64,reported_torque=row.reported_torque) rows.append(SimpleNamespace(consumption=row,publication=pub)) context_rows = (rows[0].consumption,) if context else () if two_windows: windows = (((100,110),SimpleNamespace(rows=tuple(rows[:2]),digest='4'*64),100), ((200,210),SimpleNamespace(rows=tuple(rows[2:]),digest='5'*64),200)) else: windows = (((100,130),SimpleNamespace(rows=tuple(rows[1:] if context else rows),digest='4'*64),110 if context else 100),) evidence = SimpleNamespace(candidate_policy=CLOSED_POLICY,engine_input_digest='a'*64, original=SimpleNamespace(context_only=context_rows,digest='b'*64),windows=windows) engine = SimpleNamespace(emissions=EmissionHistory.__new__(EmissionHistory),verified_feedback_tape=evidence) monkeypatch.setattr(feedback_replay,'require_feedback_engine',lambda owner:evidence) frames = tuple(SimpleNamespace(control_ns=stamp,inputs=(('active',1.),('safety_limited',0.),('untouched',-0.))) for stamp in stamps) return engine,rows,frames @pytest.mark.parametrize('candidate_request,reported',[(.17249134182929993,.18266665935516357),(.17164121568202972,.18199999630451202)]) def test_demonstrated_threshold_crossing_feeds_next_update_not_current(monkeypatch,candidate_request,reported): engine,rows,frames = arithmetic_fixture(monkeypatch) reports = {} loop = CandidateFeedbackLoop(engine,reports,(.01,),native_policy='strict') requests = {} previous = False observed_inputs = [] for _index,(joined,frame) in enumerate(zip(rows,frames,strict=True)): reports[joined.publication.output_apply_ns] = f32(reported) before = loop.before(frame) assert dict(before)['safety_limited'] == float(previous) observed_inputs.append(previous) assert pickle.dumps(tuple(pair for pair in before if pair[0]!='safety_limited')) == pickle.dumps( tuple(pair for pair in frame.inputs if pair[0]!='safety_limited')) requests[frame.control_ns] = f32(candidate_request) loop.after(frame.control_ns,candidate_request) consumed = joined.publication.reported_torque if joined.publication.output_control_ns < 100 else f32(reported) previous = abs(f32(candidate_request)-consumed) > .01 assert any(observed_inputs) proof = loop.finish(requests,reports) assert proof.row_count == 4 and proof.native_policy == 'strict' assert proof.original_digest == engine.verified_feedback_tape.original.digest def test_missing_consumed_native_report_never_uses_nearest_or_physical_value(monkeypatch): engine,rows,frames = arithmetic_fixture(monkeypatch) reports = {} loop = CandidateFeedbackLoop(engine,reports,(.01,),native_policy='strict') loop.before(frames[0]) loop.after(frames[0].control_ns,.17249134182929993) reports[rows[2].publication.output_apply_ns] = 0. # Wrong apply coordinate is not a fallback. loop.before(frames[1]) with pytest.raises(ValueError,match='not yet produced'): loop.after(frames[1].control_ns,.17249134182929993) def test_complete_finish_rejects_changed_native_result_or_omitted_frame(monkeypatch): engine,rows,frames = arithmetic_fixture(monkeypatch) reports,requests = {},{} loop = CandidateFeedbackLoop(engine,reports,(.01,),native_policy='native-shadow-identification') for joined,frame in zip(rows,frames,strict=True): reports[joined.publication.output_apply_ns] = f32(.18266665935516357) loop.before(frame) requests[frame.control_ns]=f32(.17249134182929993) loop.after(frame.control_ns,requests[frame.control_ns]) reports[rows[-1].publication.output_apply_ns] = f32(.17) with pytest.raises(ValueError,match='changed'): loop.finish(requests,reports) fresh = CandidateFeedbackLoop(engine,{},(.01,),native_policy='strict') with pytest.raises(ValueError,match='omitted'): fresh.finish({},fresh.reported) def test_context_prefix_and_window_checkpoints_use_real_original_prior(monkeypatch): engine,rows,frames = arithmetic_fixture(monkeypatch,context=True) reports,requests = {},{} loop = CandidateFeedbackLoop(engine,reports,(.01,),native_policy='strict') for index,(joined,frame) in enumerate(zip(rows,frames,strict=True)): reports[joined.publication.output_apply_ns] = f32(.18266665935516357) inputs=loop.before(frame) request=joined.consumption.requested_torque if index==0 else f32(.17249134182929993) requests[frame.control_ns]=request loop.after(frame.control_ns,request) assert dict(inputs)['safety_limited'] == (0. if index<3 else 1.) assert loop.finish(requests,reports).row_count == 4 engine,rows,frames = arithmetic_fixture(monkeypatch,two_windows=True) reports,requests = {},{} loop = CandidateFeedbackLoop(engine,reports,(.01,),native_policy='strict') for index,(joined,frame) in enumerate(zip(rows,frames,strict=True)): reports[joined.publication.output_apply_ns] = f32(.18266665935516357) assert dict(loop.before(frame))['safety_limited'] == (0. if index in (0,2) else 1.) requests[frame.control_ns]=f32(.17164121568202972) loop.after(frame.control_ns,requests[frame.control_ns]) assert loop.finish(requests,reports).row_count == 4 def test_original_baseline_and_pre_activation_remain_exact(monkeypatch): engine,rows,frames = arithmetic_fixture(monkeypatch,context=True) reports={} loop=CandidateFeedbackLoop(engine,reports,(0.,),native_policy='strict',original_baseline=True) loop.before(frames[0]) with pytest.raises(ValueError,match='baseline or preactivation'): loop.after(frames[0].control_ns,.17249134182929993) for unknown in (None,'made-up',1): with pytest.raises(ValueError,match='policy'): policy(unknown) assert policy(LEGACY_POLICY)==LEGACY_POLICY def actual_caller_fixture(domain): """Actual controller/CAN numeric unit; original source seal remains mocked.""" from openpilot.starpilot.flm.controller_replay import ControllerReplay,ReplayFrame,SelectedControllerFactory,_run,capture_snapshot,final_command,frame_input from openpilot.starpilot.flm.pid_controller_replay import PidControllerFactory from openpilot.starpilot.flm.event_controller_replay import EventControllerReplay from openpilot.starpilot.flm.event_activation import EventActivationPlan,ZERO_REFERENCE_ACTIVATION_VERSION from openpilot.starpilot.flm.event_objective import EffectObjective from openpilot.starpilot.flm.torque_adapter import Objective from openpilot.starpilot.flm.torque_emission_replay import Emission from openpilot.starpilot.flm.tests.test_full_surface_profile import base from openpilot.starpilot.flm.effect_trace import FullEffectTrace from openpilot.starpilot.flm.selected_effects import EffectReplayRecordedSource from openpilot.starpilot.flm.tests.test_event_lazy_native import TOYOTA,HYUNDAI,HONDA,make_interface,install_observer,settle,control,apply,BASE_NS platform={'torque':TOYOTA.TOYOTA_COROLLA_TSS2,'starpilot':HYUNDAI.HYUNDAI_IONIQ_6,'pid':HONDA.HONDA_CIVIC}[domain] ci=make_interface(platform) assert install_observer(ci) settled=settle(ci,control(0.)) factory=PidControllerFactory(ci.CP,'native') if domain=='pid' else SelectedControllerFactory(ci.CP,'starpilot' if domain=='starpilot' else 'standard') objective=Objective('feedforward','high','steady') original=ControllerReplay(factory,objective,identity='f'*64,baseline_revision='a'*64) actual,vm=factory.create() original.raw_mode=True first=BASE_NS+ci.CC.frame*10_000_000 original.checkpoint(first,capture_snapshot(actual,vm)) previous_flag=False previous_report=f32(settled[-1][0].torque) prior_stamp=BASE_NS+settled[-1][2].frame*10_000_000 previous_event=SimpleNamespace(control_ns=prior_stamp,apply_ns=prior_stamp+1_000_000) frames,joins,contexts=[],[],[] envelope=base() for tick in range(60): stamp=first+tick*10_000_000 inputs=frame_input(ci.CS.out,vm,SimpleNamespace(angleOffsetDeg=0.,roll=0.),active=True, safety_limited=previous_flag,desired_curvature=.00003,curvature_limited=False,lat_delay=.2) inputs+=(('control_frame',float(tick+1)),('raw_model_curvature',.00003)) tuning=() if domain=='pid' else (('effective_factor',float(actual.torque_params.latAccelFactor)), ('offset',float(actual.torque_params.latAccelOffset)),('friction',float(actual.torque_params.friction)), ('pid_pos_limit',float(actual.pid.pos_limit)),('pid_neg_limit',float(actual.pid.neg_limit))) trace=FullEffectTrace(1,envelope,stamp,stamp-10_000_000,True, envelope.coordinates,envelope.coordinates,envelope.coordinates,envelope.full_profile_sha256).validate() value,_=_run(actual,vm,inputs,objective,(0.,0.),tuning,actual_stage_residual=(0.,0.), effect_trial=EffectReplayRecordedSource(trace)) request=f32(final_command(value)) flag=bool(abs(request-previous_report)>.01) row=SimpleNamespace(control_ns=stamp,prior_publish_ns=stamp-10_000_000 if tick else 0, publication_ns=stamp-1,recv_frame=tick+1,receipt_ns=stamp,co_body_sha256='1'*64, reported_torque=previous_report,requested_torque=request,lat_active=True, input_limited=previous_flag,published_limited=flag) if previous_event is None: contexts.append(row) else: pub=SimpleNamespace(output_control_ns=previous_event.control_ns,output_apply_ns=previous_event.apply_ns, publication_ns=stamp-1,output_carrier_sequence=tick,native_identity='2'*64,applied_sha256='3'*64, reported_torque=previous_report) joins.append(SimpleNamespace(consumption=row,publication=pub)) frame=ReplayFrame(stamp,inputs,request,(0.,0.),frame_sequence=tick+1,actual_lac_command=value, limited=flag,torque_values=tuning,actual_stage_residual=(0.,0.), effect_trace=trace,effect_prepare_ns=trace.control_ns, controller_domain='torque_pid' if domain=='pid' else 'torque') frames.append(frame) output,packets,witness=apply(ci,control(value)) if witness is not None: assert (witness.can_address,witness.can_data,witness.can_bus) in packets clipped=witness.unlimited_raw is None or witness.unlimited_raw!=witness.final_raw event=Emission(stamp,stamp,stamp+1_000_000,witness,'f'*64,'e'*64,'a'*64, True,True,False,False,clipped,False,False,0,0,'') original.emissions.events[event.apply_ns]=event original.emissions.decode_queue.append(event.apply_ns) original.emissions.by_control[event.control_ns]=event previous_event=event previous_report=f32(output.torque) previous_flag=flag assert not contexts original.records.extend(frames) bounds=(frames[0].control_ns,frames[-1].control_ns) original.replay_windows=(bounds,) selected=EffectObjective('ff.left',envelope.trial_names,envelope.trial_anchor,envelope.context_key) activation=frames[30].control_ns prepare=frames[30].effect_prepare_ns assert prepare==frames[30].effect_trace.control_ns==activation plan=EventActivationPlan(ZERO_REFERENCE_ACTIVATION_VERSION,original.identity,original.baseline_revision, selected.context_key,'b'*64,tuple('train-'+str(i) for i in range(4)),tuple('held-'+str(i) for i in range(4)), activation-10_000_000,tuple('stage-'+str(i) for i in range(9)),((bounds[0],bounds[1],activation,prepare),)).validate() engine=EventControllerReplay(original,selected,envelope.replay_anchor(),activation_plan=plan) evidence=SimpleNamespace(candidate_policy=CLOSED_POLICY,engine_input_digest='a'*64, binding='c'*64,original=SimpleNamespace(context_only=tuple(contexts),digest='b'*64), windows=((bounds,SimpleNamespace(rows=tuple(joins),digest='d'*64),activation),)) engine.verified_feedback_tape=evidence return engine,evidence,tuple(joins),tuple(contexts) @pytest.mark.parametrize('domain',['torque','starpilot','pid']) @pytest.mark.parametrize('coordinates',[(0.,),(.00001,)]) @pytest.mark.parametrize('shadow',[False,True]) def test_actual_selected_controller_native_interleave_and_next_input(domain,coordinates,shadow,monkeypatch): from openpilot.starpilot.flm import feedback_replay,event_controller_replay engine,evidence,joins,contexts=actual_caller_fixture(domain) monkeypatch.setattr(feedback_replay,'require_feedback_engine',lambda owner:evidence) updates=[] native_sink=[] original_run=event_controller_replay._run original_native=engine.emissions.rollout def update(*args,**kwargs): result=original_run(*args,**kwargs) updates.append((args[2],f32(result[0]))) return result def native(*args,**kwargs): native_sink.append(kwargs['feedback_reported']) return original_native(*args,**kwargs) monkeypatch.setattr(event_controller_replay,'_run',update) monkeypatch.setattr(engine.emissions,'rollout',native) kwargs={'_identification_token':engine._EventControllerReplay__identification_token} if shadow else {} requests,encoded,_=engine._rollout_uncached(coordinates,**kwargs) assert len(updates)==len(engine.records)==60 reports=native_sink[0] associations={joined.consumption.control_ns:joined for joined in joins} context={row.control_ns:row for row in contexts} activation=evidence.windows[0][2] previous=False for frame,(inputs,request) in zip(engine.records,updates,strict=True): assert dict(inputs)['safety_limited']==float(previous) assert pickle.dumps(tuple(pair for pair in inputs if pair[0]!='safety_limited'))==pickle.dumps( tuple(pair for pair in frame.inputs if pair[0]!='safety_limited')) if frame.control_ns in context: row=context[frame.control_ns] report=row.reported_torque else: joined=associations[frame.control_ns] row=joined.consumption pub=joined.publication report=pub.reported_torque if pub.output_control_ns.01) if frame.control_ns