import {AuthorityModel, type Decision} from '../../../../packages/rover-control/src/authority'; import {type ControlProfile} from '../../../../packages/rover-control/src/profile'; /** Synthetic event replay, with no wall clock, I/O, timers or hardware adapter. */ export function trace(profile: ControlProfile): {label: string; decision: Decision}[] { const model = new AuthorityModel(profile, ['left', 'right'], { maxAgeMs:100, neutralMs:200, maxCommandMs:100, monitoredAxes:['leftY','rightY','leftX','rightX'], }, 'preview'); const rows: {label:string;decision:Decision}[] = []; let now = -50, token = ''; function step(value=0, link: 'live'|'lost'='live', core=false, request=false) { now+=50; const axes = {leftY:0,rightY:0,leftX:0,rightX:0}; axes[profile.mode==='tank'?'leftY':profile.stick==='left'?'leftY':'rightY']=value; return model.step({now, link:{state:link,at:now}, axes:Object.fromEntries(Object.entries(axes).map(([key,v])=>[key,{value:v,at:now,sequence:now}])), drives:{left:{healthy:true,stopped:value===0,at:now},right:{healthy:true,stopped:value===0,at:now}}, requestCore:request?{owner:'autonomy',at:now,sequence:1}:undefined, command:core?{token,at:now,expires:now+75,sequence:now,demand:{left:.4,right:.4}}:undefined, }); } const add=(label:string,decision:Decision)=>rows.push({label,decision}); for(let i=0;i<5;i++)step(); const grant=step(0,'live',false,true);token=grant.token??''; add('Mission Core получил явный допуск',grant); add('Автономная команда движения',step(0,'live',true)); add('Первое отклонение рычага',step(.8,'live',true)); for(let i=0;i<20;i++)step(.8); add('Тот же рычаг удерживается',step(.8)); add('Остановка подтверждена, оба рычага отпущены',step()); for(let i=0;i<3;i++)step(); add('Непрерывная нейтраль подтверждена',step()); add('Второе отклонение — ручное движение',step(.8)); add('Запоздавшая команда прежней задачи',step(.8,'live',true)); add('Радиосвязь потеряна',step(0,'lost')); add('Связь вернулась с отклонённым рычагом',step(.8)); return rows; }