"""Execute actual mounted courier admission/state/cleanup methods with native doubles.""" import os,re from pathlib import Path from policy_harness import ROOT,body,run from test_finite_magazine_reservation import translated_reservation p=Path(os.environ.get('ERR_MOUNTED_RESUPPLY_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_MountedResupply.c')) s=p.read_text() for forbidden in ('SetAmmoCount','SetOrigin','SetTransform','GetOutType.TELEPORT','TrySpawn','DeleteEntity','AddWaypoint'): assert forbidden not in s,forbidden assert 'm_MagazineSlot.IsLocked()' in body(p,'protected bool SelectTarget()') # Native owned-root/collector/access predicates have separate actual-method tests; # here execute the actual coordinator which consumes their results. sigs=['protected bool OwnedTrip()', 'bool Busy()', 'bool Unresolved()', 'protected bool Active()', 'bool Begin(', 'protected void ClearAction()', 'protected void Cleanup()', 'protected bool Board(', 'protected void Abort(', 'void Stop()', 'void Tick('] code='\n'.join(body(p,sig) for sig in sigs) code=re.sub(r'//[^\n]*','',code).replace('protected ','').replace('ref ','').replace('null','nullptr').replace('array<','Array<') code=code.replace('ERR_SupplyConvoyTask.Cast(m_Convoy)','m_Convoy').replace('Vehicle.Cast(Root)','Root') code=code.replace('SCR_ChimeraAIAgent.Cast(SCR_AIUtils.GetAIAgent(m_Worker))','GetAgent(m_Worker)') code=code.replace('priority: ','') for n in ('ERR_InfantryResupplyRules','ERR_GameMode','ERR_Actors','ERR_ConvoyMountedCrew','ERR_InfantryAmmoAccess','ERR_ForceRules','SCR_AICompartmentHandling','CompartmentAccessComponent','vector','Math','Replication'): code=code.replace(n+'.',n+'::') for n in ('m_HQ','m_Mode','m_Convoy','m_Stock','m_Spent','m_Consumed','m_NextAttempt','recipient','donor','demand','donorStatus','m_Truck','m_Target','m_Reservation','m_Recipient','m_Donor','m_Utility','m_Action','agent','m_Seat','m_Pickup','m_Swap','m_DonorOrder','m_RecipientOrder','m_MagazineSlot'): code=re.sub(r'\b'+n+r'\.',n+'->',code) code=code.replace('].Group',']->Group').replace('demand->MountedAmmo.','demand->MountedAmmo->').replace('m_Recipient->StatusSampler','m_Recipient->StatusSampler') code=code.replace('ERR_GameMode::Get()', 'Mode::Get()').replace('Array', 'Array') code=code.replace('m_Convoy->Vehicles[i].','m_Convoy->Vehicles[i]->') code=code.replace('ERR_HQUnit ','Unit* ').replace('ERR_HQWatchEntry ','Watch* ').replace('SCR_ChimeraAIAgent ','Agent* ') code=code.replace('new ERR_FiniteMagazineReservation(m_Stock, m_Spent,','new ERR_FiniteMagazineReservation(m_Stock, m_Spent,') pre=r''' #include #include #include #include #include #include #include using string=std::string; templatestruct Array:std::vector{using std::vector::vector;int Count(){return this->size();}bool IsEmpty(){return this->empty();}bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}void Insert(T x){this->push_back(x);}void RemoveItem(T x){this->erase(std::remove(this->begin(),this->end(),x),this->end());}}; templatestruct Map:std::map{V Get(K k){auto i=this->find(k);return i==this->end()?V{}:i->second;}void Set(K k,V v){(*this)[k]=v;}bool Contains(K k){return this->count(k);}void Remove(K k){this->erase(k);}}; struct vector{float x=0,y=0,z=0;static float DistanceXZ(vector a,vector b){return std::hypot(a.x-b.x,a.z-b.z);}}; struct Entity{int id=0;};using IEntity=Entity*; struct Group{};struct Roster{};struct Slot{IEntity occupant=nullptr;bool reserved=false,locked=false;bool IsLocked(){return locked;}IEntity GetOccupant(){return occupant;}bool IsReserved(){return reserved;}int Type(){return 2;}void GetWorldTransform(vector a[4]){a[3]={1,0,0};}}; struct AIActionBase{int completes=0;virtual ~AIActionBase()=default;void Complete(){completes++;}}; struct Utility{bool m_AIInfo=true;Arrayactions;int adds=0;void AddAction(AIActionBase*a){actions.Insert(a);adds++;}void GetActions(Array&a){a=actions;}}; struct Agent{Utility*m_UtilityComponent=nullptr;};Agent*agent_=nullptr;Agent*GetAgent(IEntity){return agent_;} struct Unit{struct Group*Group_=nullptr;struct Group*&Group=Group_;Roster*StatusSampler=nullptr;string ForceSourceId;}; struct Vehicle{IEntity Entity_=nullptr;IEntity&Entity=Entity_;struct Group*Group_=nullptr;struct Group*&Group=Group_;int SupplyToken=0;bool SupplyHeld=false;int clears=0;void ClearOrder(){clears++;}}; struct Receipt{};struct Task{ArrayVehicles;struct Receipt*Receipt_=nullptr;struct Receipt*&Receipt=Receipt_;}; struct Journal{};struct Route{int result=0,calls=0;int Advance(float,Journal*){calls++;return result;}}; struct HQ{bool permit=true;Maptokens;Route*d=nullptr,*r=nullptr;Group*dg=nullptr;struct Journal journal;int claims=0,releases=0; bool ReserveMountedLogistics(Unit*donor,Unit*recipient,int token){claims++;if(!permit||tokens.Get(donor->Group)||tokens.Get(recipient->Group))return false;tokens.Set(donor->Group,token);tokens.Set(recipient->Group,token);return true;} int LogisticsToken(Group*g){return tokens.Get(g);}void ReleaseLogistics(Group*g,int token){if(tokens.Get(g)==token){tokens.Remove(g);releases++;}} Route*Downlink(Group*g,string,string,int){return g==dg?d:r;}struct Journal*Journal(){return &journal;}}; struct Mode{inline static Mode*current=nullptr;bool active=true,forces=true;static Mode*Get(){return current;}bool Active(){return active;}bool Forces(){return forces;}}; struct Mounted{bool valid=true,Complete=true;int LowMagazines=1;bool Valid(){return valid;}}; struct Watch{string SourceId;bool fresh=true;int MessageId=1;float ObservedAt=0;vector Position;Mounted*MountedAmmo=nullptr;}; struct ERR_InfantryResupplyRules{static bool Fresh(Watch*w,float now){return w&&w->fresh&&std::isfinite(now)&&now>=w->ObservedAt&&now-w->ObservedAt<=120000;}}; struct Replication{static bool IsServer(){return true;}}; struct ERR_ForceRules{static bool Finite(float n){return std::isfinite(n);}}; struct Math{static float Min(float a,float b){return std::min(a,b);}}; struct CompartmentAccessComponent{inline static IEntity aboard=nullptr;static IEntity GetVehicleIn(IEntity){return aboard;}}; struct SCR_AICompartmentHandling{static int CompartmentClassToType(int t){return t;}}; struct SCR_AIGetOutVehicle:AIActionBase{SCR_AIGetOutVehicle(Utility*,void*,IEntity,int){}}; struct ERR_MountedCourierBoard:AIActionBase{ERR_MountedCourierBoard(Utility*,void*,IEntity,Slot*,int,int){}}; struct ERR_ConvoyMountedCrew{inline static bool allowed=true;inline static Mapclaims;static bool BeginCourier(IEntity e,IEntity,int t){if(!allowed||claims.Contains(e))return false;claims.Set(e,t);return true;}static void EndCourier(IEntity e,int t){if(claims.Get(e)==t)claims.Remove(e);}}; struct ERR_InfantryAmmoAccess{inline static bool points=true,clear=true;static bool Points(IEntity,Array&p){p={{1,0,0}};return points;}static bool Clear(IEntity,IEntity){return clear;}}; using SCR_ChimeraAIAgent=Agent*; ''' leaf=r''' struct Leaf{ inline static int nextResult=0;int result=0,ticks=0,stops=0;bool unresolved=false;ERR_FiniteMagazineReservation*reservation=nullptr; Leaf(ERR_FiniteMagazineReservation*r):result(nextResult),reservation(r){}int Tick(float){ticks++;return result;}bool Unresolved(){return unresolved;}string Reason(){return "fixture transaction refusal";}void Stop(){stops++;}}; struct ERR_MountedAmmoPickup:Leaf{inline static ERR_MountedAmmoPickup*last=nullptr; ERR_MountedAmmoPickup(Mode*,Task*,int,Roster*,int,void*,void*,IEntity,IEntity,ERR_FiniteMagazineReservation*r):Leaf(r){last=this;} int Tick(float n){if(ticks==0){assert(reservation->Commit());}return Leaf::Tick(n);}}; struct ERR_MountedAmmoTransfer:Leaf{inline static ERR_MountedAmmoTransfer*last=nullptr;bool reach=true; ERR_MountedAmmoTransfer(Mode*,Task*,int,Roster*,int,void*,void*,IEntity,IEntity,ERR_FiniteMagazineReservation*r):Leaf(r){last=this;} bool InReach(){return reach;}int Tick(float n){if(ticks==0){assert(reservation->ClaimMountedSwap(incoming));}return Leaf::Tick(n);}IEntity incoming=nullptr;}; struct Controller{ HQ*m_HQ=nullptr;Mode*m_Mode=nullptr;Task*m_Convoy=nullptr;int m_ConvoySlot=0,m_State=0,m_Trip=0,m_Token=0,m_ReportId=0,VehicleIndex=0,m_WorkerSlot=1; bool m_Stopped=false,m_CourierPermit=false;float m_Deadline=0,m_LastTick=-1,m_NextTick=0; Array*m_Stock=nullptr,*m_Spent=nullptr;Map*m_Consumed=nullptr;Map*m_NextAttempt=nullptr; Unit*m_Recipient=nullptr,*m_Donor=nullptr;Vehicle*m_Truck=nullptr,*m_Target=nullptr;Receipt*m_Receipt=nullptr; IEntity Root=nullptr,m_Worker=nullptr,m_Loaded=nullptr,m_Incoming=nullptr;Slot*m_Seat=nullptr,*m_MagazineSlot=nullptr;void*m_Weapon=nullptr,*m_Muzzle=nullptr; Utility*m_Utility=nullptr;AIActionBase*m_Action=nullptr;ERR_FiniteMagazineReservation*m_Reservation=nullptr;Route*m_DonorOrder=nullptr,*m_RecipientOrder=nullptr; ERR_MountedAmmoPickup*m_Pickup=nullptr;ERR_MountedAmmoTransfer*m_Swap=nullptr; bool convoyValid=true,quiet=true,vehicleValid=true,selectWorker=true,selectTarget=true,workerValid=true,current=true,stationary=true,stockPresent=true,walk=true; int notes=0,walks=0;bool ConvoyValid(){return convoyValid;}bool Quiet(Unit*){return quiet;}bool VehicleValid(Vehicle*,Unit*,int){return vehicleValid;} bool SelectWorker(){return selectWorker;}bool SelectTarget(){return selectTarget;}bool WorkerValid(){return workerValid;} bool Current(){return current;}bool Stationary(IEntity){return stationary;}bool InTruck(IEntity){return stockPresent;}bool Walk(vector,IEntity){walks++;return walk;} void Note(string){notes++;} ''' main=r''' }; struct Fixture{HQ hq;Mode mode;Task task;Receipt receipt;Vehicle truck,target;Group dg,tg;Unit donor,recipient;Watch demand,status;Mounted mounted; Entity truckEntity,root,worker,incoming,loaded;Slot seat,magSlot;Utility utility;Agent agent;Roster roster;Arraystock,spent;Mapconsumed;Mapcooldown;Route d,r;Controller c; Fixture(){Mode::current=&mode;task.Receipt=&receipt;task.Vehicles.resize(6,nullptr);task.Vehicles[1]=&truck;task.Vehicles[0]=⌖ truck.Entity=&truckEntity;truck.Group=&dg;target.Entity=&root;target.Group=&tg;donor.Group=&dg;recipient.Group=&tg;recipient.StatusSampler=&roster; donor.ForceSourceId="donor";recipient.ForceSourceId="target";demand.SourceId="target";status.SourceId="donor";demand.MountedAmmo=&mounted; hq.dg=&dg;hq.d=&d;hq.r=&r;stock={&incoming};c.m_HQ=&hq;c.m_Mode=&mode;c.m_Convoy=&task;c.m_Stock=&stock;c.m_Spent=&spent;c.m_Consumed=&consumed;c.m_NextAttempt=&cooldown; c.m_Worker=&worker;c.m_Incoming=&incoming;c.m_Loaded=&loaded;c.m_Seat=&seat;c.m_MagazineSlot=&magSlot;c.m_Utility=&utility;seat.occupant=&worker; agent.m_UtilityComponent=&utility;agent_=&agent;CompartmentAccessComponent::aboard=&root;ERR_ConvoyMountedCrew::claims.clear();ERR_ConvoyMountedCrew::allowed=true;ERR_InfantryAmmoAccess::clear=true;ERR_InfantryAmmoAccess::points=true;Leaf::nextResult=0;} bool Begin(float now=0){return c.Begin(&recipient,&donor,&demand,&status,now);} void Dispatch(){assert(Begin());d.result=r.result=1;c.Tick(0);assert(c.m_State==2);seat.occupant=nullptr;CompartmentAccessComponent::aboard=nullptr;c.Tick(1000);assert(c.m_State==3);} void Pickup(){Dispatch();Leaf::nextResult=1;c.Tick(2000);assert(c.m_State==5&&!c.m_Pickup&&c.m_Swap);c.m_Swap->incoming=&incoming;} }; int main(){ {Fixture f;assert(f.Begin()&&f.c.Busy()&&f.spent.Count()==1&&f.truck.SupplyToken==200001);f.c.Tick(0);assert(f.c.m_State==1&&f.utility.adds==0&&!f.truck.SupplyHeld); f.d.result=1;f.c.Tick(1000);assert(f.truck.SupplyHeld&&!f.target.SupplyHeld&&f.c.m_State==1);f.r.result=1;f.c.Tick(2000);assert(f.c.m_State==2&&f.utility.adds==1&&f.c.m_CourierPermit);} {Fixture f;f.Pickup();auto*p=ERR_MountedAmmoPickup::last;p->unresolved=true; // proof of an old leg changes once incoming moves onward f.c.Tick(3000);assert(f.c.m_State==7&&!f.c.m_Swap&&!f.c.Unresolved());f.seat.occupant=&f.worker;CompartmentAccessComponent::aboard=&f.root;f.c.Tick(4000); assert(!f.c.Busy()&&!f.truck.SupplyHeld&&!f.target.SupplyHeld&&f.spent.Count()==1&&f.hq.tokens.empty());assert(!f.Begin(5000));} {Fixture f;f.Pickup();ERR_MountedAmmoPickup::last->unresolved=true;f.seat.reserved=true;f.c.Tick(3000);assert(!f.c.Busy()&&!f.c.Unresolved()&&f.spent.Count()==1);f.c.Stop();assert(!f.c.Busy());} {Fixture f;assert(f.Begin());f.d.result=-1;f.c.Tick(0);assert(!f.c.Busy()&&f.spent.empty()&&f.utility.adds==0&&f.hq.tokens.empty());} // Locking the selected mount before dispatch or pickup must not consume cargo. {Fixture f;assert(f.Begin());f.magSlot.locked=true;f.d.result=f.r.result=1;f.c.Tick(0);assert(!f.c.Busy()&&f.spent.empty()&&f.utility.adds==0);} {Fixture f;f.Dispatch();f.magSlot.locked=true;f.c.Tick(2000);assert(f.c.m_State==7&&!f.c.m_Pickup);f.seat.occupant=&f.worker;CompartmentAccessComponent::aboard=&f.root;f.c.Tick(3000);assert(!f.c.Busy()&&f.spent.empty());} // Every preflight guard rejects without consuming report, stock or native orders. for(int k=0;k<12;k++){Fixture f;switch(k){case 0:f.mounted.LowMagazines=0;break;case 1:f.mounted.Complete=false;break;case 2:f.demand.fresh=false;break; case 3:f.demand.Position.x=201;break;case 4:f.c.m_Trip=128;break;case 5:f.c.convoyValid=false;break;case 6:f.c.quiet=false;break; case 7:f.c.selectWorker=false;break;case 8:f.c.selectTarget=false;break;case 9:f.hq.permit=false;break;case 10:f.truck.SupplyToken=9;break;case 11:f.target.SupplyToken=9;break;} assert(!f.Begin()&&f.spent.empty()&&f.consumed.empty()&&f.utility.adds==0);} // Failed reservation rolls back the atomic HQ pair claim without touching another spent claim. {Fixture f;f.spent={&f.incoming};assert(!f.Begin()&&f.spent.Count()==1&&f.hq.tokens.empty());} // Uncertain pickup survives Stop and keeps both matching claims until callback/proof settles. {Fixture f;f.Dispatch();f.c.Tick(2000);assert(f.c.m_State==4);f.c.m_Pickup->unresolved=true;auto*p=f.c.m_Pickup;f.c.Stop(); assert(f.c.m_State==8&&f.c.Busy()&&f.hq.tokens.size()==2&&f.spent.Count()==1);p->unresolved=false;f.c.Tick(3000);assert(!f.c.Busy()&&f.hq.tokens.empty()&&f.spent.Count()==1);} // A terminally lost submitted pickup releases holds, retaining spent identity. // Leaf deletion semantics are exercised in the actual pickup/swap regressions. {Fixture f;Entity surviving;f.stock.Insert(&surviving);f.Dispatch();f.c.Tick(2000);auto*p=f.c.m_Pickup;assert(p&&f.c.m_State==4); p->unresolved=true;f.c.workerValid=false;f.c.Tick(3000); assert(f.c.m_State==8&&f.hq.tokens.size()==2&&f.truck.SupplyHeld&&f.target.SupplyHeld); p->unresolved=false;f.c.Tick(4000);assert(!f.c.Busy()&&f.hq.tokens.empty()&&!f.truck.SupplyHeld&&!f.target.SupplyHeld&&f.spent.Count()==1); f.c.m_Incoming=&surviving;f.c.workerValid=true;f.demand.MessageId=2;f.demand.ObservedAt=f.status.ObservedAt=200000; assert(f.Begin(200000)&&f.spent.Count()==2&&f.c.m_Trip==2);} // Uncertain swap is not released merely because the controller times out or is stopped. {Fixture f;f.Pickup();f.c.m_Swap->result=0;f.c.Tick(3000);f.c.m_Swap->unresolved=true;auto*t=f.c.m_Swap;f.c.Stop(); assert(f.c.m_State==8&&f.c.m_Swap==t&&f.hq.tokens.size()==2);t->unresolved=false;f.c.Tick(4000);assert(!f.c.Busy()&&f.spent.Count()==1);} // Failed unsubmitted approach releases stock; original courier receives one native return order. {Fixture f;f.Dispatch();f.c.stockPresent=false;f.c.Tick(2000);assert(f.c.m_State==7&&f.utility.adds==2);f.seat.occupant=&f.worker;CompartmentAccessComponent::aboard=&f.root;f.c.Tick(3000);assert(!f.c.Busy()&&f.spent.empty());} // Cleanup compares token ownership, never releasing a newer/foreign hold. {Fixture f;assert(f.Begin());f.truck.SupplyToken=777;f.target.SupplyToken=888;f.hq.tokens.Set(&f.dg,777);f.hq.tokens.Set(&f.tg,888);f.c.Stop(); assert(f.truck.SupplyToken==777&&f.target.SupplyToken==888&&f.hq.tokens.Get(&f.dg)==777&&f.hq.tokens.Get(&f.tg)==888);} {Fixture f;f.Dispatch();auto*owned=f.c.m_Action;AIActionBase foreign;f.utility.actions.Insert(&foreign);f.c.Stop();assert(owned->completes==1&&foreign.completes==0&&!ERR_ConvoyMountedCrew::claims.Contains(&f.worker));} {Fixture f;f.Dispatch();f.c.workerValid=false;f.c.Tick(2000);assert(!f.c.Busy()&&f.spent.empty()&&f.hq.tokens.empty());} {Fixture f;f.c.selectWorker=false;f.truck.SupplyHeld=true;f.target.SupplyHeld=true;assert(!f.Begin());f.c.Stop();assert(f.truck.SupplyHeld&&f.target.SupplyHeld);} {Fixture f;assert(f.Begin());f.task.Vehicles[0]=nullptr;f.c.m_Target=nullptr;f.c.Tick(0);assert(!f.c.Busy()&&f.spent.empty());} {Fixture f;assert(f.Begin());f.c.Tick(std::numeric_limits::quiet_NaN());assert(!f.c.Busy()&&f.spent.empty());} } ''' run(pre+translated_reservation()+leaf+code+main) print('PASS: actual mounted courier admission, radio, individual orders, two-stage transfer, reboarding, token cleanup and quarantine lifecycle') # Execute exact original-crew token hooks and courier-specific native board cleanup. tactics=Path(os.environ.get('ERR_MOUNTED_TACTICS_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_SupplyConvoyTactics.c')) hooks='\n'.join(body(tactics,sig) for sig in ('static bool BeginCourier(', 'static void EndCourier(', 'static void Release(IEntity actor)')) hooks=hooks.replace('null','nullptr').replace('s_Crews.','s_Crews.').replace('s_Couriers.','s_Couriers.') hooks=hooks.replace('Vehicle originalVehicle','IEntity originalVehicle') cleanup=body(p,'protected void OwnSeatCleanup()').replace('protected ','').replace('null','nullptr') cleanup=cleanup.replace('BaseCompartmentSlot seat','Slot* seat').replace('seat.','seat->') callbacks='\n'.join(body(p,sig) for sig in ('override void OnActionCompleted()', 'override void OnActionFailed()')) callbacks=callbacks.replace('override ','').replace('super.','Base::') run(r''' #include #include struct Entity{};using IEntity=Entity*; templatestruct Map:std::map{V Get(K k){auto i=this->find(k);return i==this->end()?V{}:i->second;}bool Contains(K k){return this->count(k);}void Set(K k,V v){(*this)[k]=v;}void Remove(K k){this->erase(k);}}; struct Crew{inline static Maps_Crews;inline static Maps_Couriers; '''+hooks+r'''}; struct Slot{IEntity occupant=nullptr,reserved=nullptr;int writes=0;IEntity GetOccupant(){return occupant;}bool IsReserved(){return reserved;}bool IsReservedBy(IEntity e){return reserved==e;}void SetCompartmentAccessible(bool b){assert(b);writes++;}void SetReserved(IEntity e){reserved=e;writes++;}}; struct Param{Slot*m_Value=nullptr;}; struct Base{Param m_CompartmentToGetIn;int completed=0,failed=0,unsafe=0; void OnActionCompleted(){completed++;if(m_CompartmentToGetIn.m_Value)unsafe++;} void OnActionFailed(){failed++;if(m_CompartmentToGetIn.m_Value)unsafe++;}}; struct Board:Base{IEntity OriginalWorker=nullptr;Slot*OriginalSeat=nullptr; '''+cleanup+callbacks+r'''}; int main(){ Entity worker,driver,vehicle,foreign; Crew::s_Crews.Set(&worker,&vehicle);Crew::s_Crews.Set(&driver,&vehicle); assert(!Crew::BeginCourier(&worker,&foreign,200001));assert(Crew::BeginCourier(&worker,&vehicle,200001)); assert(!Crew::BeginCourier(&worker,&vehicle,200002)&&Crew::s_Crews.Get(&driver)==&vehicle); Crew::EndCourier(&worker,200002);assert(Crew::s_Couriers.Contains(&worker)); Crew::EndCourier(&worker,200001);assert(!Crew::s_Couriers.Contains(&worker)&&Crew::s_Crews.Get(&worker)==&vehicle); assert(Crew::BeginCourier(&worker,&vehicle,200002));Crew::Release(&worker);assert(!Crew::s_Crews.Contains(&worker)&&!Crew::s_Couriers.Contains(&worker)); Crew::EndCourier(&worker,200002);assert(!Crew::s_Crews.Contains(&worker)); for(int variant=0;variant<5;variant++)for(int fail=0;fail<2;fail++){ Slot seat,other;Board b;b.OriginalWorker=&worker;b.OriginalSeat=&seat;b.m_CompartmentToGetIn.m_Value=&seat; if(variant==1){seat.reserved=&worker;}if(variant==2){seat.reserved=&foreign;}if(variant==3){seat.occupant=&foreign;}if(variant==4){b.m_CompartmentToGetIn.m_Value=&other;} if(fail)b.OnActionFailed();else b.OnActionCompleted(); assert(!b.m_CompartmentToGetIn.m_Value&&b.unsafe==0&&b.completed+b.failed==1); assert(seat.writes==(variant==0?1:variant==1?2:0)&&other.writes==0); if(variant==2)assert(seat.reserved==&foreign); } } ''') print('PASS: actual scoped crew permit and native board completion/failure preserves foreign seats without teleport fallback')