Advance standalone admission, finite artillery and native validation

This commit is contained in:
2026-09-19 09:02:31 +02:00
parent af5146a317
commit 40a474934c
532 changed files with 56456 additions and 199 deletions
+1 -1
View File
@@ -18,4 +18,4 @@ int main(){for(int site=0;site<4;site++)for(int order=0;order<10;order++){
}
}}
''')
print('PASS: migrated salvo offsets are deterministic, spread and bounded (firing controller pending)')
print('PASS: migrated salvo offsets are deterministic, spread and bounded (native firing and complete salvo qualification are separate)')
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env python3
import contextlib
import importlib.util
import io
from pathlib import Path
import sys
import tempfile
import unittest
from unittest.mock import patch
spec = importlib.util.spec_from_file_location('dedicated_native', Path(__file__).parents[1] / 'tools/dedicated_native.py')
runner = importlib.util.module_from_spec(spec)
spec.loader.exec_module(runner)
class DedicatedNativeTests(unittest.TestCase):
def probe(self, namespace='isolated', interfaces=None, routes=None, ipv6=''):
interfaces = interfaces if interfaces is not None else [(1, 'lo')]
routes = routes if routes is not None else 'Iface Destination Gateway\n'
def content(path, *args):
return io.StringIO(ipv6 if path.endswith('ipv6_route') else routes)
with patch('os.readlink', return_value=namespace), patch('socket.if_nameindex', return_value=interfaces), patch('builtins.open', side_effect=content), patch.object(sys, 'argv', ['probe', 'host', '/server']), patch('os.execv') as launch, contextlib.redirect_stdout(io.StringIO()):
try:
exec(runner.PROBE, {})
except AssertionError:
self.assertFalse(launch.called)
return False
launch.assert_called_once_with('/server', ['/server'])
return True
def test_isolation_gate_executes_only_private_loopback(self):
self.assertTrue(self.probe())
self.assertFalse(self.probe(namespace='host'))
self.assertFalse(self.probe(interfaces=[(1, 'lo'), (2, 'eth0')]))
self.assertFalse(self.probe(routes='Iface Destination\neth0 00000000\n'))
self.assertFalse(self.probe(ipv6='0000 eth0\n'))
self.assertTrue(self.probe(ipv6='0000 lo\n'))
def test_vanilla_control_has_no_successor_or_custom_systems(self):
args=runner.engine_args('vanilla-everon')
self.assertNotIn('-addons',args)
self.assertNotIn('-addonsDir',args)
self.assertNotIn('-worldSystemsConfig',args)
self.assertEqual(args[-2:],['-server','Missions/21_GM_Eden.conf'])
self.assertEqual(args[0],'/tmp/runtime/ArmaReforgerServer')
def test_manifest_detects_mutation_and_refuses_links(self):
with tempfile.TemporaryDirectory() as directory:
root=Path(directory); target=root/'a.c'; target.write_text('first')
old=runner.manifest(root); target.write_text('second')
self.assertNotEqual(old,runner.manifest(root))
(root/'linked').symlink_to(target)
with self.assertRaises(ValueError): runner.manifest(root)
def test_routes_do_not_mix_public_config_or_client_flags(self):
for route in ['header','diag-world','vanilla-everon']:
args=runner.engine_args(route)
self.assertNotIn('-config',args)
self.assertNotIn('-client',args)
self.assertIn('-noBackend',args)
self.assertNotIn('-rpl-validation-rdb-disable',args)
normal=runner.engine_args('header')
self.assertEqual(normal[0],'/tmp/runtime/ArmaReforgerServer')
self.assertTrue(normal[normal.index('-server')+1].endswith('ERR_Everon_Base.conf'))
self.assertNotIn('-worldSystemsConfig',normal)
self.assertIn('-worldSystemsConfig',runner.engine_args('diag-world'))
if __name__ == '__main__': unittest.main()
+104
View File
@@ -0,0 +1,104 @@
"""Synthetic files test no-launch planning; never execute a server or client."""
import json
from pathlib import Path
import sys
import tempfile
import unittest
from unittest.mock import patch
sys.path.insert(0, str(Path(__file__).resolve().parents[1]/'tools'))
import dedicated_preflight as tool
class DedicatedPreflightTests(unittest.TestCase):
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
root = Path(self.tmp.name)
self.source, self.runtime = root/'source', root/'runtime'
self.runtime.mkdir()
for project, header in tool.HEADERS.items():
addon = self.source/'addons'/project
path = addon/header
path.parent.mkdir(parents=True)
(addon/'addon.gproj').write_text('GameProject { GUID "2528466DE220D91C" }')
path.write_text('SCR_MissionHeader { World "'+tool.WORLD+'" SystemsConfig "'+tool.SYSTEMS+'" }')
path.with_suffix('.conf.meta').write_text('MetaFileClass { Name "{AD62322D5213C440}'+header+'" }')
(self.runtime/'runtime-origin.json').write_text(json.dumps({'app_id':1874900,'purpose':'private anonymous Reforger dedicated server preparation; no server launched'}))
def plan(self, **kwargs):
return tool.build_plan(self.source,self.runtime,**kwargs)
def installed(self, app='1874900', architecture=62):
directory=self.runtime/'server';directory.mkdir(exist_ok=True)
binary=directory/'ArmaReforgerServer'
data=bytearray(20);data[:6]=b'\x7fELF\x02\x01';data[18:20]=architecture.to_bytes(2,'little')
binary.write_bytes(data);binary.chmod(0o700)
manifests=directory/'steamapps';manifests.mkdir(exist_ok=True)
(manifests/'appmanifest_1874900.acf').write_text('"AppState" { "appid" "'+app+'" "buildid" "synthetic-build" "StateFlags" "4" }')
return binary
def test_missing_runtime_still_prepares_strict_loopback_review(self):
result,config,_=self.plan()
self.assertFalse(result['launch_allowed']);self.assertFalse(result['multiplayer_passed'])
self.assertEqual(result['genuine_clients_verified'],0)
self.assertIn('missing or incomplete',result['blockers'][0])
self.assertEqual(config['bindAddress'],'127.0.0.1')
self.assertEqual(config['publicAddress'],'127.0.0.1')
self.assertFalse(config['game']['visible'])
self.assertTrue(config['game']['gameProperties']['fastValidation'])
self.assertTrue(config['game']['gameProperties']['battlEye'])
self.assertTrue(config['operating']['disableCrashReporter'])
self.assertNotIn('rcon',config);self.assertNotIn('a2s',config)
def test_binary_is_inspected_never_executed_and_cannot_establish_mp(self):
self.installed()
with patch('subprocess.run',side_effect=AssertionError('must not run')),patch('subprocess.Popen',side_effect=AssertionError('must not spawn')):
result,_,_=self.plan()
runtime=result['runtime']
self.assertTrue(runtime['binary_elf_x86_64']);self.assertTrue(runtime['install_complete'])
self.assertEqual(runtime['steam_build_id'],'synthetic-build')
self.assertIsNone(runtime['engine_version']);self.assertFalse(runtime['native_runtime_executed'])
self.assertFalse(result['launch_allowed']);self.assertTrue(result['blockers'])
def test_wrong_app_rejected_wrong_arch_incomplete(self):
self.installed(app='1890870')
with self.assertRaisesRegex(ValueError,'stable dedicated'):self.plan()
self.installed(architecture=183)
result,_,_=self.plan();self.assertFalse(result['runtime']['binary_elf_x86_64'])
self.assertIn('missing or incomplete',result['blockers'][0])
def test_symlink_to_existing_server_rejected(self):
binary=self.installed();target=self.runtime/'other-server';binary.rename(target);binary.symlink_to(target)
with self.assertRaisesRegex(ValueError,'symlink'):self.plan()
def test_header_and_port_validation(self):
for port in (0,1023,65536):
with self.assertRaisesRegex(ValueError,'unprivileged'):self.plan(port=port)
header=self.source/'addons/core'/tool.HEADERS['core']
header.write_text(header.read_text().replace(tool.SYSTEMS,'wrong'))
with self.assertRaisesRegex(ValueError,'SystemsConfig'):self.plan()
def test_project_selection_and_source_snapshot_change(self):
before,config,_=self.plan(project='chat')
self.assertEqual(before['scenario']['project'],'chat')
self.assertTrue(config['game']['scenarioId'].endswith(tool.HEADERS['chat']))
(self.source/'addons/core/new.c').write_text('// independent new source')
after,_,_=self.plan(project='chat')
self.assertNotEqual(before['source_manifest_sha256'],after['source_manifest_sha256'])
def test_write_new_private_review_only_preserves_existing_evidence(self):
result,config,manifest=self.plan();destination=self.runtime/'review'
tool.write_plan(destination,result,config,manifest)
self.assertEqual(json.loads((destination/'server-config.review.json').read_text()),config)
self.assertFalse(json.loads((destination/'preflight.json').read_text())['listener_started'])
self.assertEqual(tool.digest(destination/'source-manifest.json'),result['source_manifest_sha256'])
with self.assertRaisesRegex(ValueError,'never overwritten'):tool.write_plan(destination,result,config,manifest)
with self.assertRaisesRegex(ValueError,'direct child'):tool.write_plan(self.source/'review',result,config,manifest)
def test_unmarked_runtime_and_source_overlap_refused(self):
result,config,manifest=self.plan();(self.runtime/'runtime-origin.json').unlink()
with self.assertRaisesRegex(ValueError,'origin marker'):tool.write_plan(self.runtime/'review',result,config,manifest)
with self.assertRaisesRegex(ValueError,'separate'):tool.build_plan(self.source,self.source/'runtime')
if __name__=='__main__':unittest.main()
+15 -3
View File
@@ -179,7 +179,7 @@ class GameRunnerTests(unittest.TestCase):
def test_ready_requires_game_module_without_workbench_and_normal_phase(self):
module = 'SCRIPT : Module: Game; loaded 12x files; defines: "PLATFORM_WINDOWS,ENABLE_DIAG"; CRC32: a\n'
phase = 'SCRIPT : Rereintroduced [mission]: phase 0 -> 1\nSCRIPT : ERR ORDINARY: header verified project=core systems=MissionSystems\n'
phase = 'SCRIPT : Rereintroduced [mission]: phase 0 -> 1\nSCRIPT : ERR ORDINARY: header verified project=core systems=MissionSystems\nSCRIPT : ERR ORDINARY: local participant verified project=core phase=prison\n'
self.assertTrue(runner.game_evidence(module+phase)['ready'])
self.assertFalse(runner.game_evidence(phase)['ready'])
self.assertFalse(runner.game_evidence(module)['ready'])
@@ -190,8 +190,8 @@ class GameRunnerTests(unittest.TestCase):
def test_startup_requires_selected_header_and_actual_systems_marker(self):
module = 'SCRIPT : Module: Game; defines: "PLATFORM_WINDOWS"; CRC32: a\n'
phase = 'SCRIPT : Rereintroduced [mission]: phase 0 -> 1\n'
core = 'SCRIPT : ERR ORDINARY: header verified project=core systems=MissionSystems\n'
chat = 'SCRIPT : ERR ORDINARY: header verified project=chat systems=MissionSystems\n'
core = 'SCRIPT : ERR ORDINARY: header verified project=core systems=MissionSystems\nSCRIPT : ERR ORDINARY: local participant verified project=core phase=prison\n'
chat = 'SCRIPT : ERR ORDINARY: header verified project=chat systems=MissionSystems\nSCRIPT : ERR ORDINARY: local participant verified project=chat phase=prison\n'
self.assertFalse(runner.game_evidence(module+phase, 'core')['ready'])
self.assertFalse(runner.game_evidence(module+phase+core, 'chat')['ready'])
self.assertTrue(runner.game_evidence(module+phase+chat, 'chat')['ready'])
@@ -202,6 +202,18 @@ class GameRunnerTests(unittest.TestCase):
self.assertTrue(result['failed'])
self.assertFalse(result['ready'])
def test_world_without_normal_local_admission_is_not_ready(self):
world = ('SCRIPT : Module: Game; defines: "PLATFORM_WINDOWS"; CRC32: a\n'
'SCRIPT : Rereintroduced [mission]: phase 0 -> 1\n'
'SCRIPT : ERR ORDINARY: header verified project=core systems=MissionSystems\n')
result = runner.game_evidence(world, 'core')
self.assertTrue(result['scenario_header_verified'])
self.assertFalse(result['local_participant_verified'])
self.assertFalse(result['ready'])
self.assertFalse(result['failed']) # incomplete admission may still arrive
self.assertFalse(runner.game_evidence(world+'ERR ORDINARY: local participant verified project=chat phase=prison\n', 'core')['ready'])
self.assertTrue(runner.game_evidence(world+'ERR ORDINARY: local participant verified project=core phase=prison\n', 'core')['ready'])
def test_no_engine_or_audio_spawn_during_import_and_process_refusal(self):
with patch.object(runner, 'assert_no_game', side_effect=ValueError('existing game')):
with patch.object(runner.subprocess, 'Popen') as spawn, patch.object(runner.subprocess, 'run') as commands:
+89
View File
@@ -0,0 +1,89 @@
"""Execute actual resolver/context/latch bodies with opaque native handles.
UUID generation/nullness and native session/controller APIs are substituted;
this is not authentication, native GenV4 or multiplayer evidence.
"""
from policy_harness import ROOT, body, run
import re
source=ROOT/'addons/core/Scripts/Game/ERR/ERR_LocalAdmission.c'
s=source.read_text().split('\nmodded class ERR_GameMode')[0]
s=s[s.index('class ERR_LocalAdmissionRules'):]
s=s.replace('class ERR_LocalAdmissionRules','struct ERR_LocalAdmissionRules').replace('class ERR_LocalAdmission\n','struct ERR_LocalAdmission\n')
s=s.replace('\n}\n','\n};\n').replace('protected ','')
s=s.replace('void ERR_LocalAdmission(', 'ERR_LocalAdmission(')
s=s.replace('ERR_GameMode', 'Mode').replace('SCR_PlayerController', 'Controller').replace('PlayerManager', 'Manager')
s=re.sub(r'\b(Mode|Controller|Manager) (mode|controller|manager|m_Mode|m_Controller)\b',r'\1* \2',s)
s=s.replace('Mode.Get()', 'Mode::Get()').replace('RplMode.None','0')
s=s.replace('Replication.IsServer()', 'isServer').replace('RplSession.Mode()', 'sessionMode')
s=s.replace('GetGame().', 'GetGame()->').replace('manager.', 'manager->').replace('controller.', 'controller->')
s=s.replace('System.GetCLIParam', 'System::GetCLIParam').replace('string project;', 'std::string project;')
s=s.replace('bool connected, sameManager;', 'bool connected=false, sameManager=false;').replace('int controllerId;', 'int controllerId=0;')
s=s.replace('ERR_LocalAdmissionRules.', 'ERR_LocalAdmissionRules::')
s=s.replace('UUID.NULL_UUID','UUID::NULL_UUID').replace('UUID.GenV4()', 'UUID::GenV4()').replace('null','nullptr')
# Enforce initializes managed fields; retain that contract in this C++ model.
s=s.replace('Mode* m_Mode;', 'Mode* m_Mode=nullptr;').replace('Controller* m_Controller;', 'Controller* m_Controller=nullptr;')
s=re.sub(r'\b(bool|int) (m_\w+);',r'\1 \2=0;',s)
run('''#include <cassert>
#include <string>
int generated=0;bool isServer=true;int sessionMode=0;
struct UUID {int value=0;bool IsNull(){return value<=0;}bool operator==(UUID other){return value==other.value;}static UUID NULL_UUID;static UUID GenV4(){return UUID{++generated+100};}};
UUID UUID::NULL_UUID{0};
struct Controller {int id=1;int GetPlayerId(){return id;}};
struct Manager {int count=1;bool connected=true;Controller* controller=nullptr;int GetPlayerCount(){return count;}bool IsPlayerConnected(int id){return connected;}Controller* GetPlayerController(int id){return controller;}};
struct Mode {static Mode* current;static Mode* Get(){return current;}};Mode* Mode::current=nullptr;
struct Game {Manager* manager=nullptr;Controller* local=nullptr;Manager* GetManager(){return manager;}Controller* GetPlayerController(){return local;}};
Game* game=nullptr;Game* GetGame(){return game;}void Print(const char*){}
namespace System {bool GetCLIParam(const char*,std::string&){return false;}}
template<class... Args> void PrintFormat(Args... args) {}
'''+s+'''
int main(){
// Exact None only; every context condition independently matters.
for(int mode=-1;mode<5;++mode)for(int count=0;count<3;++count)for(int flags=0;flags<16;++flags)
assert(ERR_LocalAdmissionRules::Context(flags&1,mode,count,flags&2,flags&4,flags&8,1,1)==(mode==0&&count==1&&flags==15));
assert(!ERR_LocalAdmissionRules::Context(true,0,1,true,true,true,0,0));
assert(!ERR_LocalAdmissionRules::Context(true,0,1,true,true,true,1,2));
Mode round,nextRound;Mode::current=&round;Controller owner,replacement;Manager manager;manager.controller=&owner;Game world{&manager,&owner};game=&world;
ERR_LocalAdmission admission(&round);
UUID selected=admission.Resolve(&round,1,&owner,UUID{0});assert(!selected.IsNull()&&admission.LocalKey()&&generated==1);
assert(admission.Resolve(&round,1,&owner,UUID{0})==selected&&generated==1);
assert(admission.Resolve(&round,1,&owner,UUID{55})==selected&&generated==1); // late BI arrival cannot make fresh life
assert(admission.Validate());
assert(!admission.Disconnected(2));assert(admission.Validate());
assert(admission.Disconnected(1));assert(!admission.Validate());
assert(admission.Resolve(&round,1,&owner,UUID{55}).IsNull()); // irreversible within this mode
ERR_LocalAdmission native(&round);assert(native.Resolve(&round,1,&owner,UUID{55})==UUID{55});
assert(!native.LocalKey()&&native.Resolve(&round,1,&owner,UUID{0})==UUID{55}&&generated==1);
native.Stop();assert(native.Resolve(&round,1,&owner,UUID{0}).IsNull());assert(!native.Validate());
// Replacement, mode switch, manager/local mismatch and additional connections latch.
for(int fault=0;fault<6;++fault){
sessionMode=0;Mode::current=&round;manager.controller=&owner;world.local=&owner;manager.count=1;manager.connected=true;
ERR_LocalAdmission a(&round);assert(!a.Resolve(&round,1,&owner,UUID{0}).IsNull());
if(fault==0)sessionMode=1;
if(fault==1)manager.controller=&replacement;
if(fault==2)world.local=&replacement;
if(fault==3)manager.count=2;
if(fault==4)manager.connected=false;
if(fault==5)Mode::current=&nextRound;
assert(!a.Validate());
sessionMode=0;Mode::current=&round;manager.controller=&owner;world.local=&owner;manager.count=1;manager.connected=true;
assert(!a.Validate());assert(a.Resolve(&round,1,&owner,UUID{88}).IsNull());
}
// A newly created round owns a fresh key. Old resolver cannot be reused.
Mode::current=&nextRound;ERR_LocalAdmission next(&nextRound);UUID nextKey=next.Resolve(&nextRound,1,&owner,UUID{0});assert(!(nextKey==selected));
assert(admission.Resolve(&nextRound,1,&owner,UUID{0}).IsNull());
// Fresh network modes remain native even on an absent controller/local world,
// after Stop, on null backend data, and with changing native identities.
for(int mode: {1,2,3}){
sessionMode=mode;int before=generated;ERR_LocalAdmission network(&nextRound);game=nullptr;
assert(network.Resolve(&nextRound,9,nullptr,UUID{41})==UUID{41});
assert(network.Resolve(&nextRound,9,nullptr,UUID{0}).IsNull());
network.Stop();assert(network.Validate());
assert(network.Resolve(&nextRound,9,nullptr,UUID{42})==UUID{42});
assert(!network.Selected()&&!network.LocalKey()&&generated==before);game=&world;
}
// Incomplete local context cannot generate a key and cannot later self-repair.
sessionMode=0;manager.count=0;int before=generated;ERR_LocalAdmission invalid(&nextRound);
assert(invalid.Resolve(&nextRound,1,&owner,UUID{0}).IsNull()&&generated==before);
manager.count=1;assert(invalid.Resolve(&nextRound,1,&owner,UUID{0}).IsNull());
}
''')
print('PASS: actual local admission context/selection/latch, same-round late identity, replacement/mode failure, fresh round and untouched network path')
+83
View File
@@ -0,0 +1,83 @@
"""Execute actual aim-equivalence and renewal control flow with synthetic API data.
No fake native ballistic result is represented as a measured firing result.
"""
import re
from policy_harness import ROOT, body, run
r=ROOT/'addons/ai/Scripts/Game/ERR'
solution=r/'ERR_MortarAimSolution.c'; firing=r/'ERR_MortarFiring.c'
eq=body(solution,'static bool Equivalent(').replace('vector.Distance','vector::Distance').replace('Math.AbsFloat','std::fabs')
matches=body(solution,'bool Matches(').replace('ERR_MortarBattery battery','ERR_MortarBattery* battery').replace('ERR_HQReport report','ERR_HQReport* report').replace('battery.','battery->')
fresh=body(r/'ERR_MortarPrediction.c','static bool Fresh(').replace('ERR_HQReport report','ERR_HQReport* report').replace('report.','report->')
renew=body(firing,'bool ERR_RevalidateAim(')
for typ in ['ERR_MortarBattery','ERR_MortarSystem','ERR_HQReport','ERR_MortarAimSolution']:
renew=re.sub(r'\b'+typ+r' (battery|system|report|commanded|updated)\b',typ+r'* \1',renew)
renew=renew.replace('IEntity gun;','IEntity gun=nullptr;').replace('ResourceName ammo;','std::string ammo;')
for name in ['battery','system','report','commanded','updated']:renew=renew.replace(name+'.',name+'->')
for name in ['ERR_MortarBattery','ERR_MortarAimRules','ERR_MortarPrediction']:renew=renew.replace(name+'.',name+'::')
# Native trace formatting is deliberately inert. Authorization branches remain
# the production method body, and every solver invocation is counted below.
renew=re.sub(r', string\.Format\([^\n]*\)\);',');',renew)
run('''#include <cassert>
#include <cmath>
#include <limits>
#include <string>
struct vector {float x=0,y=0,z=0; static float Distance(vector a,vector b){return std::sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));}};
using IEntity=void*;
struct ERR_HQReport {IEntity Target=this;bool Distress=false;float ObservedAt=0;std::string TravelMode="foot";};
struct ERR_MortarPrediction {static constexpr float MAX_REPORT_AGE_MS=60000;
'''+fresh+'''};
struct ERR_MortarAimRules {
'''+eq+'''};
struct Node;struct ERR_MortarAimSolution;
struct ERR_MortarBattery {static inline std::string SHELL="nativeHE";IEntity Gun=this;ERR_MortarAimSolution* AimSolution=nullptr;Node* AimSolver=nullptr;int OrderId=1,OrderShots=0;float AimedAt=1000; void Trace(const char*,const char*){}};
struct ERR_MortarAimSolution {IEntity Gun=nullptr;ERR_HQReport* Report=nullptr;int OrderId=1,Shot=0,Charge=0;vector GunOrigin{},Impact{500,0,0},AimTarget{500,500,0};float FlightTime=30;
'''+matches+'''};
struct ERR_MortarSystem {int rejects=0;bool Withhold(ERR_MortarBattery*,const char*){rejects++;return false;}const char* ContactFailure(ERR_MortarBattery*){return "stale";}};
struct Node {
static constexpr int PORT_ARTILLERY_ENTITY=1,PORT_AMMO_PREFAB=2;
IEntity portGun=nullptr;std::string portAmmo=ERR_MortarBattery::SHELL;ERR_MortarAimSolution* calculated=nullptr;int solves=0;
void GetVariableIn(int,IEntity& out){out=portGun;}void GetVariableIn(int,std::string& out){out=portAmmo;}
ERR_MortarAimSolution* ERR_Solve(ERR_MortarBattery*,ERR_MortarSystem* system,ERR_HQReport*,float){solves++;if(!calculated)system->rejects++;return calculated;}
'''+renew+'''};
struct Fixture {
ERR_MortarBattery battery;ERR_HQReport report;ERR_MortarAimSolution original,next;ERR_MortarSystem system;Node node;
Fixture(){original.Gun=battery.Gun;original.Report=&report;next=original;battery.AimSolution=&original;battery.AimSolver=&node;node.portGun=battery.Gun;node.calculated=&next;}
bool attempt(float now=25000){return node.ERR_RevalidateAim(&battery,&system,&report,now);}
};
int main(){
Fixture stable; assert(stable.attempt()); assert(stable.node.solves==1&&stable.battery.AimedAt==25000);
assert(stable.report.ObservedAt==0&&stable.battery.AimSolution==&stable.original);
assert(stable.attempt(45000)&&stable.node.solves==2); // fresh recomputation every renewal
assert(!stable.attempt(60001)&&stable.node.solves==2&&stable.battery.AimedAt==45000); // observation never renewed
Fixture limit;assert(limit.attempt(60000));
Fixture future;future.report.ObservedAt=26000;assert(!future.attempt()&&future.node.solves==0);
Fixture gone;gone.battery.AimSolver=nullptr;assert(!gone.attempt()&&gone.node.solves==0);
Fixture wrongGun;wrongGun.node.portGun=&wrongGun.report;assert(!wrongGun.attempt()&&wrongGun.node.solves==0);
Fixture wrongAmmo;wrongAmmo.node.portAmmo="other";assert(!wrongAmmo.attempt()&&wrongAmmo.node.solves==0);
Fixture newReport;ERR_HQReport different;newReport.original.Report=&different;assert(!newReport.attempt()&&newReport.node.solves==0);
Fixture nextOrder;nextOrder.battery.OrderId++;assert(!nextOrder.attempt()&&nextOrder.node.solves==0);
Fixture nextShot;nextShot.battery.OrderShots++;assert(!nextShot.attempt()&&nextShot.node.solves==0);
Fixture solverFail;solverFail.node.calculated=nullptr;assert(!solverFail.attempt()&&solverFail.battery.AimedAt==1000);
Fixture charge;charge.next.Charge++;assert(!charge.attempt()&&charge.battery.AimedAt==1000);
Fixture gunMove;gunMove.next.GunOrigin.y=.051f;assert(!gunMove.attempt());
Fixture impactMove;impactMove.next.Impact.y=.101f;assert(!impactMove.attempt());
Fixture aimMove;aimMove.next.AimTarget.y+=.101f;assert(!aimMove.attempt());
Fixture flight;flight.next.FlightTime+=.051f;assert(!flight.attempt());
Fixture invalid;invalid.next.FlightTime=std::numeric_limits<float>::quiet_NaN();assert(!invalid.attempt());
Fixture slowDrift;slowDrift.next.Impact.x+=.06f;assert(slowDrift.attempt());
slowDrift.next.Impact.x+=.06f;assert(!slowDrift.attempt(35000)); // compare original, not last accepted approximation
assert(slowDrift.battery.AimSolution==&slowDrift.original&&slowDrift.original.Impact.x==500);
}
''')
# The tested renewal is used at both existing pre-shot and physical-transfer
# gates; it may neither emit a replacement barrel command nor change a report.
source=firing.read_text();system=(r/'ERR_MortarSystem.c').read_text()
assert source.count('system.AllowShot(battery)')==2
assert 'SetVariableOut' not in body(firing,'bool ERR_RevalidateAim(')
assert 'ObservedAt =' not in source
assert 'now - battery.AimedAt > 10000' in system
assert 'battery.AimSolver.ERR_RevalidateAim(battery, this, report, now)' in system
assert source.count('BallisticTable.GetAimHeightOfProjectileAltitudeFromSource(')==1
assert 'GetAmmoInitialSpeedCoefficients(ammo, coefficients)' in body(firing,'protected ERR_MortarAimSolution ERR_Solve(')
print('PASS: actual aim renewal requires fresh same-report solve and original-command equivalence; native firing untested')
+39
View File
@@ -0,0 +1,39 @@
"""Execute the production report ledger; native scheduler coverage is separate."""
from pathlib import Path
from policy_harness import body, run
r=Path(__file__).resolve().parents[1]
p=r/'addons/ai/Scripts/Game/ERR/ERR_MortarReportLedger.c'
a=body(p,'bool Available(').replace('m_Attempts.', 'm_Attempts.')
c=body(p,'bool Claim(')
run('''#include <cassert>
#include <map>
#include <iterator>
struct Entries {std::map<int,float> entries; int Count(){return entries.size();}
int GetKey(int i){return std::next(entries.begin(),i)->first;}
float GetElement(int i){return std::next(entries.begin(),i)->second;}
void Remove(int key){entries.erase(key);} bool Contains(int key){return entries.count(key);}
void Insert(int key,float time){entries.emplace(key,time);}};
struct ERR_MortarPrediction {static constexpr float MAX_REPORT_AGE_MS=60000;};
struct Ledger {Entries m_Attempts;
'''+a.replace('ERR_MortarPrediction.', 'ERR_MortarPrediction::')+c+'''};
int main(){
Ledger a; assert(a.Available(1,0,0));assert(a.Available(1,0,10)); // unavailable radio must not claim
assert(a.Claim(1,0,100));assert(!a.Available(1,0,200));assert(!a.Claim(1,0,50000));
assert(!a.Claim(1,10000,50000)); // rewritten timestamp cannot refresh same message
assert(a.Claim(2,200,300));assert(!a.Claim(1,0,60000)); // A/B/A replay
assert(!a.Available(1,0,60001));assert(a.Claim(3,60001,60001));
assert(a.m_Attempts.Count()==2);assert(a.Claim(4,60300,60300));assert(a.m_Attempts.Count()==2);
assert(!a.Claim(0,0,0));assert(!a.Claim(-1,0,0));assert(!a.Claim(5,-1,0));
assert(!a.Claim(5,100,99));assert(!a.Claim(5,0,60001));
Ledger bounded;for(int i=1;i<=128;i++)assert(bounded.Claim(i,0,0));
assert(!bounded.Claim(129,1,1));assert(bounded.Claim(130,60001,60001));assert(bounded.m_Attempts.Count()==1);
Ledger nextRound;assert(nextRound.Claim(1,0,0));
}
''')
b=r/'addons/ai/Scripts/Game/ERR/ERR_MortarBattery.c';s=r/'addons/ai/Scripts/Game/ERR/ERR_MortarSystem.c'
request=body(b,'bool BeginRequest(')
assert request.index('m_ReportLedger.Claim(')<request.index('Cancel(')<request.index('OrderId++')
assert 'm_ReportLedger' not in body(b,'void Cancel(')
tick=body(s,'void Tick(')
assert tick.index('battery.CanRequest(report, now)')<tick.index('m_HQ.Downlink(')<tick.index('selected.BeginRequest(')
print('PASS: actual mortar report ledger prevents duplicate response after cancellation, expiry and interleaved reports; native scheduler separate')
+101
View File
@@ -0,0 +1,101 @@
"""Actual Enforce policies and transaction observation body under narrow API fakes."""
from policy_harness import ROOT, body, run
r=ROOT/'addons/ai/Scripts/Game/ERR'
readiness=r/'ERR_MortarReadiness.c'; transfer=r/'ERR_MortarSupplyTransfer.c'; battery=r/'ERR_MortarBattery.c'
policy='\n'.join([body(readiness,'static ERR_MortarSupplyState Population('),body(readiness,'static bool AllocationValid('),body(readiness,'static int CycleGate('),body(transfer,'static bool Authority('),body(transfer,'static bool Proven(')])
policy=policy.replace('ERR_MortarSupplyState.','ERR_MortarSupplyState::')
run('''#include <cassert>
enum class ERR_MortarSupplyState {FAILED=-1,PENDING,READY};
'''+policy+'''
int main(){
using S=ERR_MortarSupplyState;
assert(Population(0,0,0,false,false)==S::PENDING);
assert(Population(3,3,0,true,false)==S::PENDING);
assert(Population(4,3,1,false,false)==S::PENDING);
assert(Population(4,3,1,true,false)==S::READY);
assert(Population(4,3,1,true,true)==S::FAILED);
assert(Population(0,0,0,false,true)==S::FAILED);
assert(Population(5,3,2,true,false)==S::FAILED);
assert(Population(4,4,0,true,false)==S::FAILED);
assert(AllocationValid(0)&&AllocationValid(9));
assert(!AllocationValid(-1)&&!AllocationValid(10));
assert(Authority(true,false,1,1));
assert(!Authority(false,false,1,1));
assert(!Authority(true,true,1,1));
assert(!Authority(true,false,1,2));
for(int bits=0;bits<16;bits++) {
bool callback=bits&1, source=bits&2, destination=bits&4, exact=bits&8;
assert(Proven(callback,source,destination,exact)==(bits==13));
}
int counter=0;
assert(CycleGate(true,0,counter,8,1)==0); // no physical projectile, no count
for(int i=0;i<1000;i++) if(CycleGate(true,1,counter,8,0)==1) counter++;
assert(counter==0); // pending supply never invokes native super
assert(CycleGate(true,1,counter,8,-1)==-1);
if(CycleGate(true,1,counter,8,1)==1) counter++;
assert(counter==1 && CycleGate(true,1,counter,8,1)==0); // same event not counted twice
assert(CycleGate(false,2,counter,8,1)==-1);
assert(CycleGate(true,8,7,8,-1)==1); // final confirmed round needs no ninth shell
}
''')
# Retain actual control flow; translate only native member/type syntax and the
# component lookup into a directly supplied fake item component.
poll=body(transfer,'ERR_MortarSupplyState Poll(')
poll=poll.replace('ERR_MortarSupplyState.','ERR_MortarSupplyState::').replace('Replication.IsServer()','Replication::IsServer()').replace('InventoryItemComponent item;','InventoryItemComponent* item=nullptr;').replace('if (m_Shell) item = InventoryItemComponent.Cast(m_Shell.FindComponent(InventoryItemComponent));','if (m_Shell) item = m_Shell;').replace('item.GetParentSlot().GetStorage()','item->GetParentSlot()->GetStorage()').replace('item.GetParentSlot()','item->GetParentSlot()')
ack=body(transfer,'void Acknowledge(')
run('''#include <cassert>
enum class ERR_MortarSupplyState {FAILED=-1,PENDING,READY};
struct Replication { static bool IsServer(){return true;} };
struct Slot { void* storage; void* GetStorage(){return storage;} };
struct InventoryItemComponent { Slot* slot; Slot* GetParentSlot(){return slot;} };
'''+body(transfer,'static bool Proven(')+'''
struct Transfer {
bool valid=true,source=true,destination=false,m_Accepted=true,m_Invalidated=false,m_Resolved=false,m_Ready=false;
int m_Source=1,m_Destination=2,m_Acknowledgement=0;
float m_Deadline=8000;
void* m_Storage=this;
Slot slot{this}; InventoryItemComponent item{&slot}; InventoryItemComponent* m_Shell=&item;
bool Valid(float){return valid&&!m_Invalidated;}
bool Contains(int which){return m_Shell && (which==1 ? source : destination);}
'''+ack+poll+'''
};
int main(){
using S=ERR_MortarSupplyState;
Transfer t; assert(t.Poll(0)==S::PENDING && !t.m_Resolved);
t.Acknowledge(true); t.Acknowledge(false); assert(t.m_Acknowledgement==1);
assert(t.Poll(1)==S::PENDING && !t.m_Resolved); // callback alone cannot supply
t.destination=true; assert(t.Poll(2)==S::PENDING); // source still claims ownership
t.source=false; t.slot.storage=nullptr; assert(t.Poll(3)==S::PENDING); // wrong storage
t.slot.storage=t.m_Storage; assert(t.Poll(4)==S::READY && t.m_Resolved);
Transfer stopped; stopped.m_Invalidated=true; stopped.source=false; stopped.destination=true; stopped.Acknowledge(true);
assert(stopped.Poll(5)==S::FAILED && !stopped.m_Ready && stopped.m_Resolved);
Transfer timeout; assert(timeout.Poll(8000)==S::FAILED && !timeout.m_Resolved && timeout.m_Invalidated);
timeout.source=false;timeout.destination=true;timeout.Acknowledge(true);
assert(timeout.Poll(9000)==S::FAILED && timeout.m_Resolved && !timeout.m_Ready); // late success cannot authorize
Transfer late;late.source=false;late.destination=true;late.Acknowledge(true);
assert(late.Poll(8000)==S::FAILED); // no deadline-boundary success bypass
Transfer failed;failed.Acknowledge(false);failed.Acknowledge(true);
assert(failed.Poll(1)==S::FAILED && failed.m_Acknowledgement==-1 && failed.m_Resolved);
Transfer gone;gone.m_Shell=nullptr;gone.Acknowledge(true);
assert(gone.Poll(1)==S::PENDING && !gone.m_Resolved); // ambiguous until deadline, never another move
Transfer unauthorized;unauthorized.valid=false;
assert(unauthorized.Poll(0)==S::FAILED && !unauthorized.m_Resolved);
}
''')
# Source contract checks constrain integration that cannot run without the engine.
b=battery.read_text();sys=(r/'ERR_MortarSystem.c').read_text();f=(r/'ERR_MortarFiring.c').read_text();rd=readiness.read_text();tr=transfer.read_text()
update=body(battery,'void Update(float now)')
assert update.index('m_Readiness.Poll(now)') < update.index('if (!Operational())')
assert 'm_Allocated = true;' in rd and rd.count('TrySpawnPrefabToStorage(ERR_MortarBattery.SHELL')==1
assert rd.index('m_Allocated = true;') < rd.index('TrySpawnPrefabToStorage(ERR_MortarBattery.SHELL')
assert 'm_aUnitPrefabSlots = new array<ResourceName>()' in rd and 'PurgeSpawnRequestsForGroup(group)' in rd
assert 'DeleteSpawned' not in body(readiness,'void Stop(')
assert 'battery.Stop();' in body(r/'ERR_MortarSystem.c','void Stop(')
assert tr.count('TryMoveItemToStorage(')==1 and 'GetItem()' not in tr.replace('callback.GetItem()','')
assert 'm_AttemptedShells.Insert(item)' in b and 'm_AttemptedShells.Contains(item)' in b
assert 'm_Transfer.CapturedOrder() == OrderId' in b
assert 'battery.PendingSupplyReport' in sys and 'supply == ERR_MortarSupplyState.PENDING) return;' in sys
shoot=f[f.index('modded class SCR_AIStaticArtilleryBehavior_ShootingLogic'):]
assert shoot.index('battery.SupplyState(')<shoot.index('super.EOnTaskSimulate(')
assert shoot.count('super.EOnTaskSimulate(')==1 and 'battery.SupplyGunner()' not in shoot
print('PASS: actual startup/generation/ownership/timeout/callback policies and native-counter wait; integration preserves one-shot allocation and pending-crew cancellation')
@@ -0,0 +1,52 @@
"""Native fixture's actual snapshot predicate rejects changed life/body evidence."""
from policy_harness import ROOT, body, run
p=ROOT/'addons/core/Scripts/Game/ERR/ERR_NativeLocalAdmissionProbe.c'
s=body(p,'protected bool Unchanged()').replace('protected ','').replace('ERR_Phase.PRISON','1').replace('GetGame().','GetGame()->')
for name in ['m_Mode','m_Controller','m_Life','m_Logic']:
s=s.replace(name+'.',name+'->')
s=s.replace('Players().','Players()->').replace('GetPlayerManager().','GetPlayerManager()->')
run('''#include <cassert>
using IEntity=void*;
struct UUID {int value=1; bool operator==(UUID o){return value==o.value;}};
struct Life {UUID AccountId;bool Connected=true,UsedLife=true;IEntity Actor=nullptr;};
struct Controller {IEntity actor=nullptr;IEntity GetControlledEntity(){return actor;}};
struct Roster {Life* life=nullptr;Life* current=nullptr;bool canEnter=false;Life* Get(int){return life;}Life* CurrentActor(IEntity){return current;}bool CanEnter(int,int){return canEnter;}};
struct Mode {Roster roster;Roster* Players(){return &roster;}};
struct Manager {Controller* controller=nullptr;Controller* GetPlayerController(int){return controller;}};
struct Game {Manager manager;Manager* GetPlayerManager(){return &manager;}};Game game;Game* GetGame(){return &game;}
struct Logic {bool idle=true;bool ERR_LocalProbeIdle(int){return idle;}};
struct Probe {
Mode mode;Life life,other;Controller controller;Logic logic;int actor=0;
Mode* m_Mode=&mode;Life* m_Life=&life;Controller* m_Controller=&controller;Logic* m_Logic=&logic;IEntity m_Actor=&actor;
UUID m_Key;int m_Connection=1,m_Participants=1,participants=1;
Probe(){life.Actor=m_Actor;controller.actor=m_Actor;mode.roster.life=&life;mode.roster.current=&life;game.manager.controller=&controller;}
int Participants(){return participants;}
'''+s+'''};
int main(){
Probe baseline;assert(baseline.Unchanged());
for(int fault=0;fault<13;++fault){
Probe p;
if(fault==0)p.m_Controller=nullptr;
if(fault==1)p.m_Actor=nullptr;
if(fault==2)p.m_Life=nullptr;
if(fault==3)p.mode.roster.life=&p.other;
if(fault==4)p.mode.roster.current=nullptr;
if(fault==5)p.life.AccountId.value=2;
if(fault==6)p.life.Connected=false;
if(fault==7)p.life.UsedLife=false;
if(fault==8)p.life.Actor=nullptr;
if(fault==9)p.controller.actor=nullptr;
if(fault==10)game.manager.controller=nullptr;
if(fault==11)p.participants=2;
if(fault==12)p.logic.idle=false;
assert(!p.Unchanged());
}
Probe spent;spent.mode.roster.canEnter=true;assert(!spent.Unchanged());
}
''')
source=p.read_text()
assert source.startswith('#ifdef WORKBENCH')
assert 'UUID.GenV4' not in source and 'OnPlayerDisconnected_S(' not in source
assert 'm_Logic.OnPlayerAuditSuccess_S(m_Connection);' in source
assert 'm_Logic.ERR_LocalProbeRefuseController(m_Connection)' in source
print('PASS: native local-admission snapshot rejects changed life/key/body/participant/pending state; authentication is not simulated')
+81
View File
@@ -0,0 +1,81 @@
"""Execute actual fixture commit/event/closure gates; not native artillery simulation."""
from policy_harness import ROOT, body, run
p=ROOT/'addons/ai/Scripts/Game/ERR/ERR_NativeMortarFiringProbe.c'
policies='\n'.join(body(p, sig) for sig in ['static bool CommitFresh(', 'static bool EventBound(', 'static bool ExpiredClosure('])
policies=policies.replace('ERR_MortarPrediction.', 'ERR_MortarPrediction::').replace('string failure', 'Text failure')
methods='\n'.join(body(p,sig) for sig in ['void NativeCommit(', 'void NativeClosing(', 'void NativeProjectile('])
methods=methods.replace('ERR_MortarBattery battery','Battery* battery').replace('IEntity gun, IEntity projectile','Entity* gun, Entity* projectile').replace('string reason, string failure','Text reason, Text failure')
methods=methods.replace('m_Battery.', 'm_Battery->').replace('battery.', 'battery->').replace('Report.', 'Report->').replace('projectile.GetOrigin()', 'projectile->GetOrigin()')
methods=methods.replace('GetGame().GetWorld().GetWorldTime()', 'clockNow').replace('ERR_NativeMortarEvidenceRules.', 'ERR_NativeMortarEvidenceRules::').replace('ERR_MortarSalvo.', 'ERR_MortarSalvo::')
run('''#include <cassert>
#include <vector>
#include <algorithm>
#include <string>
float clockNow=20000;
struct Text:std::string {using std::string::string;bool Contains(const char* part){return find(part)!=npos;}};
struct ERR_MortarPrediction {static constexpr float MAX_REPORT_AGE_MS=60000;};
struct ERR_MortarSalvo {static constexpr int ROUNDS=8;};
struct ERR_NativeMortarEvidenceRules {
'''+policies+'''};
struct Entity {int GetOrigin(){return 0;}};
struct Report {int MessageId=7;float ObservedAt=1000;};
struct Battery {bool CommandOpen=true,Released=true,stopped=false;int SourceId=7,OrderId=1,OrderShots=0;float AimedAt=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 {
bool m_Stopped=false,m_BadProjectile=false,m_WaitForExpiry=true,m_CommitPending=false,m_ClosureSeen=false,m_ClosureComplete=false,m_ClosureExpired=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;
'''+methods+'''
};
int main(){
using Rules=ERR_NativeMortarEvidenceRules;
assert(Rules::EventBound(true,1,1,0,0,60999,90000)); // original fresh commit survives delayed native emission
assert(Rules::CommitFresh(1000,1000,61000));assert(!Rules::CommitFresh(1000,1000,61001));
assert(!Rules::CommitFresh(1100,1000,20000));assert(!Rules::CommitFresh(1000,1000,999));
assert(Rules::ExpiredClosure(1000,61001,"aim: delivered target report expired or invalid"));
assert(!Rules::ExpiredClosure(1000,61000,"aim: delivered target report expired or invalid"));
assert(!Rules::ExpiredClosure(1000,65000,"native artillery activity FAILED"));
Entity gun,other,projectile;Battery b;Probe p;p.m_Battery=&b;p.m_Gun=&gun;
p.NativeProjectile(&other,&projectile);assert(!p.m_BadProjectile&&p.m_Events==0);
p.NativeCommit(&b,clockNow);assert(p.m_CommitPending&&p.m_Commits==1&&!p.m_BadProjectile);
p.NativeProjectile(&gun,&projectile);assert(p.m_Events==1&&!p.m_BadProjectile&&!p.m_CommitPending);
p.NativeProjectile(&gun,&projectile);assert(p.m_BadProjectile&&p.m_Events==1);
Probe nullEvent;nullEvent.m_Battery=&b;nullEvent.m_Gun=&gun;nullEvent.NativeProjectile(&gun,nullptr);assert(nullEvent.m_BadProjectile&&nullEvent.m_Events==0);
Probe stoppedObserver;stoppedObserver.m_Battery=&b;stoppedObserver.m_Gun=&gun;stoppedObserver.m_Stopped=true;stoppedObserver.NativeCommit(&b,20000);stoppedObserver.NativeProjectile(&gun,&projectile);assert(stoppedObserver.m_Commits==0&&stoppedObserver.m_Events==0&&!stoppedObserver.m_BadProjectile);
// Physical launch after report expiry is legitimate if its commit was fresh.
b=Battery();b.Report=&b.report;b.AimedAt=60500;Probe delayed;delayed.m_Battery=&b;delayed.m_Gun=&gun;delayed.m_Step=3;
delayed.NativeCommit(&b,60999);clockNow=62999;delayed.NativeProjectile(&gun,&projectile);
assert(delayed.m_Events==1&&!delayed.m_BadProjectile);
for(int fault=0;fault<10;++fault){
b=Battery();b.Report=&b.report;clockNow=20000;Probe q;q.m_Battery=&b;q.m_Gun=&gun;
if(fault==0)b.CommandOpen=false;
if(fault==1)b.Released=false;
if(fault==2)b.SourceId=8;
if(fault==3)b.AimedAt=-1;
if(fault==4)b.AimedAt=9999;
if(fault==5)b.FlightTime=0;
if(fault==6)q.m_Step=2;
if(fault==7)b.report.ObservedAt=1001;
if(fault==8)b.OrderId=2;
if(fault==9){clockNow=61001;b.AimedAt=61000;}
q.NativeCommit(&b,clockNow);assert(q.m_BadProjectile&&!q.m_CommitPending&&q.m_Commits==0);
}
b=Battery();b.Report=&b.report;clockNow=20000;Probe missing;missing.m_Battery=&b;missing.m_Gun=&gun;
missing.NativeProjectile(&gun,&projectile);assert(missing.m_BadProjectile);
Probe duplicate;duplicate.m_Battery=&b;duplicate.m_Gun=&gun;duplicate.NativeCommit(&b,20000);duplicate.NativeCommit(&b,20000);assert(duplicate.m_BadProjectile&&duplicate.m_Commits==1);
for(int fault=0;fault<3;++fault){
b=Battery();b.Report=&b.report;clockNow=20000;Probe changed;changed.m_Battery=&b;changed.m_Gun=&gun;changed.NativeCommit(&b,20000);
if(fault==0)b.OrderId++;
if(fault==1)b.OrderShots++;
if(fault==2)clockNow=19999;
changed.NativeProjectile(&gun,&projectile);assert(changed.m_BadProjectile);
}
b=Battery();b.Report=&b.report;clockNow=65000;Probe expired;expired.m_Battery=&b;expired.m_Gun=&gun;
expired.NativeClosing(&b,"native aim or firing authorization rejected","aim: delivered target report expired or invalid");assert(expired.m_ClosureSeen&&expired.m_ClosureExpired&&!expired.m_BadProjectile);
Probe unrelated;unrelated.m_Battery=&b;unrelated.NativeClosing(&b,"native activity FAILED","");assert(unrelated.m_BadProjectile);
Probe stopped;stopped.m_Battery=&b;b.stopped=true;stopped.NativeClosing(&b,"HQ stopped","aim: delivered target report expired or invalid");assert(stopped.m_BadProjectile);
b.stopped=false;b.OrderShots=8;Probe complete;complete.m_Battery=&b;complete.m_Events=8;clockNow=50000;complete.NativeClosing(&b,"native artillery activity COMPLETED","");assert(complete.m_ClosureComplete&&!complete.m_BadProjectile);
}
''')
print('PASS: actual probe binds native events to fresh immutable commits, permits delayed emission, rejects unrelated expiry closure and premature stop')
+84
View File
@@ -0,0 +1,84 @@
"""Source policy and actual fixture completion checks; not an engine test."""
from pathlib import Path
import unittest
from policy_harness import body, run
ROOT = Path(__file__).resolve().parents[1]
SOURCE = ROOT/'addons/ai/Scripts/Game/ERR/ERR_NativeMortarTransferProbe.c'
class NativeMortarTransferChecks(unittest.TestCase):
def test_original_identity_conservation_policy(self):
method = body(SOURCE, 'static bool Conservation(')
run(method + '''
#include <cassert>
int main() {
for(int original=0;original<30;original++) for(int actual=0;actual<30;actual++)
for(int all=0;all<2;all++) for(int unique=0;unique<2;unique++)
assert(Conservation(original,actual,all,unique)==(original==27 && actual==27 && all && unique));
}
''')
def test_actual_move_completion_requires_callback_slot_and_deadline(self):
method=body(SOURCE, 'protected int MoveResult(').replace('protected int','int').replace('InventoryItemComponent item;', 'InventoryItemComponent* item;').replace('InventoryItemComponent item =', 'InventoryItemComponent* item =').replace('InventoryItemComponent.Cast','InventoryItemComponent::Cast').replace('FindComponent(InventoryItemComponent)','FindComponent(0)').replace('null','nullptr')
for name in ('m_MoveCallback','m_MoveShell','m_MoveDestination','item'):
method=method.replace(name+'.',name+'->')
method=method.replace('GetParentSlot().', 'GetParentSlot()->')
run('''
#include <cassert>
struct Entity;
struct Storage { bool has=false; bool Contains(Entity*) { return has; } };
struct Slot { Storage* storage=nullptr; Storage* GetStorage() { return storage; } };
struct InventoryItemComponent {
Slot* slot=nullptr;
static InventoryItemComponent* Cast(InventoryItemComponent* x) { return x; }
Slot* GetParentSlot() { return slot; }
};
struct Entity { InventoryItemComponent* item=nullptr; InventoryItemComponent* FindComponent(int) { return item; } };
struct Callback { int Result=0; };
struct Probe {
Callback* m_MoveCallback=nullptr; Entity* m_MoveShell=nullptr;
Storage* m_MoveDestination=nullptr; float m_MoveDeadline=100;
''' + method + '''
};
int main() {
Probe p; Callback cb; Entity shell; Storage target,wrong; Slot slot; InventoryItemComponent item;
p.m_MoveCallback=&cb; p.m_MoveShell=&shell; p.m_MoveDestination=&target;
assert(p.MoveResult(99)==0); // acceptance alone is not completion
cb.Result=1; assert(p.MoveResult(99)==0); // callback alone is insufficient
target.has=true; assert(p.MoveResult(99)==0); // exact item metadata required
shell.item=&item; item.slot=&slot; slot.storage=&wrong;
assert(p.MoveResult(99)==0); // apparent membership in wrong storage is insufficient
slot.storage=&target; assert(p.MoveResult(100)==-1); // bounded deadline
assert(p.m_MoveCallback==&cb); // failure retains pending operation and borrowed shell
cb.Result=-1; assert(p.MoveResult(99)==-1);
cb.Result=1; assert(p.MoveResult(99)==1);
assert(!p.m_MoveCallback && !p.m_MoveShell && !p.m_MoveDestination);
assert(p.MoveResult(99)==1); // completion cannot replay an inventory operation
}
''')
def test_no_shell_creation_or_mutation_and_safe_cleanup(self):
source=SOURCE.read_text()
self.assertEqual(source.count('ERR_Actors.Spawn('),1)
self.assertIn('ERR_Actors.Spawn(STORE,',source)
for forbidden in ('TrySpawnPrefab', 'SetHealth(', 'ForceUnconsciousness', 'DeleteRplEntity', 'TotalShots++', 'LoadMagazine', 'GetShootingLogic'):
self.assertNotIn(forbidden,source)
self.assertNotRegex(source,r'TotalShots\s*=(?!=)')
stop=body(SOURCE,'void Stop()')
self.assertIn('if (!m_MoveCallback)',stop)
self.assertIn('storage && items.IsEmpty()',stop)
self.assertIn('m_System.Stop()',stop)
self.assertEqual(source.count('ERR_Actors.DeleteSpawned('),1)
def test_scoped_hook_cancel_and_exact_request_capture(self):
source=SOURCE.read_text()
self.assertTrue(source.startswith('#ifdef WORKBENCH'))
self.assertIn('outcome == "mortar-transfer"',source)
self.assertIn('if (m_ERRTransferFixture) return;',source)
self.assertIn('super.Tick(now);',source)
self.assertIn('m_CallbackAtCancel = m_ObservedTransfer.ERR_CallbackState()',source)
self.assertIn('m_ObservedTransfer.CapturedOrder() == m_Battery.OrderId',source)
self.assertIn('m_Battery.OrderId != m_CancelOrder',source)
self.assertIn('m_Battery.ERR_TransferAttempts() != m_AttemptsAtStart + 2',source)
self.assertIn('late callback timing not exercised',source)
self.assertIn('Has(entry.OriginalOwner, entry.Shell)',source)
self.assertEqual(body(SOURCE,'protected bool BeginMove(').count('TryMoveItemToStorage('),1)
self.assertIn('return BeginMove(shell, storage, now)',body(SOURCE,'protected bool Stash('))
if __name__=='__main__': unittest.main()
+63
View File
@@ -0,0 +1,63 @@
"""Run actual extracted fixture rules; no native flight or Enforce claims."""
from pathlib import Path
import unittest
from policy_harness import body, run
SOURCE=Path(__file__).resolve().parents[1]/'addons/core/Scripts/Game/ERR/ERR_NativePoweredFlightProbe.c'
class PoweredFlightPolicy(unittest.TestCase):
def test_actual_authority_all_inputs(self):
method=body(SOURCE,'static bool Authority(')
run('#include <cassert>\n'+method+'''
int main(){for(int mask=0;mask<256;mask++) {
bool server=mask&1, enabled=mask&2, stopped=mask&4, pilot=mask&8, seat=mask&16, player=mask&32, alive=mask&64, fuel=mask&128;
assert(Authority(server,enabled,stopped,pilot,seat,player,alive,fuel)==(server&&enabled&&!stopped&&pilot&&seat&&!player&&alive&&fuel));
}}
''')
def test_actual_hover_landing_and_bounded_input_rules(self):
methods='\n'.join(body(SOURCE,key).replace('Math.','Math::') for key in ['static float ClampInput(', 'static float DesiredVertical(', 'static bool Hover(', 'static bool Landed('])
run('''
#include <cassert>
#include <cmath>
#include <algorithm>
struct Math { static float Clamp(float x,float low,float high){return std::clamp(x,low,high);} static float AbsFloat(float x){return std::abs(x);} };
'''+methods+'''
int main(){
assert(ClampInput(3)==1 && ClampInput(-3)==-1);
assert(ClampInput(0.8f,0.15f)==0.15f);
assert(DesiredVertical(0,false)==1.5f && DesiredVertical(8,false)==0);
assert(DesiredVertical(8,true)==-0.8f && DesiredVertical(0,true)==0);
assert(Hover(8,0.2f,0.1f,1,1));
assert(!Hover(0,0,0,1,0) && !Hover(11,0,0,1,0));
assert(!Hover(8,2,0,1,0) && !Hover(8,0,0.6f,1,0));
assert(!Hover(8,0,0,0.9f,0) && !Hover(8,0,0,1,9));
assert(Landed(true,0.1f,0.1f,0.01f,1));
assert(!Landed(false,0,0,0,1)); // low stationary hover is never landing
assert(!Landed(true,2,0,0,1) && !Landed(true,0,1,0,1));
assert(!Landed(true,0,0,0.2f,1) && !Landed(true,0,0,0,0.8f));
}
''')
def test_native_input_only_and_local_hooks(self):
source=SOURCE.read_text()
for forbidden in ('SetVelocity(', 'SetAngularVelocity(', 'SetWorldTransform(', 'SetOrigin(', 'SetAngles(', '.Teleport(', 'ForceStartEngine(', '.EngineStart(', 'RotorSetForce', 'RotorSetTorque', 'SetHealth(', 'SetFuel(', 'SetGlobalFuelConsumptionScale', 'GetInputManager('):
self.assertNotIn(forbidden,source)
self.assertTrue(source.startswith('#ifdef WORKBENCH'))
self.assertIn('outcome == "powered-flight"',source)
self.assertIn('controller != m_Character || owner != m_Pilot',source)
self.assertIn('controller != m_Controller',source)
self.assertIn('super.OnPrepareControls(owner, am, dt, player)',source)
self.assertEqual(source.count('.StartEngine()'),1)
self.assertEqual(source.count('physics.SetActive('),1)
self.assertIn('m_Wakes == 0',source)
for control in ('Collective','CyclicForward','CyclicAside','AntiTorque'):
self.assertIn('m_Input.SetVehicle'+control+'(',source)
self.assertIn('m_Input.GetVehicle'+control+'()',source)
def test_stop_and_engine_shutdown_are_bounded(self):
source=SOURCE.read_text();stop=body(SOURCE,'void Stop()')
self.assertIn('OwnPilot() && !PlayerPresent()',stop)
self.assertIn('s_Current = null',stop)
self.assertNotIn('StopEngine',stop) # no engine kill on midair fail/capture
self.assertNotIn('DeleteSpawned',stop)
self.assertIn('m_Stage >= 4 && m_Stage <= 6 && !m_Controller.IsEngineOn()',source)
self.assertIn('m_Fuel.GetTotalFuel() < m_InitialFuel - 0.05',source)
self.assertIn('m_Controller.StopEngine(false)',source)
self.assertIn('ERR_PoweredFlightRules.Landed(m_Simulation.HasAnyGroundContact()',source)
if __name__=='__main__': unittest.main()