Capture current mission, AI, map and administration development

Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
This commit is contained in:
2026-10-13 22:52:53 +02:00
parent a951a96edc
commit 6a667d8deb
8104 changed files with 2124945 additions and 2061 deletions
@@ -0,0 +1,45 @@
--- a/addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c
+++ b/addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c
@@ -1,5 +1,21 @@
// Explicit, local Workbench diagnostic only. Never compiled into game/server builds.
#ifdef WORKBENCH
+modded class ERR_HQ
+{
+ bool ERR_IsolateMountedBMP()
+ {
+ string bmp;
+ if (!ERR_NativeMountedAmmoProbe.Enabled() || !System.GetCLIParam("errMountedBMP", bmp) || bmp != "1"
+ || !m_Mode || m_Mode != ERR_GameMode.Get() || m_Mode.StartMode() != 0 || m_Mode.Phase() != ERR_Phase.PRISON
+ || !m_Hunters || m_Hunters.Deployed() != 0 || !m_Towns) return false;
+ // Neither service ticks in PRISON. Town creation is synchronous; there are
+ // no queued town soldiers to cancel or existing populations to refund here.
+ m_Hunters.Stop();
+ m_Towns.Stop();
+ return true;
+ }
+}
+
modded class ERR_GameMode
{
// Read-only normal-route stock witness; no courier, movement or arming action.
@@ -838,6 +854,20 @@
}
if (m_ERRTestMountedAmmo)
{
+ string mountedBMP;
+ if (System.GetCLIParam("errMountedBMP", mountedBMP) && mountedBMP == "1")
+ {
+ string bmpMines, bmpSwap, bmpCourier;
+ bool mixedBMP = (System.GetCLIParam("errMineStock", bmpMines) && bmpMines == "1")
+ || (System.GetCLIParam("errMountedSwapEligibility", bmpSwap) && bmpSwap == "1")
+ || (System.GetCLIParam("errMountedCourier", bmpCourier) && bmpCourier == "1");
+ if (!ERR_Check(!mixedBMP && StartMode() == 0 && Phase() == ERR_Phase.PRISON,
+ "BMP accounting isolation requires prison start and no mine/swap/courier variants")) return;
+ ERR_HQ bmpHQ = ERR_HQ.Get();
+ if (!ERR_Check(bmpHQ && bmpHQ.ERR_IsolateMountedBMP(),
+ "BMP accounting isolation precedes opening hunter and town admissions")) return;
+ Print("ERR BMP FIXTURE: opening hunters and new town admissions stopped before prison escape; original site troops, automatic convoy target, body cap, stock and proof deadline unchanged");
+ }
// Protect only this diagnostic observer while normal enemy forces continue.
DamageManagerComponent mountedObserverDamage = DamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(DamageManagerComponent));
if (!ERR_Check(mountedObserverDamage != null, "mounted observer has native damage component")) return;
@@ -0,0 +1,10 @@
{
"files": {
"addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c": {
"baseline_sha256": "e2a32dbe372edc2f5cd03a55dcb3dd11689ad8b60940a7a318b0c829d464d3e2",
"proposal_sha256": "b7e1857b0678b3a2c71880c0f35b09da9e978f19bacf5b4e7449c893fdbe2b95"
}
},
"patch_sha256": "792b3670fda0aaadbb09bbf23a7a34981129e93302372cbbea512467fb601c19",
"scope": "WORKBENCH mounted-ammo+errMountedBMP fixture only. Before initial prison exit, stop unstarted hunters/town admissions. No actors deleted/refunded, settings/caps/targets/deadlines unchanged. No tests/compiler/native run."
}
@@ -0,0 +1,34 @@
/tmp/err-policy-iqjo2mvy/check.cpp:11:33: error: declaration of ‘Entity* ERR_ConvoyVehicle::Entity’ changes meaning of ‘Entity’ [-Wchanges-meaning]
11 | struct ERR_ConvoyVehicle{Entity*Entity=nullptr;bool Registered=true;int Group=1;};
| ^~~~~~
/tmp/err-policy-iqjo2mvy/check.cpp:11:26: note: used here to mean ‘struct Entity’
11 | struct ERR_ConvoyVehicle{Entity*Entity=nullptr;bool Registered=true;int Group=1;};
| ^~~~~~
/tmp/err-policy-iqjo2mvy/check.cpp:7:8: note: declared here
7 | struct Entity{Prefab prefab;Prefab*GetPrefabData(){return &prefab;}};
| ^~~~~~
/tmp/err-policy-iqjo2mvy/check.cpp: In member function ‘void Probe::Capture(ERR_HQ*, ERR_ConvoyVehicle*, float)’:
/tmp/err-policy-iqjo2mvy/check.cpp:41:76: error: comparison of integer expressions of different signedness: ‘int’ and ‘std::vector<int>::size_type’ {aka ‘long unsigned int’} [-Werror=sign-compare]
41 | && unit->Uplink->MessageId == report->MessageId && unit->Uplink->Cursor < unit->Uplink->Nodes.size(), "original mounted payload observed before real radio delivery")) return;
| ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors
PASS: actual bounded native mounted proof/detached payload/deadline/cleanup methods, production-only setup and isolated runner selector
PASS: actual one-existing-convoy candidate readiness, sender-root identity, incomplete cargo refusal and fixed three-candidate bound
Traceback (most recent call last):
File "/tmp/erri-mounted-bmp-probe/tests/test_native_mounted_ammo_probe.py", line 172, in <module>
run(r'''
~~~^^^^^
#include <cassert>
^^^^^^^^^^^^^^^^^^
...<33 lines>...
}
^
'''.replace(';if(', ';\n if('))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 13, in run
subprocess.run(['g++','-std=c++17','-Wall','-Werror',str(p/'check.cpp'),'-o',str(p/'check')],check=True)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/subprocess.py", line 578, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['g++', '-std=c++17', '-Wall', '-Werror', '/tmp/err-policy-iqjo2mvy/check.cpp', '-o', '/tmp/err-policy-iqjo2mvy/check']' returned non-zero exit status 1.
@@ -0,0 +1,19 @@
check: /tmp/err-policy-oooz7m9i/check.cpp:115: int main(): Assertion `s.p.captures==3' failed.
Traceback (most recent call last):
File "/tmp/erri-mounted-bmp-probe/tests/test_native_mounted_ammo_probe.py", line 40, in <module>
run(r'''
~~~^^^^^
#include <cassert>
^^^^^^^^^^^^^^^^^^
...<64 lines>...
}
^
'''.replace(';if(', ';\n if('))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 14, in run
subprocess.run([str(p/'check')],check=True)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/subprocess.py", line 578, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/tmp/err-policy-oooz7m9i/check']' died with <Signals.SIGABRT: 6>.
@@ -0,0 +1,8 @@
{
"finding": "Existing mounted witness allowed BMP Complete=false if Valid and could prove natural radio delivery from a UAZ. Thus it did not qualify the exact WCS BMP controls exclusion. No production defect demonstrated.",
"fix": "Opt-in --mounted-bmp restricted to Chat mounted-ammo one round at least360s without mine/swap/courier. Capture only task slot4, exact BMP prefab plus Complete/Valid/nonzero armed snapshot. Fleet retains all6 roots and existing cargo proof, requires same BMP completeness; final delivered detached-copy proof retains exact slot4 vehicle/root/crew and queued snapshot. Interrupted reports may retry naturally on same proof task without deadline reset.",
"unchanged": "Default target3, body budget/admission,180s fixed proof deadline, cargo/roster/freshness/copy checks, default mounted/swap/courier/mine behavior, production sampler/report/order logic. Hegel separate hook explicitly isolates unrelated hunter/town admissions before canonical prison unlock.",
"test_boundaries": "Actual Capture/BMPReady/Tick/Candidate/Forget/Stop and hook isolation methods executed. Native inventory, reporter/roster identity and snapshot Valid are explicit doubles; actual sampler has existing separate tests. Fleet source condition preserved/reviewed, not full native Fleet execution in this harness. Baseline compiles then fails first slot-only capture assertion. Removing Complete guard compiles then fails actual Capture incomplete rejection.",
"native_qualification": "Pending parent native run. No firing, consumption, reload, stock transfer, autonomous interception or physical travel proof claimed.",
"compilers_finished": true
}
@@ -0,0 +1,283 @@
--- a/addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeMountedAmmoProbe.c
+++ b/addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeMountedAmmoProbe.c
@@ -35,6 +35,8 @@
protected bool m_FleetReady;
protected bool m_SwapEligibility;
protected bool m_MineStock;
+ protected bool m_BMP;
+ protected ref ERR_ConvoyVehicle m_BMPVehicle;
protected bool m_MountedDiagnosticPrinted;
protected ref ERR_ConvoyMineStock m_MineBatch;
protected ref ERR_ConvoyVehicle m_MineTruck;
@@ -58,11 +60,14 @@
void ERR_NativeMountedAmmoProbe(ERR_GameMode mode, float now)
{
m_Mode = mode; m_Deadline = now + 180000;
- string swap, mines, courier;
+ string swap, mines, courier, bmp;
+ m_BMP = System.GetCLIParam("errMountedBMP", bmp) && bmp == "1";
m_MineStock = System.GetCLIParam("errMineStock", mines) && mines == "1";
m_SwapEligibility = System.GetCLIParam("errMountedSwapEligibility", swap) && swap == "1";
if (m_MineStock && (m_SwapEligibility || (System.GetCLIParam("errMountedCourier", courier) && courier == "1")))
Check(false, "mine-stock proof requires the normal mounted radio path, without swap or courier flags");
+ if (m_BMP && (m_MineStock || m_SwapEligibility || (System.GetCLIParam("errMountedCourier", courier) && courier == "1")))
+ Check(false, "BMP proof requires the normal mounted radio path, without mine, swap or courier flags");
if (m_SwapEligibility) m_SwapProbe = new ERR_NativeMountedSwapProbe();
}
bool SwapEligibility() { return m_SwapEligibility; }
@@ -100,6 +105,13 @@
}
return !vehicle.Members.IsEmpty();
}
+ protected bool BMPReady(ERR_ConvoyVehicle vehicle, ERR_HQMountedAmmoSnapshot sample)
+ {
+ return vehicle && vehicle.Entity && vehicle.Entity.GetPrefabData()
+ && vehicle.Entity.GetPrefabData().GetPrefabName() == ERR_ConvoyResources.VehiclePrefab(4)
+ && sample && sample.Valid() && sample.Complete && sample.Weapons > 0 && sample.Magazines > 0
+ && sample.Rounds + sample.Chambers > 0;
+ }
protected void Capture(ERR_HQ hq, ERR_ConvoyVehicle vehicle, float now)
{
if (m_Queued || !vehicle || !vehicle.Registered) return;
@@ -107,10 +119,12 @@
if (!Original(vehicle, unit) || !unit.PendingStatus || !unit.Uplink) return;
ERR_HQStatusReport report = unit.PendingStatus;
if (!report.MountedAmmo || report.MountedAmmo.Weapons < 1 || report.MountedAmmo.Magazines < 1) return;
+ if (m_BMP && !BMPReady(vehicle, report.MountedAmmo)) return;
ERR_HQWatchEntry before = hq.Watch().Find(report.SourceId);
if (before && before.MessageId >= report.MessageId) return;
if (!Check(ERR_HQWatchRules.Valid(report, now) && report.SourceId == unit.StatusSampler.InitialSourceId()
&& unit.Uplink.MessageId == report.MessageId && unit.Uplink.Cursor < unit.Uplink.Nodes.Count(), "original mounted payload observed before real radio delivery")) return;
+ if (m_BMP) m_BMPVehicle = vehicle;
m_Unit = unit; m_Root = vehicle.Entity; m_Queued = report;
m_Payload = report.MountedAmmo.Snapshot(); m_Route = unit.Uplink; m_RoutePayload = m_Route.Payload;
Check(m_Payload != report.MountedAmmo && Same(m_Payload, report.MountedAmmo)
@@ -208,7 +222,7 @@
{
ERR_ConvoyVehicle vehicle = task.Vehicles[slot];
if (!Check(vehicle && Original(vehicle, hq.ERR_MountedFixtureUnit(vehicle.Group)), "root retains original admitted seated crew and ledger")) return false;
- bool diagnose = m_MineStock && slot == 1 && !m_MountedDiagnosticPrinted;
+ bool diagnose = ((m_MineStock && slot == 1) || (m_BMP && slot == 4)) && !m_MountedDiagnosticPrinted;
if (diagnose) ERR_HQMountedAmmoSampler.BeginDiagnostic();
ERR_HQMountedAmmoSnapshot sample = ERR_HQMountedAmmoSampler.Inspect(vehicle.Entity);
if (diagnose)
@@ -225,6 +239,7 @@
if (!Check(sample && sample.Valid(), "native root returns bounded valid snapshot")) return false;
PrintFormat("ERR MOUNTED SAMPLE: source=%1 slot=%2 complete=%3 weapons=%4 muzzles=%5 magazines=%6", task.Receipt.SourceId, slot, sample.Complete, sample.Weapons, sample.Muzzles, sample.Magazines);
PrintFormat("ERR MOUNTED COUNTS: slot=%1 rounds=%2 capacity=%3 chambers=%4 low=%5", slot, sample.Rounds, sample.Capacity, sample.Chambers, sample.LowMagazines);
+ if (m_BMP && slot == 4 && !Check(BMPReady(vehicle, sample), "original slot4 BMP has complete valid armed mounted counts")) return false;
if (sample.Weapons > 0 && sample.Magazines > 0) armed = true;
if (slot == 1)
{
@@ -277,7 +292,11 @@
{
ERR_ConvoyTask task = hq.Convoys().At(convoy);
if (!task || (m_ProofTask && task != m_ProofTask)) continue;
- for (int slot = 0; slot < task.Vehicles.Count() && slot < 6; slot++) Capture(hq, task.Vehicles[slot], now);
+ for (int slot = 0; slot < task.Vehicles.Count() && slot < 6; slot++)
+ {
+ if (m_BMP && slot != 4) continue;
+ Capture(hq, task.Vehicles[slot], now);
+ }
}
if (!m_FleetReady) m_FleetReady = Fleet(hq);
if (m_Failed) return -1;
@@ -301,6 +320,10 @@
&& delivered.Fit == m_Queued.Fit && m_Route.MessageId == m_Queued.MessageId
&& m_Route.Payload == m_RoutePayload, "delivered observation age, roster counts and radio payload preserved")) return -1;
if (!Check(hq.ERR_MountedFixtureUnit(m_Unit.Group) == m_Unit && ERR_Actors.Alive(m_Root), "original source and root retained through delivery")) return -1;
+ if (m_BMP && !Check(m_ProofTask && m_ProofTask.Vehicles.Count() == 6
+ && m_BMPVehicle && m_ProofTask.Vehicles[4] == m_BMPVehicle && m_BMPVehicle.Entity == m_Root
+ && Original(m_BMPVehicle, m_Unit) && BMPReady(m_BMPVehicle, m_Payload),
+ "same original slot4 BMP and complete armed queued snapshot retained through actual radio delivery")) return -1;
if (!Mines(m_ProofTask, false)) return -1;
return 1;
}
@@ -309,7 +332,7 @@
if (hq.SupplyConvoys().Target() == 3 && hq.Convoys().Count() <= 3) return true;
return Check(false, "unchanged default three-convoy production target");
}
- protected void Forget() { m_Unit = null; m_Root = null; m_Queued = null; m_Payload = null; m_Route = null; m_RoutePayload = string.Empty; }
+ protected void Forget() { m_BMPVehicle = null; m_Unit = null; m_Root = null; m_Queued = null; m_Payload = null; m_Route = null; m_RoutePayload = string.Empty; }
void Stop()
{
m_Stopped = true; if (m_SwapProbe) m_SwapProbe.Stop();
--- a/tools/headless_workbench.py
+++ b/tools/headless_workbench.py
@@ -18,6 +18,7 @@
p.add_argument('--trace-random-radius', action='store_true', help='Workbench-only read-only zero-radius caller traces; one normal Chat round, capped at sixteen records')
p.add_argument('--maintenance-refuel', action='store_true', help='Opt-in normal-route check: original held Southern fuel can transfers finite fuel through its native UAZ action; one arranged tank depletion, no stock creation')
p.add_argument('--mounted-swap-eligibility', action='store_true', help='Read-only mounted-ammo variant: one exact finite cargo/mounted magazine CanSwap call; no transfer or radio proof')
+p.add_argument('--mounted-bmp', action='store_true', help='Read-only original BMP slot4 complete mounted counts and its natural HQ radio delivery; isolates unrelated opening hunters before unlock')
p.add_argument('--mine-stock', action='store_true', help='Read-only mounted-ammo check of exact callback-proved finite PMN4 cargo before and after natural radio delivery')
p.add_argument('--mounted-courier', action='store_true', help='Mounted-ammo variant: intentionally deplete one original installed magazine, then require natural HQ radio, finite pickup, native exchange and original-seat return')
p.add_argument('--mounted-intercept', action='store_true', help='After convoy driving, two synthetic witness samples exercise real HQ radio/planning and original escort detour/hold/expiry/resume')
@@ -71,6 +72,7 @@
if a.smoke == 'supply-convoys' and (a.project != 'chat' or a.rounds != 1 or a.timeout < 900): p.error('supply-convoys requires Chat, one round, and at least900 seconds')
if a.smoke == 'alarm-hearing' and (a.project != 'chat' or a.rounds != 1 or a.timeout < 360): p.error('alarm-hearing requires Chat, exactly one round, and timeout at least360 seconds')
if a.smoke == 'mounted-ammo' and (a.project != 'chat' or a.rounds != 1 or a.timeout < 360): p.error('mounted-ammo requires Chat, exactly one round, and timeout at least360 seconds')
+if a.mounted_bmp and (a.smoke != 'mounted-ammo' or a.project != 'chat' or a.rounds != 1 or a.timeout < 360 or a.mine_stock or a.mounted_courier or a.mounted_swap_eligibility): p.error('--mounted-bmp requires Chat mounted-ammo, one round, timeout at least360 seconds, without mine/courier/swap flags')
if a.smoke == 'convoy' and (a.project != 'chat' or a.rounds != 1 or a.timeout < 600): p.error('convoy requires Chat, exactly one round, and timeout at least600 seconds')
if a.smoke == 'infantry-transfer' and (a.project != 'chat' or a.rounds != 1 or a.timeout < 360): p.error('infantry-transfer requires Chat, one round and timeout at least360 seconds')
if a.smoke == 'hq-local-handoff' and (a.project != 'chat' or a.rounds != 1 or a.timeout < 360): p.error('hq-local-handoff requires Chat, one round and timeout at least360 seconds')
@@ -137,6 +139,7 @@
if a.mounted_intercept: command += ['-errMountedIntercept', '1']
if a.mounted_swap_eligibility: command += ['-errMountedSwapEligibility', '1']
if a.mounted_courier: command += ['-errMountedCourier', '1']
+if a.mounted_bmp: command += ['-errMountedBMP', '1']
if a.mine_stock: command += ['-errMineStock', '1']
if a.maintenance_refuel: command += ['-errMaintenanceRefuel', '1']
if a.trace_random_radius: command += ['-errTraceRandomRadius', '1']
--- a/tests/test_native_mounted_ammo_probe.py
+++ b/tests/test_native_mounted_ammo_probe.py
@@ -4,8 +4,8 @@
from policy_harness import ROOT, body, run
ROOT=Path(os.environ.get('ERR_NATIVE_SWAP_ROOT',ROOT))
p=Path(os.environ.get('ERR_NATIVE_MOUNTED_AMMO_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeMountedAmmoProbe.c'))
-s=p.read_text();smoke=(ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c').read_text()
-runner=(ROOT/'tools/headless_workbench.py').read_text()
+s=p.read_text();smoke=Path(os.environ.get('ERR_NATIVE_SMOKE_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c')).read_text()
+runner=Path(os.environ.get('ERR_NATIVE_MOUNTED_RUNNER',ROOT/'tools/headless_workbench.py')).read_text()
assert s.startswith('#ifdef WORKBENCH') and s.rstrip().endswith('#endif')
for forbidden in ('Spawn(', 'SpawnEntity', 'TrySpawn', '.Ingest(', '.Advance(', '.Dispatch(', '.BindVehicle(', '.Sample(',
'.SetOrigin(', '.SetAmmoCount(', '.Kill(', '.SetHealth(', 'NextStatus =', 'PendingStatus =', 'Uplink =', 'new ERR_HQStatusReport'):
@@ -34,7 +34,7 @@
code=code.replace('string.Empty','string{}').replace('protected ','').replace('null','nullptr').replace('ERR_GameMode.Get()', 'ERR_GameMode::Get()').replace('ERR_Actors.Alive(', 'ERR_Actors::Alive(')
for t in ('ERR_HQMountedAmmoSnapshot','ERR_HQ','ERR_ConvoyTask','ERR_HQWatchEntry'):
code=re.sub(r'\b'+t+r' (?=\w)',t+'* ',code)
-for var in ('a','b','hq','m_Mode','task','m_Queued','delivered','m_Unit','m_Route','m_ProofTask','m_SwapProbe'):
+for var in ('a','b','hq','m_Mode','task','m_Queued','delivered','m_Unit','m_Route','m_ProofTask','m_SwapProbe','m_BMPVehicle'):
code=re.sub(r'\b'+var+r'\.',var+'->',code)
for call in ('Convoys()','SupplyConvoys()','Watch()'):code=code.replace(call+'.',call+'->')
run(r'''
@@ -49,16 +49,16 @@
struct Route{int MessageId=7;string Payload="original";};struct Unit{int Group=1;Report* PendingStatus=nullptr;Route* Uplink=nullptr;};
struct ERR_GameMode{bool active=true;static inline ERR_GameMode* current=nullptr;static ERR_GameMode* Get(){return current;}bool Active(){return active;}};
template<class T>struct Arr:std::vector<T>{int Count(){return this->size();}void Clear(){this->clear();}};
-struct ERR_ConvoyTask{bool Stopped=false;Arr<int> Vehicles;};struct Pool{int count=3;int Count(){return count;}ERR_ConvoyTask* At(int){return nullptr;}};
+struct Escort{Root* Entity=nullptr;};struct ERR_ConvoyTask{bool Stopped=false;Arr<Escort*> Vehicles;};struct Pool{ERR_ConvoyTask* task=nullptr;int count=3;int Count(){return count;}ERR_ConvoyTask* At(int){return task;}};
struct Supply{int target=3;int Target(){return target;}string Status(){return "fixture production status";}};struct Watch{ERR_HQWatchEntry* entry=nullptr;ERR_HQWatchEntry* Find(string){return entry;}};
struct ERR_HQ{Pool pool;Supply supply;struct Watch watch;Unit* unit=nullptr;
Pool* Convoys(){return &pool;}Supply* SupplyConvoys(){return &supply;}struct Watch* Watch(){return &watch;}Unit* ERR_MountedFixtureUnit(int){return unit;}};
template<class... T>void PrintFormat(T...){}
struct SwapProbe{int result=1,calls=0,stops=0;int Tick(ERR_GameMode*,ERR_HQ*,ERR_ConvoyTask*){calls++;return result;}void Stop(){stops++;}};
-struct Probe{bool m_MineStock=false,mineProof=true;int mineChecks=0;void*m_MineBatch=nullptr,*m_MineTruck=nullptr,*m_MineInventory=nullptr;Arr<int>m_Mines,m_PrimaryCargo;bool Mines(ERR_ConvoyTask*,bool){mineChecks++;return !m_MineStock||mineProof;}bool m_SwapEligibility=false;SwapProbe* m_SwapProbe=nullptr;ERR_ConvoyTask* candidate=nullptr;ERR_ConvoyTask* Candidate(ERR_HQ*){return candidate;}bool m_Stopped=false,m_Failed=false,m_FleetReady=false,fleet=true;float m_Deadline=180000,m_NextLog=0;
+struct Probe{bool m_BMP=false,original=true;Escort*m_BMPVehicle=nullptr;bool Original(Escort*,Unit*){return original;}bool BMPReady(Escort*,ERR_HQMountedAmmoSnapshot*s){return s&&s->Complete&&s->Weapons>0&&s->Magazines>0&&s->Rounds+s->Chambers>0;}bool m_MineStock=false,mineProof=true;int mineChecks=0;void*m_MineBatch=nullptr,*m_MineTruck=nullptr,*m_MineInventory=nullptr;Arr<int>m_Mines,m_PrimaryCargo;bool Mines(ERR_ConvoyTask*,bool){mineChecks++;return !m_MineStock||mineProof;}bool m_SwapEligibility=false;SwapProbe* m_SwapProbe=nullptr;ERR_ConvoyTask* candidate=nullptr;ERR_ConvoyTask* Candidate(ERR_HQ*){return candidate;}bool m_Stopped=false,m_Failed=false,m_FleetReady=false,fleet=true;float m_Deadline=180000,m_NextLog=0;
ERR_ConvoyTask* m_ProofTask=nullptr;ERR_GameMode* m_Mode=nullptr;Report* m_Queued=nullptr;ERR_HQMountedAmmoSnapshot* m_Payload=nullptr;Route* m_Route=nullptr;
int captures=0;string m_RoutePayload="original";Unit* m_Unit=nullptr;Root* m_Root=nullptr;
- bool Check(bool b,string){if(!b)m_Failed=true;return b;}bool Fleet(ERR_HQ*){return fleet;}void Capture(ERR_HQ*,int,float){captures++;}
+ bool Check(bool b,string){if(!b)m_Failed=true;return b;}bool Fleet(ERR_HQ*){return fleet;}void Capture(ERR_HQ*,Escort*,float){captures++;}
'''+code+r'''
};
struct Setup{ERR_GameMode mode;ERR_HQ hq;Probe p;Root root;Unit unit;Route route;Report queued;ERR_HQWatchEntry delivered;
@@ -67,6 +67,14 @@
unit.PendingStatus=&queued;unit.Uplink=&route;queued.MountedAmmo=&original;delivered.MountedAmmo=&received;hq.watch.entry=&delivered;hq.unit=&unit;}
};
int main(){
+ // BMP delivery cannot succeed through a different slot/root, lost ownership or incomplete payload.
+ for(int fault=0;fault<6;fault++){Setup s;ERR_ConvoyTask task;Escort bmp,other;Root replacement;
+ task.Vehicles.resize(6);bmp.Entity=&s.root;task.Vehicles[4]=&bmp;s.p.m_BMP=true;s.p.m_BMPVehicle=&bmp;s.p.m_ProofTask=&task;s.hq.pool.task=&task;
+ if(fault==1)task.Vehicles[4]=&other;if(fault==2)bmp.Entity=&replacement;if(fault==3)s.p.original=false;
+ if(fault==4){s.payload.Complete=false;s.original.Complete=false;s.received.Complete=false;}
+ if(fault==5){s.payload.Rounds=0;s.payload.Chambers=0;s.original=s.payload;s.received=s.payload;}
+ assert(s.p.Tick(&s.hq,3000)==(fault==0?1:-1));assert(s.p.captures==3); // exactly slot4 per observed task, never other slots
+ }
{Setup s;s.p.m_MineStock=true;s.p.mineProof=false;assert(s.p.Tick(&s.hq,3000)==-1&&s.p.mineChecks==1);}
{Setup s;s.p.m_MineStock=true;s.p.m_Mines.push_back(1);s.p.m_PrimaryCargo.push_back(2);s.p.m_MineBatch=&s;s.p.Stop();assert(s.p.m_Mines.empty()&&s.p.m_PrimaryCargo.empty()&&!s.p.m_MineBatch);}
{Setup s;SwapProbe dry;ERR_ConvoyTask task;s.p.m_SwapEligibility=true;s.p.m_SwapProbe=&dry;s.p.candidate=&task;
@@ -143,3 +151,95 @@
}
''')
print('PASS: actual one-existing-convoy candidate readiness, sender-root identity, incomplete cargo refusal and fixed three-candidate bound')
+
+# Execute the exact Capture and BMPReady methods; native identity/roster/watch
+# boundaries are explicit doubles, while the snapshot validator has its own full suite.
+selected=[]
+if 'protected bool BMPReady(' in s: selected.append(body(p,'protected bool BMPReady('))
+selected.append(body(p,'protected void Capture('))
+capture='\n'.join(selected).replace('protected ','').replace('null','nullptr')
+for ns in ('ERR_ConvoyResources','ERR_HQWatchRules'):
+ capture=capture.replace(ns+'.',ns+'::')
+for t in ('ERR_ConvoyVehicle','ERR_HQMountedAmmoSnapshot','ERR_HQ','ERR_HQUnit','ERR_HQStatusReport','ERR_HQWatchEntry'):
+ capture=re.sub(r'\b'+t+r' (?=\w)',t+'* ',capture)
+for v in ('vehicle','sample','hq','unit','report','before','m_Route','m_Payload'):
+ capture=re.sub(r'\b'+v+r'\.',v+'->',capture)
+for x in ('Entity','MountedAmmo','StatusSampler','Uplink'):
+ capture=capture.replace('.'+x+'.','.'+x+'->').replace('->'+x+'.','->'+x+'->')
+for x in ('GetPrefabData()','Watch()'):
+ capture=capture.replace(x+'.',x+'->')
+capture=capture.replace('unit->Uplink->Nodes.Count()', 'int(unit->Uplink->Nodes.size())')
+run(r'''
+#include <cassert>
+#include <string>
+#include <vector>
+struct string:std::string{using std::string::string;string(const std::string&s):std::string(s){}bool Contains(const char*s){return find(s)!=npos;}};
+struct Prefab{string name="bmp";string GetPrefabName(){return name;}};
+struct Entity{Prefab prefab;Prefab*GetPrefabData(){return &prefab;}};
+struct ERR_ConvoyResources{static string VehiclePrefab(int slot){assert(slot==4);return "bmp";}};
+struct ERR_HQMountedAmmoSnapshot{bool Complete=true,valid=true;int Weapons=3,Magazines=3,Rounds=80,Chambers=1;
+ bool Valid(){return valid;}ERR_HQMountedAmmoSnapshot*Snapshot(){return new ERR_HQMountedAmmoSnapshot(*this);}};
+struct ERR_ConvoyVehicle{struct Entity*Entity=nullptr;bool Registered=true;int Group=1;};
+struct ERR_HQStatusReport{ERR_HQMountedAmmoSnapshot*MountedAmmo=nullptr;int MessageId=7;string SourceId="source";};
+struct ERR_HQWatchEntry{int MessageId=6;};
+struct Sampler{string InitialSourceId(){return "source";}};
+struct Route{int MessageId=7,Cursor=0;std::vector<int>Nodes={1,2};string Payload="mounted ammunition=original";};
+struct ERR_HQUnit{ERR_HQStatusReport*PendingStatus=nullptr;Route*Uplink=nullptr;Sampler*StatusSampler=nullptr;};
+struct Watch{ERR_HQWatchEntry*entry=nullptr;ERR_HQWatchEntry*Find(string){return entry;}};
+struct ERR_HQ{ERR_HQUnit*unit=nullptr;struct Watch watch;ERR_HQUnit*ERR_MountedFixtureUnit(int){return unit;}struct Watch*Watch(){return &watch;}};
+struct ERR_HQWatchRules{static bool Valid(ERR_HQStatusReport*,float){return true;}};
+struct Probe{bool m_BMP=true,original=true,failed=false;ERR_ConvoyVehicle*m_BMPVehicle=nullptr;ERR_HQStatusReport*m_Queued=nullptr;ERR_HQUnit*m_Unit=nullptr;Entity*m_Root=nullptr;ERR_HQMountedAmmoSnapshot*m_Payload=nullptr;Route*m_Route=nullptr;string m_RoutePayload;
+ bool Original(ERR_ConvoyVehicle*,ERR_HQUnit*){return original;}bool Check(bool x,const char*){if(!x)failed=true;return x;}
+ bool Same(ERR_HQMountedAmmoSnapshot*a,ERR_HQMountedAmmoSnapshot*b){return a->Complete==b->Complete&&a->Weapons==b->Weapons&&a->Magazines==b->Magazines&&a->Rounds==b->Rounds&&a->Chambers==b->Chambers;}
+'''+capture+r'''
+};
+struct Setup{Probe p;Entity root;ERR_ConvoyVehicle vehicle;ERR_HQ hq;ERR_HQUnit unit;Sampler sampler;Route route;ERR_HQStatusReport report;ERR_HQMountedAmmoSnapshot sample;
+ Setup(){vehicle.Entity=&root;hq.unit=&unit;unit.PendingStatus=&report;unit.Uplink=&route;unit.StatusSampler=&sampler;report.MountedAmmo=&sample;}};
+int main(){
+ {Setup s;s.root.prefab.name="uaz";s.p.Capture(&s.hq,&s.vehicle,1000);assert(!s.p.m_Queued&&!s.p.m_Payload);}
+ for(int bad=0;bad<6;bad++){Setup s;if(bad==0)s.sample.Complete=false;if(bad==1)s.sample.valid=false;
+ if(bad==2)s.sample.Weapons=0;if(bad==3)s.sample.Magazines=0;if(bad==4){s.sample.Rounds=0;s.sample.Chambers=0;}if(bad==5)s.p.original=false;
+ s.p.Capture(&s.hq,&s.vehicle,1000);assert(!s.p.m_Queued&&!s.p.m_BMPVehicle);}
+ {Setup s;s.p.Capture(&s.hq,&s.vehicle,1000);assert(s.p.m_Queued==&s.report&&s.p.m_BMPVehicle==&s.vehicle&&s.p.m_Root==&s.root);
+ assert(s.p.m_Payload!=&s.sample&&s.p.m_Payload->Complete&&s.p.m_Route==&s.route&&!s.p.failed);
+ s.sample.Rounds=0;assert(s.p.m_Payload->Rounds==80);}
+ {Setup s;s.p.m_BMP=false;s.root.prefab.name="uaz";s.sample.Complete=false;s.p.Capture(&s.hq,&s.vehicle,1000);assert(s.p.m_Queued==&s.report&&!s.p.m_BMPVehicle);}
+}
+'''.replace(';if(', ';\n if('))
+node=next(n for n in ast.parse(runner).body if isinstance(n,ast.If) and ast.unparse(n.test).startswith('a.mounted_bmp and'))
+condition=compile(ast.Expression(node.test),'<bmp-selector>','eval')
+for field in [None,'smoke','project','rounds','timeout','mine_stock','mounted_courier','mounted_swap_eligibility']:
+ values=dict(mounted_bmp=True,smoke='mounted-ammo',project='chat',rounds=1,timeout=360,mine_stock=False,mounted_courier=False,mounted_swap_eligibility=False)
+ if field:values[field]={'smoke':'convoy','project':'core','rounds':2,'timeout':359}.get(field,True)
+ assert eval(condition,{'a':SimpleNamespace(**values)})==(field is not None)
+assert "if a.mounted_bmp: command += ['-errMountedBMP', '1']" in runner
+print('PASS: actual BMP capture requires complete armed exact original resource; pinned delivery/slot checks and isolated CLI flag')
+
+# WORKBENCH isolation changes only unrelated services before the real unlock.
+assert start.index('!mixedBMP && StartMode() == 0 && Phase() == ERR_Phase.PRISON') < start.index('bmpHQ.ERR_IsolateMountedBMP()') < start.index('UnlockPrison(')
+assert all(x in start for x in ('errMineStock','errMountedSwapEligibility','errMountedCourier'))
+hook_path=Path(os.environ.get('ERR_NATIVE_SMOKE_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c'))
+hook=body(hook_path,'bool ERR_IsolateMountedBMP(').replace('ERR_NativeMountedAmmoProbe.','ERR_NativeMountedAmmoProbe::').replace('System.','System::').replace('ERR_GameMode.','ERR_GameMode::').replace('ERR_Phase.','ERR_Phase::')
+for v in ('m_Mode','m_Hunters','m_Towns'):hook=hook.replace(v+'.',v+'->')
+run(r'''
+#include <cassert>
+#include <string>
+using string=std::string;
+struct ERR_NativeMountedAmmoProbe{static inline bool enabled=true;static bool Enabled(){return enabled;}};
+struct System{static inline string flag="1";static bool GetCLIParam(string key,string&out){assert(key=="errMountedBMP");out=flag;return !flag.empty();}};
+struct ERR_Phase{static constexpr int PRISON=1;};
+struct ERR_GameMode{int start=0,phase=1;static inline ERR_GameMode*current=nullptr;static ERR_GameMode*Get(){return current;}int StartMode(){return start;}int Phase(){return phase;}};
+struct Service{int deployed=0,stops=0;int Deployed(){return deployed;}void Stop(){stops++;}};
+struct HQ{ERR_GameMode*m_Mode=nullptr;Service*m_Hunters=nullptr,*m_Towns=nullptr;
+'''+hook+r'''
+};
+int main(){for(int fault=0;fault<10;fault++){
+ ERR_GameMode mode,other;ERR_GameMode::current=&mode;Service hunters,towns;HQ h;h.m_Mode=&mode;h.m_Hunters=&hunters;h.m_Towns=&towns;
+ ERR_NativeMountedAmmoProbe::enabled=true;System::flag="1";
+ if(fault==1)ERR_NativeMountedAmmoProbe::enabled=false;if(fault==2)System::flag="";if(fault==3)System::flag="0";
+ if(fault==4)ERR_GameMode::current=&other;if(fault==5)mode.start=1;if(fault==6)mode.phase=2;
+ if(fault==7)hunters.deployed=1;if(fault==8)h.m_Hunters=nullptr;if(fault==9)h.m_Towns=nullptr;
+ assert(h.ERR_IsolateMountedBMP()==(fault==0));assert(hunters.stops==(fault==0?1:0)&&towns.stops==(fault==0?1:0));
+}}
+'''.replace(';if(', ';\n if('))
+print('PASS: actual opt-in pre-unlock isolation refuses wrong mode/phase/flag and existing hunters; no baseline service changes')
@@ -0,0 +1,4 @@
PASS: actual bounded native mounted proof/detached payload/deadline/cleanup methods, production-only setup and isolated runner selector
PASS: actual one-existing-convoy candidate readiness, sender-root identity, incomplete cargo refusal and fixed three-candidate bound
PASS: actual BMP capture requires complete armed exact original resource; pinned delivery/slot checks and isolated CLI flag
PASS: actual opt-in pre-unlock isolation refuses wrong mode/phase/flag and existing hunters; no baseline service changes
@@ -0,0 +1,50 @@
{
"complete": true,
"approved": true,
"blockers": [],
"review": "Independent read-only inspection of both exact frozen proposals, existing production service guards, actual-method harness source and recorded logs. No tests/compiler/native rerun.",
"bindings": {
"/tmp/erri-mounted-bmp-probe": {
"manifest_sha256": "af0e6e99a3969ea64d3936b01f56f54c829d56754251c2af09c28710468991de",
"patch_sha256": "d594eddef2327addad3a3977b247cd971b1fbe8713368151e0e502b8ce9d1fc3",
"files": {
"addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeMountedAmmoProbe.c": {
"baseline_sha256": "8d197f7a1398625e5a19db3284b0bf72c6ee6e032843a3e4d9a4e58de42b6825",
"proposed_sha256": "7ddb634444c79ad9291d53a754dc0ed383342e36720ddaa4b7aa4bd4e7ee656d"
},
"tools/headless_workbench.py": {
"baseline_sha256": "af11b29cc9f22f12e019978164fe808c9c903ea977b15a722846501a8377727f",
"proposed_sha256": "b0bbb87597fe5f116e8b4fd1d60d52983935d438d3e82b972c675991fddcc971"
},
"tests/test_native_mounted_ammo_probe.py": {
"baseline_sha256": "dd7169d8127fef52a4815fb4ad8227307df557170da6a22723c765bcd74ba340",
"proposed_sha256": "87bc8b9952be2e13fd7778af59504078e694b7bd9f0bdfea173feeec58a10f0e"
}
}
},
"/tmp/erri-mounted-bmp-hook": {
"manifest_sha256": "8054b7a04f6ae992fc00f82044738ea04f53fa4e4d334ab183e7638b755ef1e6",
"patch_sha256": "792b3670fda0aaadbb09bbf23a7a34981129e93302372cbbea512467fb601c19",
"files": {
"addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c": {
"baseline_sha256": "e2a32dbe372edc2f5cd03a55dcb3dd11689ad8b60940a7a318b0c829d464d3e2",
"proposal_sha256": "b7e1857b0678b3a2c71880c0f35b09da9e978f19bacf5b4e7449c893fdbe2b95"
}
}
}
},
"checks": [
"Isolation helper remains inside WORKBENCH and requires actual mounted-ammo enabled/server path, errMountedBMP=1, current mode, prison start and PRISON phase, no previously deployed hunters, and both service identities. Calls Stop before canonical UnlockPrison. Town Tick refuses PRISON and creation is synchronous; no existing town population or new body refunds required.",
"Runner rejects wrong fixture/project/rounds/deadline and mixed mine/courier/swap flags before launch. Raw fixture repeats mutual-exclusion guards before isolation. Default flag-disabled branch unchanged.",
"Automatic target remains3, pool/cap/reservations and startup clock unchanged. Existing180000ms probe deadline and six-root physical roster/cargo-exclusion checks retained.",
"BMP capture selects slot4 only and checks exact original BMP resource, valid Complete nonempty armed counts. Pins exact convoy vehicle/root, original roster, sender source, queued message and route payload; copies snapshot independently.",
"Final proof requires same selected task slot4/original vehicle/root and original roster, exact Watch MessageId, separate delivered and queued snapshots equal to detached captured scalars, observation/delivery bounds and unchanged route payload. No direct radio Advance/Ingest/dispatch or stock edits.",
"Harness logs show final green, baseline compiled runtime-red at absent slot4-only selection, Complete-removal mutation compiled runtime-red at admission assertion. Native APIs/physics are doubled; no engine proof inferred."
],
"limitations": [
"This is a deliberately isolated protected-observer diagnostic; ordinary default-population convoy availability is not qualified.",
"Success would qualify original BMP mounted accounting and natural radio delivery for one original convoy only, not physical interception, full fleet reliability, manual play, multiplayer or FPS.",
"Existing baseline fixture failure and shared117/135 refusal remain valid evidence; cap policy unchanged.",
"No native completion is asserted by this source review."
]
}
@@ -0,0 +1,21 @@
check: /tmp/err-policy-yqj9w2m8/check.cpp:59: int main(): Assertion `!s.p.m_Queued&&!s.p.m_BMPVehicle' failed.
PASS: actual bounded native mounted proof/detached payload/deadline/cleanup methods, production-only setup and isolated runner selector
PASS: actual one-existing-convoy candidate readiness, sender-root identity, incomplete cargo refusal and fixed three-candidate bound
Traceback (most recent call last):
File "/tmp/erri-mounted-bmp-probe/tests/test_native_mounted_ammo_probe.py", line 172, in <module>
run(r'''
~~~^^^^^
#include <cassert>
^^^^^^^^^^^^^^^^^^
...<33 lines>...
}
^
'''.replace(';if(', ';\n if('))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 14, in run
subprocess.run([str(p/'check')],check=True)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/subprocess.py", line 578, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/tmp/err-policy-yqj9w2m8/check']' died with <Signals.SIGABRT: 6>.
@@ -0,0 +1,31 @@
{
"files": {
"addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeMountedAmmoProbe.c": {
"baseline_sha256": "8d197f7a1398625e5a19db3284b0bf72c6ee6e032843a3e4d9a4e58de42b6825",
"proposed_sha256": "7ddb634444c79ad9291d53a754dc0ed383342e36720ddaa4b7aa4bd4e7ee656d"
},
"tools/headless_workbench.py": {
"baseline_sha256": "af11b29cc9f22f12e019978164fe808c9c903ea977b15a722846501a8377727f",
"proposed_sha256": "b0bbb87597fe5f116e8b4fd1d60d52983935d438d3e82b972c675991fddcc971"
},
"tests/test_native_mounted_ammo_probe.py": {
"baseline_sha256": "dd7169d8127fef52a4815fb4ad8227307df557170da6a22723c765bcd74ba340",
"proposed_sha256": "87bc8b9952be2e13fd7778af59504078e694b7bd9f0bdfea173feeec58a10f0e"
}
},
"patch_sha256": "d594eddef2327addad3a3977b247cd971b1fbe8713368151e0e502b8ce9d1fc3",
"hook_source_sha256": "b7e1857b0678b3a2c71880c0f35b09da9e978f19bacf5b4e7449c893fdbe2b95",
"tests": {
"green_exit": 0,
"baseline_exit": 1,
"baseline_compiled_runtime_red": true,
"mutation_exit": 1,
"mutation_compiled_runtime_red": true,
"logs": {
"green.log": "608933baa6b1f2798ec075bbc9a66f4b347444c4806d3dde9c930d2aec1be978",
"baseline-red.log": "8c2a4a94132827f0b4f6aebd216f93256ccd6af34a5446e5a99921b9a8d2ec0b",
"mutation-red.log": "a877ec3e21aef3d994d82812f19c54a2120a0a316c5ddb920e079c6137d84193",
"adapter-compile-failure.log": "0fbdda6e7a15f318622150a45377e3974485eb0fb3dd0e164f6bded65b1d2bde"
}
}
}