Merge owned systems into one addon while preserving resource identities. Gate player admission on the replicated prison scene, restore the original framed door, and hold enemy AI until escape. Correct scenario branding and author metadata, include publishing assets, and retain regression and native verification evidence.
253 lines
18 KiB
Python
253 lines
18 KiB
Python
"""Execute route result policy and audit opt-in finite/native fixture boundaries."""
|
|
from policy_harness import ROOT, body, run
|
|
P=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_NativeAircraftRouteProbe.c'
|
|
source=P.read_text()
|
|
rules='\n'.join(body(P,k) for k in ('static bool Terminal(', 'static bool TranslateProof(', 'static bool PhysicalFinish(', 'static bool CanDispose(')).replace('ERR_AircraftFlightState.','State::')
|
|
run('''#include <cassert>
|
|
namespace State {enum {COMPLETE=8,CANCELLED,FAILED,RELINQUISHED};}
|
|
'''+rules+'''
|
|
int main(){
|
|
assert(Terminal(false,State::COMPLETE,0));assert(!Terminal(false,State::CANCELLED,0));assert(!Terminal(false,State::FAILED,0));
|
|
assert(TranslateProof(true,true,20,19.5,.5));
|
|
assert(!TranslateProof(true,true,20,1,.5));assert(!TranslateProof(true,false,20,20,0));assert(!TranslateProof(false,true,20,20,0));assert(!TranslateProof(true,true,20,20,.76f));
|
|
assert(!TranslateProof(true,true,29,29,0));assert(!TranslateProof(true,true,9,9,0));
|
|
assert(PhysicalFinish(true,true,true,.1f,1,1,1,101,101));
|
|
assert(!PhysicalFinish(true,true,false,.1f,1,1,1,101,101));assert(!PhysicalFinish(true,true,true,0,1,1,1,101,101));assert(!PhysicalFinish(true,true,true,.1f,2,1,1,101,101));assert(!PhysicalFinish(false,true,true,.1f,1,1,1,101,101));
|
|
assert(CanDispose(true,true,true,true,true));for(int i=0;i<5;i++)assert(!CanDispose(i!=0,i!=1,i!=2,i!=3,i!=4));
|
|
}
|
|
''')
|
|
assert source.startswith('#ifdef WORKBENCH') and source.rstrip().endswith('#endif')
|
|
assert 'outcome == "aircraft-route"' in body(P,'static bool Enabled(')
|
|
assert 'outcome == "aircraft-control"' not in source
|
|
assert source.count('ERR_Actors.Spawn(AIRCRAFT,')==1 and source.count('SpawnCharacterInCompartment(')==1
|
|
assert source.count('physics.SetActive(ActiveState.ACTIVE)')==1
|
|
for prohibited in ('SetWorldTransform(', 'SetOrigin(', 'SetVelocity(', '.StartEngine(', '.StopEngine(', 'm_Mode.Own('):assert prohibited not in source
|
|
assert 'ERR_AircraftRouteEnvelope.Survey(candidate, destination)' in body(P,'protected bool FindPad(')
|
|
tick=body(P,'int Tick(')
|
|
assert 'ERR_AircraftRouteEnvelope.QualifyRoute(' in tick and 'StartRetainedRoute()' in tick
|
|
assert tick.index('ERR_AircraftRouteEnvelope.QualifyRoute(')<tick.index('StartRetainedRoute()')
|
|
assert 'm_Flight.Arrived() && vector.DistanceXZ(transform[3], m_Destination) <= 0.75' in tick
|
|
assert 'm_Flight.ERR_NativeControlDeadline() != m_ControlDeadline' in tick
|
|
assert tick.index('m_Service.Tick();')<tick.index('if (!m_Flight.Finished())')
|
|
assert 'm_Flight.Tick(' not in source and 'm_Flight.StartRoute(' not in source and 'm_Flight.Cancel(' not in source
|
|
stop=body(P,'void Stop(')
|
|
assert stop.index('s_Current = null')<stop.index('m_Service.Stop()')<stop.index('ERR_Actors.DeleteSpawned(')<stop.index('m_Service.Tick()')<stop.index('m_Flight = null')<stop.index('m_Service = null')
|
|
assert 'ERR_NativeAircraftRouteRules.CanDispose(' in stop
|
|
assert source.index('probe.PrepareActions(')<source.index('super.OnPrepareControls(owner, am, dt, player);')
|
|
start=source.index('protected override event void OnPrepareControls()')
|
|
assert source.index('super.OnPrepareControls();',start)<source.index('probe.PrepareHelicopter(this);',start)
|
|
print('PASS: finite opt-in route fixture, original native input order, meaningful physical-arrival evidence and guarded cleanup; no native launch')
|
|
|
|
# Integration is separate from physical route proof. Exercise real early CLI
|
|
# refusals against a deliberately absent prefix: no engine or audio can start.
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
runner=ROOT/'tools/headless_workbench.py'
|
|
cases=[
|
|
('core','1','420',[], 'requires Chat, one round, and at least 420 seconds'),
|
|
('chat','2','420',[], 'requires Chat, one round, and at least 420 seconds'),
|
|
('chat','1','419',[], 'requires Chat, one round, and at least 420 seconds'),
|
|
('chat','1','420',['--flight-action-inputs'], 'flight-action-inputs requires the Core powered-flight fixture'),
|
|
('chat','1','420',['--flight-autohover'], 'flight-autohover requires Core powered-flight with flight-action-inputs'),
|
|
('chat','1','420',[], 'must be a disposable cloned prefix'),
|
|
]
|
|
for project,rounds,timeout,extra,message in cases:
|
|
with tempfile.TemporaryDirectory(prefix='erri-route-parse-') as directory:
|
|
temporary=Path(directory)
|
|
result=subprocess.run([sys.executable,str(runner),'--compat',str(temporary/'missing-prefix'),'--profile',str(temporary/'missing-profile'),'--project',project,'--smoke','aircraft-route','--rounds',rounds,'--timeout',timeout,*extra],capture_output=True,text=True,timeout=10)
|
|
assert result.returncode==2, (project,rounds,timeout,extra,result.stderr)
|
|
assert message in result.stderr, (project,rounds,timeout,extra,result.stderr)
|
|
assert list(temporary.iterdir())==[], 'Refused route invocation must not create profiles or prefix locks'
|
|
|
|
chat=ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c'
|
|
text=chat.read_text()
|
|
assert 'm_ERRTestAircraftRoute = outcome == "aircraft-route";' in text
|
|
assert 'if (m_ERRTestAircraftControl || m_ERRTestAircraftRoute || m_ERRTestAircraftField) m_ERRSmokeDeadline = GetWorld().GetWorldTime() + 330000;' in text
|
|
assert 'OnStop().Insert(ERR_StopHQPatrol);' in text
|
|
assert 'if (m_ERRAircraftRoute) m_ERRAircraftRoute.Stop();' in body(chat,'protected void ERR_StopHQPatrol(')
|
|
assert 'ERR_StopHQPatrol();' in body(chat,'protected bool ERR_Check(')
|
|
|
|
def block(text,anchor):
|
|
start=text.index(anchor)
|
|
opening=text.index('{',start);depth=1;end=opening+1
|
|
while depth:
|
|
depth+=(text[end]=='{')-(text[end]=='}');end+=1
|
|
return text[start:end]
|
|
branch=block(body(chat,'protected void ERR_SmokeTick('),'if (m_ERRSmokeStep == 230)')
|
|
assert 'int result = m_ERRAircraftRoute.Tick(now);' in branch
|
|
assert 'if (result < 0) { ERR_Check(false, "native actual aircraft route fixture"); return; }' in branch
|
|
assert 'if (result == 1) { m_ERRSmokeStep = 231; Transition(ERR_Phase.DEFEAT); }' in branch
|
|
# Execute the unchanged actual branch to prove pending/failure cannot advance
|
|
# to the fixture terminal and successful transition sees the completed step.
|
|
run('''#include <cassert>
|
|
#include <initializer_list>
|
|
namespace ERR_Phase {enum {DEFEAT};}
|
|
struct Probe {int result=0,ticks=0;int Tick(float){ticks++;return result;}};
|
|
struct Fixture {int m_ERRSmokeStep=230,failures=0,transitions=0;Probe m_ERRAircraftRoute;
|
|
void ERR_Check(bool,const char*){failures++;}
|
|
void Transition(int phase){assert(phase==ERR_Phase::DEFEAT&&m_ERRSmokeStep==231);transitions++;}
|
|
void Tick(float now){
|
|
'''+branch.replace('ERR_Phase.','ERR_Phase::')+'''
|
|
}
|
|
};
|
|
int main(){
|
|
for(int result:{-1,0,1}){Fixture f;f.m_ERRAircraftRoute.result=result;f.Tick(1000);assert(f.m_ERRAircraftRoute.ticks==1);assert(f.failures==(result<0));assert(f.transitions==(result==1));assert(f.m_ERRSmokeStep==(result==1?231:230));}
|
|
}
|
|
''')
|
|
terminal=block(body(chat,'protected void ERR_SmokePhase('),'if (m_ERRTestAircraftRoute)')
|
|
assert 'current == ERR_Phase.DEFEAT && m_ERRSmokeStep == 231' in terminal
|
|
assert terminal.index('ERR_StopHQPatrol();')<terminal.index('ERR SMOKE COMPLETE:')
|
|
assert terminal.count('ERR SMOKE COMPLETE:')==1
|
|
initial=block(body(chat,'protected void ERR_SmokeTick('),'if (m_ERRTestAircraftRoute)')
|
|
assert initial.count('new ERR_NativeAircraftRouteProbe(this)')==1
|
|
assert 'm_ERRSmokeStep = 230;' in initial and initial.rstrip().endswith('return;\n\t\t\t}')
|
|
print('PASS: actual Chat route step result dispatch and scoped completion/cleanup wiring; six real early-parser refusal paths leave no prefix/profile output')
|
|
|
|
# The added two-second telemetry only observes, and cannot extend/control flight.
|
|
diagnostic=body(P,'protected void Diagnostic(')
|
|
assert diagnostic.index('now < m_NextLog')<diagnostic.index('m_NextLog = now + 2000')<diagnostic.index('ERR AIRCRAFT ROUTE MOTION:')
|
|
for forbidden in ('SetActionValue(', 'SetVelocity(', 'SetWorldTransform(', '.Cancel(', '.Tick(', '.StartRoute(', '.SetAutohoverEnabled('):assert forbidden not in diagnostic
|
|
for field in ('position=%2','velocity=%3','along=%4','cross=%5','targetError=%6','computedDemand=%7','projectedForward=%8','projectedAside=%9','stageRemaining=%5','overallRemaining=%6'):assert field in diagnostic
|
|
assert body(P,'float ERR_NativeRouteStageDeadline(').strip()=='float ERR_NativeRouteStageDeadline() { return m_StageDeadline; }'
|
|
|
|
|
|
# Service adaptation executes the actual fixture entry and retained-identity
|
|
# methods. Only native service outcomes are substituted; no physical proof.
|
|
def retained_cpp(text):
|
|
return text.replace('protected ','').replace('m_Service.', 'm_Service->').replace('new ERR_AircraftService(', 'new Service(')
|
|
run(r'''#include <cassert>
|
|
#include <string>
|
|
struct Flight{};
|
|
bool registration=true,startAccepted=true;int constructions=0,registerCalls=0,startCalls=0;
|
|
struct Service {
|
|
Flight flight;bool pending=false;int token=0,count=0,attempts=0;float deadline=0;int aircraft=0,group=0,pilot=0,seat=0;
|
|
Service(int){constructions++;}
|
|
bool Register(int a,int g,int p,int s){registerCalls++;if(!registration)return false;aircraft=a;group=g;pilot=p;seat=s;count=1;return true;}
|
|
bool Ready(int){return registration;}int RegisteredCount(){return count;}int AttemptedOrders(){return attempts;}
|
|
int OrderToken(int){return token;}float OrderDeadline(int){return deadline;}bool Pending(int){return pending;}
|
|
bool StartRoute(int a,int,int t,float d){assert(a==aircraft);startCalls++;attempts++;token=t;deadline=d;pending=startAccepted;return startAccepted;}
|
|
Flight* ERR_NativeOriginalFlight(int){return attempts?&flight:nullptr;}
|
|
};
|
|
struct Probe {
|
|
Service* m_Service=nullptr;Flight* m_Flight=nullptr;
|
|
int m_Mode=1,m_Aircraft=2,m_Group=3,m_Pilot=4,m_Seat=5,m_Envelope=6,m_ControllerStarts=0,failed=0;
|
|
const int ORDER_TOKEN=771001;float m_ControlDeadline=240000;
|
|
bool Check(bool okay,const char*){if(!okay)failed++;return okay;}
|
|
''' + retained_cpp(body(P,'protected bool RetainedIdentity(')) + retained_cpp(body(P,'protected bool StartRetainedRoute(')) + r'''
|
|
};
|
|
int main(){
|
|
Probe p;assert(!p.RetainedIdentity());assert(p.StartRetainedRoute());assert(p.RetainedIdentity()&&p.m_ControllerStarts==1&&constructions==1&®isterCalls==1&&startCalls==1);
|
|
assert(p.m_Service->aircraft==2&&p.m_Service->group==3&&p.m_Service->pilot==4&&p.m_Service->seat==5&&p.m_Service->Pending(2));
|
|
assert(!p.StartRetainedRoute()&&constructions==1&&startCalls==1); // no replacement or duplicate controller
|
|
Flight foreign;auto original=p.m_Flight;p.m_Flight=&foreign;assert(!p.RetainedIdentity());p.m_Flight=original;
|
|
p.m_Service->token++;assert(!p.RetainedIdentity());p.m_Service->token--;
|
|
p.m_Service->deadline++;assert(!p.RetainedIdentity());p.m_Service->deadline--;
|
|
p.m_Service->count=2;assert(!p.RetainedIdentity());p.m_Service->count=1;
|
|
p.m_Service->attempts=2;assert(!p.RetainedIdentity());p.m_Service->attempts=1;assert(p.RetainedIdentity());
|
|
registration=false;Probe unready;assert(!unready.StartRetainedRoute()&&unready.m_ControllerStarts==0&&startCalls==1);registration=true;
|
|
startAccepted=false;Probe refused;assert(!refused.StartRetainedRoute()&&refused.m_ControllerStarts==1&&startCalls==2&&refused.m_Flight);
|
|
}
|
|
''')
|
|
# The sole fixture getter observes the service's original retained controller.
|
|
getter=body(P,'ERR_AircraftRouteFlight ERR_NativeOriginalFlight(')
|
|
run(r'''#include <cassert>
|
|
struct BaseFlight {virtual ~BaseFlight()=default;};struct Flight:BaseFlight{};struct FieldFlight:BaseFlight{};struct Entry {BaseFlight* FlightPtr=nullptr;};
|
|
struct Observe {Entry* entry=nullptr;Entry* Find(int){return entry;}
|
|
''' + getter.replace('ERR_AircraftRouteFlight.Cast(entry.Flight)', 'dynamic_cast<Flight*>(entry.Flight)').replace('ERR_AircraftRouteFlight ', 'Flight* ').replace('Vehicle aircraft','int aircraft').replace('ERR_AircraftServiceEntry entry','Entry* entry').replace('entry.Flight','entry->FlightPtr').replace('null','nullptr') + r'''
|
|
};
|
|
int main(){Observe p;assert(!p.ERR_NativeOriginalFlight(1));Flight flight;Entry e;e.FlightPtr=&flight;p.entry=&e;assert(p.ERR_NativeOriginalFlight(1)==&flight);FieldFlight field;e.FlightPtr=&field;assert(!p.ERR_NativeOriginalFlight(1));}
|
|
''')
|
|
assert 'm_Service.Drained() && !m_Service.Pending(m_Aircraft) && !m_Service.Retired(m_Aircraft)' in tick
|
|
assert 'if (!RetainedIdentity())' in tick
|
|
assert source.count('new ERR_AircraftService(')==1 and 'new ERR_AircraftRouteFlight(' not in source
|
|
for sig in ('void PrepareActions(', 'void PrepareHelicopter('):
|
|
assert 'm_Flight.Prepare' not in body(P,sig), 'Production bridge remains the only native control dispatcher'
|
|
print('PASS: actual retained-service fixture entry, immutable controller/token/deadline/count bindings, observer getter and cleanup ownership ordering; native route validation pending')
|
|
|
|
# Cancellation is a separate explicit variant; no arrival credit or second stop.
|
|
flight=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_AircraftFlight.c'
|
|
cancel_rules='\n'.join(body(P,k) for k in ('static bool CanStop(', 'static bool CancelProof(')).replace('ERR_AircraftFlightState.','State::').replace('ERR_AircraftFlightRules.Hover','Hover')
|
|
run('''#include <cassert>
|
|
#include <cmath>
|
|
namespace State {enum {IDLE,HOOKS,STARTING,POSITIVE,NEGATIVE,CLIMB,LANDING,SHUTDOWN,COMPLETE,CANCELLED,FAILED,RELINQUISHED,TRANSLATING};}
|
|
namespace Math {float AbsFloat(float x){return std::abs(x);}}
|
|
'''+body(flight,'static bool Hover(').replace('Math.','Math::')+cancel_rules+'''
|
|
int main(){
|
|
assert(CanStop(State::TRANSLATING,false,8,.4,0,1,3));
|
|
assert(!CanStop(State::TRANSLATING,false,8,.4,0,1,2.999f));
|
|
assert(!CanStop(State::TRANSLATING,true,8,.4,0,1,4));
|
|
assert(!CanStop(State::TRANSLATING,false,6,.4,0,1,4));
|
|
assert(!CanStop(State::TRANSLATING,false,8,2,0,1,4));
|
|
assert(!CanStop(State::TRANSLATING,false,8,.4,.6,1,4));
|
|
assert(!CanStop(State::TRANSLATING,false,8,.4,0,.9,4));
|
|
for(int i=State::IDLE;i<=State::RELINQUISHED;i++)assert(!CanStop(i,false,8,.4,0,1,4));
|
|
assert(CancelProof(true,true,true,true,true,true,.75f,false));
|
|
for(int i=0;i<6;i++)assert(!CancelProof(i!=0,i!=1,i!=2,i!=3,i!=4,i!=5,.1f,false));
|
|
assert(!CancelProof(true,true,true,true,true,true,.751f,false));
|
|
assert(!CancelProof(true,true,true,true,true,true,-1,false));
|
|
assert(!CancelProof(true,true,true,true,true,true,0,true));
|
|
}
|
|
''')
|
|
|
|
def stop_cpp(text):
|
|
return retained_cpp(text).replace('m_Flight.','m_Flight->').replace('m_Envelope.','m_Envelope->').replace('ERR_AircraftFlightState.','State::')
|
|
run(r'''#include <cassert>
|
|
namespace State {enum {TRANSLATING=12,LANDING=6,CANCELLED=9};}
|
|
template<class... Args>void PrintFormat(const char*,Args...){}
|
|
struct Flight {
|
|
int state=State::TRANSLATING,actions=50,helicopters=60,token=771001,point=0;float deadline=240000;bool finished=false;
|
|
int State(){return state;}bool Finished(){return finished;}int OrderToken(){return token;}
|
|
int LandingPoint(){return point;}float ERR_NativeControlDeadline(){return deadline;}
|
|
int ERR_NativeRouteActionUpdates(){return actions;}int ERR_NativeRouteHelicopterUpdates(){return helicopters;}
|
|
};
|
|
struct Service {
|
|
Flight flight;bool stopping=false,pending=true,retain=true;int stops=0,count=1,attempts=1,token=771001;float deadline=240000;
|
|
Flight* ERR_NativeOriginalFlight(int){return &flight;}bool Stopping(){return stopping;}bool Pending(int){return pending;}
|
|
bool Drained(){return !pending;}bool Ready(int){return !stopping;}
|
|
int RegisteredCount(){return count;}int AttemptedOrders(){return attempts;}int OrderToken(int){return token;}float OrderDeadline(int){return deadline;}
|
|
void Stop(){stops++;stopping=true;pending=retain;flight.state=State::LANDING;flight.point=22;}
|
|
};
|
|
struct Envelope{bool inside=true;bool Contains(int p,float){return inside&&p==22;}};
|
|
struct Probe {
|
|
Service service;Envelope envelope;Service* m_Service=&service;Flight* m_Flight=&service.flight;Envelope* m_Envelope=&envelope;
|
|
int m_Aircraft=1,ORDER_TOKEN=771001,m_CancelCount=0,m_CancelActionUpdates=0,m_CancelHelicopterUpdates=0,m_CancelLandingPoint=0;
|
|
float m_ControlDeadline=240000,m_CancelAt=-1;int failed=0;
|
|
bool Check(bool okay,const char*){if(!okay)failed++;return okay;}
|
|
'''+stop_cpp(body(P,'protected bool RetainedIdentity('))+stop_cpp(body(P,'protected bool StopRetainedRoute('))+r'''
|
|
};
|
|
int main(){
|
|
Probe p;assert(p.StopRetainedRoute(12000));assert(p.m_CancelCount==1&&p.m_CancelAt==12000&&p.service.stops==1);
|
|
assert(p.m_CancelActionUpdates==50&&p.m_CancelHelicopterUpdates==60&&p.m_CancelLandingPoint==22);
|
|
assert(p.service.Pending(1)&&!p.service.Drained()&&!p.service.Ready(1)&&p.service.flight.state==State::LANDING);
|
|
assert(p.RetainedIdentity());assert(!p.StopRetainedRoute(20000)&&p.service.stops==1&&p.m_CancelAt==12000&&p.m_ControlDeadline==240000);
|
|
Probe already;already.service.stopping=true;assert(!already.StopRetainedRoute(1)&&already.service.stops==0);
|
|
Probe rebound;rebound.service.token++;assert(!rebound.StopRetainedRoute(1)&&rebound.service.stops==0);
|
|
Probe lost;lost.service.retain=false;assert(!lost.StopRetainedRoute(1)&&lost.service.stops==1); // premature drain is a failure
|
|
Probe foreign;foreign.envelope.inside=false;assert(!foreign.StopRetainedRoute(1));
|
|
Probe renewed;renewed.service.flight.deadline++;assert(!renewed.StopRetainedRoute(1));
|
|
}
|
|
''')
|
|
readback=body(P,'bool ERR_NativeRouteFreshReadback(')
|
|
run('''#include <cassert>
|
|
struct Observe {bool m_Readback=true;float m_LastControl=1000;
|
|
'''+readback+'''
|
|
};
|
|
int main(){Observe p;assert(p.ERR_NativeRouteFreshReadback(1000));assert(p.ERR_NativeRouteFreshReadback(2000));assert(!p.ERR_NativeRouteFreshReadback(2001));assert(!p.ERR_NativeRouteFreshReadback(999));p.m_LastControl=-1;assert(!p.ERR_NativeRouteFreshReadback(0));p.m_LastControl=1000;p.m_Readback=false;assert(!p.ERR_NativeRouteFreshReadback(1000));}
|
|
''')
|
|
assert 'm_CancelFixture = System.GetCLIParam("errSmokeRouteServiceCancel", cancellation) && cancellation == "1";' in source
|
|
assert 'if (m_CancelFixture && m_CancelCount == 0)' in tick
|
|
assert 'now - m_CancelStable >= 500 && !StopRetainedRoute(now)' in tick
|
|
assert tick.index('StopRetainedRoute(now)')<tick.index('m_Service.Tick();')
|
|
assert 'else if (m_TranslationFixture)' in tick, 'cancel does not claim destination hold'
|
|
assert 'm_Envelope.Contains(m_CancelLandingPoint, 1)' in tick and 'm_Flight.LandingPoint() != m_CancelLandingPoint' in tick
|
|
assert 'm_Flight.ERR_NativeRouteActionUpdates() > m_CancelActionUpdates + 10' in tick
|
|
assert 'm_Flight.ERR_NativeRouteHelicopterUpdates() > m_CancelHelicopterUpdates + 10' in tick
|
|
assert 'm_Flight.ERR_NativeRouteFreshReadback(now)' in tick
|
|
assert 'now - m_LandingStable >= 2000' in tick
|
|
assert 'if (m_Service && !m_Service.Stopping()) m_Service.Stop();' in stop
|
|
assert source.count('m_Service.Stop();')==2 # exclusive trigger vs guarded final cleanup
|
|
assert 'now + 300000' not in tick and 'now + 240000' in tick
|
|
print('PASS: actual measured cancellation gate, one-shot retained service Stop, no premature drain, immutable lease, fresh real controller readback and separate physical cancellation result policy')
|