Validate independent packed addons and complete physical mortar salvos

This commit is contained in:
2026-09-19 11:42:13 +02:00
parent 7c53b4bb81
commit dfd7cc49e2
532 changed files with 63902 additions and 96 deletions
+91
View File
@@ -0,0 +1,91 @@
"""Execute the actual full-salvo evidence gates; this is not a native firing result."""
from policy_harness import ROOT, body, run
p=ROOT/'addons/ai/Scripts/Game/ERR/ERR_NativeMortarSalvoProbe.c'
base=ROOT/'addons/ai/Scripts/Game/ERR/ERR_NativeMortarFiringProbe.c'
rules='\n'.join(body(base, sig) for sig in ['static bool AimFresh(', 'static bool CommitFresh(', 'static bool EventBound('])
rules=rules.replace('ERR_MortarPrediction.', 'ERR_MortarPrediction::')
complete=body(p,'static bool Complete(').replace('ERR_MortarSalvo.', 'ERR_MortarSalvo::')
methods='\n'.join(body(p,sig) for sig in ['void NativeCommit(', 'void NativeClosing(', 'void NativeProjectile('])
for a,b in [('ERR_MortarBattery battery','Battery* battery'),('IEntity gun, IEntity projectile','Entity* gun, Entity* projectile'),('string reason, string failure','std::string reason, std::string failure'),('m_Battery.','m_Battery->'),('battery.','battery->'),('Report.','Report->'),('projectile.GetOrigin()','projectile->GetOrigin()'),('GetGame().GetWorld().GetWorldTime()','clockNow'),('ERR_NativeMortarEvidenceRules.','ERR_NativeMortarEvidenceRules::'),('ERR_MortarSalvo.','ERR_MortarSalvo::')]: methods=methods.replace(a,b)
run('''#include <cassert>
#include <vector>
#include <algorithm>
#include <string>
float clockNow=20000;
struct ERR_MortarPrediction {static constexpr float MAX_REPORT_AGE_MS=60000;};
struct ERR_MortarSalvo {static constexpr int ROUNDS=8;};
struct ERR_NativeMortarEvidenceRules {'''+rules+'''};
struct Rules {'''+complete+'''};
struct Entity {int GetOrigin(){return 0;}};
struct Report {int MessageId=7;float ObservedAt=1000;};
struct Battery {void* Activity=nullptr;void* Refresh=nullptr;bool RefreshRejected=false;bool CommandOpen=true,Released=true,stopped=false;int SourceId=7,OrderId=1,OrderShots=0;float AimedAt=19000,AimValidatedAt=19000,FlightTime=20;struct Report report;struct Report* Report=&report;bool Stopped(){return stopped;}};
struct Items {std::vector<Entity*> values;bool Contains(Entity* p){return std::find(values.begin(),values.end(),p)!=values.end();}void Insert(Entity* p){values.push_back(p);}};
template<class... Args>void PrintFormat(Args...args){}
struct Probe {
void* m_OriginalActivity=nullptr;bool m_RefreshCase=false;int m_UpdatedCommits=0,m_CommitSource=0;float m_CommitObservedAt=0;
bool m_Stopped=false,m_BadProjectile=false,m_CommitPending=false,m_ClosureSeen=false,m_ClosureComplete=false;
Battery* m_Battery;Entity* m_Gun;Items m_Projectiles;int m_Events=0,m_Step=1,m_Source=7,m_Order=1,m_Commits=0,m_CommitOrder=0,m_CommitShot=0;float m_ObservedAt=1000,m_CommittedAt=0;std::string m_BadReason;
bool ReportKnown(Report* report){return report&&report->MessageId==m_Source&&report->ObservedAt==m_ObservedAt;}
bool AllAccepted(){return !m_RefreshCase;}
'''+methods+'''};
int main(){
assert(Rules::Complete(8,8,8,8,19,false));
for(int count=0;count<8;count++)assert(!Rules::Complete(count,count,count,count,27-count,false));
assert(!Rules::Complete(9,9,9,9,18,false));
assert(!Rules::Complete(8,7,8,8,19,false));
assert(!Rules::Complete(8,8,7,8,19,false));
assert(!Rules::Complete(8,8,8,7,19,false));
assert(!Rules::Complete(8,8,8,8,20,false));
assert(!Rules::Complete(8,8,8,8,18,false));
assert(!Rules::Complete(8,8,8,8,19,true));
Entity gun,foreign,shots[9];Battery b;Probe p;p.m_Battery=&b;p.m_Gun=&gun;
p.NativeProjectile(&foreign,&shots[0]);assert(p.m_Events==0);
for(int i=0;i<8;i++){
b.OrderShots=i;b.AimedAt=clockNow;b.AimValidatedAt=clockNow;
p.NativeCommit(&b,clockNow);assert(p.m_CommitPending&&!p.m_BadProjectile&&p.m_Commits==i+1);
clockNow+=500;p.NativeProjectile(&gun,&shots[i]);assert(p.m_Events==i+1&&!p.m_CommitPending&&!p.m_BadProjectile);
}
b.OrderShots=8;p.NativeClosing(&b,"native artillery activity COMPLETED (shot count is separate)","");
assert(p.m_ClosureSeen&&p.m_ClosureComplete&&!p.m_BadProjectile);
p.NativeCommit(&b,clockNow);assert(p.m_BadProjectile&&p.m_Commits==8); // ninth commit forbidden
for(int fault=0;fault<11;fault++){
Battery f;Probe q;q.m_Battery=&f;q.m_Gun=&gun;clockNow=20000;
if(fault==0)f.report.ObservedAt=1001; // retimestamped contact
if(fault==1)f.OrderId=2;
if(fault==2)f.SourceId=8;
if(fault==3)f.OrderShots=1; // skipped physical event
if(fault==4)q.m_Step=2; // post-completion replay
if(fault==5)q.m_CommitPending=true;
if(fault==6){clockNow=61001;f.AimedAt=61000;f.AimValidatedAt=61000;}
if(fault==7)f.AimValidatedAt=9999;
if(fault==8)f.Released=false;
if(fault==9)f.CommandOpen=false;
if(fault==10)f.FlightTime=0;
q.NativeCommit(&f,clockNow);assert(q.m_BadProjectile&&q.m_Commits==0);
}
Battery f;Probe q;q.m_Battery=&f;q.m_Gun=&gun;clockNow=20000;
q.NativeCommit(&f,clockNow);q.NativeProjectile(&gun,&shots[0]);q.NativeProjectile(&gun,&shots[0]);assert(q.m_BadProjectile&&q.m_Events==1);
for(int fault=0;fault<4;fault++){
Battery f;Probe q;q.m_Battery=&f;q.m_Gun=&gun;q.m_Events=8;q.m_Commits=8;f.OrderShots=8;
std::string reason="native artillery activity COMPLETED (shot count is separate)";
if(fault==0){q.m_Events=4;q.m_Commits=4;f.OrderShots=4;}
if(fault==1)reason="native aim or firing authorization rejected";
if(fault==2)f.stopped=true;
if(fault==3)q.m_CommitPending=true;
q.NativeClosing(&f,reason,"delivered target report expired");assert(q.m_BadProjectile);
}
Battery stopped;Probe quiet;quiet.m_Battery=&stopped;quiet.m_Gun=&gun;quiet.m_Stopped=true;
quiet.NativeCommit(&stopped,20000);quiet.NativeProjectile(&gun,&shots[0]);quiet.NativeClosing(&stopped,"HQ stopped","");
assert(!quiet.m_BadProjectile&&quiet.m_Events==0&&quiet.m_Commits==0&&!quiet.m_ClosureSeen);
}
''')
# Native hooks must count only real events and retain the existing superclass behavior.
s=p.read_text()
assert s.startswith('#ifdef WORKBENCH') and 'outcome == "mortar-salvo"' in s
assert 'super.OnWeaponFired(effectEntity, muzzle, projectileEntity);' in s
assert 'super.ReserveShellAirspace(now);' in s and 'super.Cancel(reason);' in s
assert 'm_StopUntil = now + 25000' in s
assert 'm_Battery.CanRequest(m_Delivered, now)' in s
assert 'm_Battery.Order(' not in s and 'm_Battery.BeginRequest(' not in s
assert 'm_Battery.Stop();' in body(p,'void Stop(')
print('PASS: actual full-salvo gates require eight fresh committed physical launches, natural closure and exact finite inventory; reject partial/extra/replayed events')