-
Notifications
You must be signed in to change notification settings - Fork 1
Deep Review Findings
Claude adversarial-review log (source-cited). This page records findings from independent verification passes against the Chernarus source mission, cross-checking the SQF code atlas, Gameplay systems atlas and other pages. Each finding is confirmed against
path:line, given a severity, and paired with a remediation playbook. It complements (does not replace) Codex's atlas pages and the Feature status register.
All paths are relative to the source mission root Missions/[55-2hc]warfarev2_073v48co.chernarus/. Arma 2 OA 1.64 — not Arma 3.
What. The PVF dispatch executes a string taken directly from the value a remote machine broadcast, with no validation that it names a known command.
-
Server/Functions/Server_HandlePVF.sqf:_script = _publicVar select 0; _parameters Spawn (Call Compile _script); -
Client/Functions/Client_HandlePVF.sqf: same pattern on_publicVar select 1. - The handlers are bound in
Common/Init/Init_PublicVariables.sqfasWFBE_PVF_<Command> addPublicVariableEventHandler { (_this select 1) Spawn WFBE_SE_FNC_HandlePVF }._this select 1is the new value chosen by the sender. - Clients legitimately reach the server channel via
Common/Functions/Common_SendToServerOptimized.sqf:15→publicVariableServer 'WFBE_PVF_<cmd>'.
The legitimate flow always sets index 0 to the bare identifier "SRVFNC<Command>", so Call Compile resolves a function-variable lookup. But nothing constrains the value to that shape: a crafted broadcast on a registered WFBE_PVF_* channel whose select 0 is arbitrary SQF text would be compiled and run on the receiver. This is the well-known Arma 2 publicVariable trust-boundary problem.
Why the usual mitigations are absent here.
-
No server-side validation.
Server_HandlePVF.sqfdoes not check that_scriptbegins withSRVFNCor is in the registered command set (confirmed: noSRVFNC/CLTFNCguard in either handler). -
No BattlEye filtering.
BattlEyeFilter/publicvariable.txtcontains a single rule,5 "kickAFK". That rule is the AFK-kick feature (the mission cannot kick directly, so it broadcastskickAFKand relies on BattlEye to kick the sender — see Networking and public variables). It is not a security filter: there is no restrictive default line and no whitelist of theWFBE_PVF_*channels with value constraints.
Severity rationale. This is a live-server hardening gap, not a mission-logic bug. It matters for any publicly-listed server (the README advertises one). It is recorded here as defensive guidance for the server owner.
Remediation playbook (cheapest first):
-
Validate before compile (server-side, no BE knowledge needed). In
Server_HandlePVF.sqf, reject any_scriptnot in the known set, e.g. build a lookup of"SRVFNC"+cmdfor every registered command at init andexitWith(with aWARNINGlog) if_scriptis not a member. Same idea forClient_HandlePVF.sqfagainstCLTFNC*. This neutralizes arbitrary-string compilation while preserving all legitimate traffic. -
Add a real BattlEye
publicvariable.txtas defense-in-depth: a restrictive default plus an explicit allow-list ofWFBE_PVF_*, the direct channels in the SQF code atlas "Direct Public Variable Channels" table, and the existingkickAFKrule. Do not add a blanket restrictive default without the allow-list, or you will break all PVF traffic. - Prefer
publicVariableClient/publicVariableServer(targeted) over broadcast for owner-directed messages to shrink the surface (already mostly done).
Server/Support/Support_Paratroopers.sqf:117 sends the marker:
[leader _playerTeam, "HandleParatrooperMarkerCreation", [_x, _sideID]] Call WFBE_CO_FNC_SendToClient;Common/Functions/Common_SendToClient.sqf turns that into WFBE_PVF_HandleParatrooperMarkerCreation (dedicated path) / CLTFNCHandleParatrooperMarkerCreation (hosted path). But:
-
HandleParatrooperMarkerCreationis not in the_clientCommandPVlist inCommon/Init/Init_PublicVariables.sqf, soWFBE_PVF_HandleParatrooperMarkerCreationhas noaddPublicVariableEventHandler, andCLTFNCHandleParatrooperMarkerCreationis never compiled (confirmed: no reference in anyInit_*).
Result: on a dedicated server the marker PV is broadcast but never handled; on a hosted/SP server Spawn (Call Compile "CLTFNCHandleParatrooperMarkerCreation") resolves to nil → no marker (and a likely script error). The send side exists; the receive side was never wired. This upgrades the atlas note ("exists but not registered") to a confirmed broken feature. Fix: add HandleParatrooperMarkerCreation to _clientCommandPV (the receiver file Client/PVFunctions/HandleParatrooperMarkerCreation.sqf already exists), or remove the dead send.
MASH markers use a two-hop relay:
- Client deploys tent →
WFBE_CL_MASH_MARKER_CREATED→ server EH inServer/Module/MASH/MASHMarker.sqf:1(registered) re-broadcastsWFBE_SE_MASH_MARKER_SENT. - The client EH that should consume
WFBE_SE_MASH_MARKER_SENTlives inClient/Module/MASH/receiverMASHmarker.sqf:1— but its only reference is the commented compile atClient/Init/Init_Client.sqf:132://WFBE_CL_FNC_ReceiverMASHmarker = Call Compile preprocessFileLineNumbers "Client\Module\MASH\receiverMASHmarker.sqf";
Result: no client ever registers the WFBE_SE_MASH_MARKER_SENT handler, so MASH map markers never appear. (MASH respawn itself is independent and may work; only the map marker is dead.) This resolves the atlas's "client receiver currently not clearly active / requires verification." Fix: uncomment/restore the receiver registration in client init, or drop the dead server re-broadcast.
DR-4 — Generated-mission drift: Takistan is in sync; the skip-list is a silent-divergence trap; modded maps are abandoned (generated-mission drift) — Medium
A full recursive diff of Missions/[55-2hc]…chernarus vs Missions_Vanilla/[61-2hc]…takistan shows every difference is exactly a LoadoutManager skip-listed file or blacklisted directory — there is no accidental drift between the two at this commit:
- Differing files:
mission.sqm,version.sqf(git-ignored),Client/GUI/GUI_Menu_Help.sqf,WASP/unsort/StartVeh.sqf,loadScreen.jpg,texHeaders.bin,Server/Init/Init_Server.sqf(theSET_MAP 1→2patch), and the blacklistedCommon/Config/Core_Artillery/*+Server/Config/*+Textures/*.
This is more reassuring but also more dangerous than the "generated missions can drift" framing elsewhere. The precise hazard is the skip-list, defined in Tools/LoadoutManager FileManagement/FileManager.cs (ShouldSkipFile + the co.takistan directory blacklist):
A gameplay edit made in Chernarus to any skip-listed file —
mission.sqm,GUI_Menu_Help.sqf,StartVeh.sqf, anything underCore_Artillery/,Server/Config/, orTextures/— will never propagate to Takistan viadotnet run. These must be hand-mirrored in both missions.
So the standard guidance "edit Chernarus + run LoadoutManager" is incomplete: it is correct for the ~95% of files that are copied, and silently wrong for the skip-listed set. See the expanded propagation guidance in Tools and build workflow.
Modded maps are abandoned/stale. Because modded propagation is commented out at Tools/LoadoutManager SqfFileGenerators/SqfFileGenerator.cs:132, the Modded_Missions/* trees are far behind Chernarus (787 files):
| Modded mission | File count | State |
|---|---|---|
…Napf |
507 | ~280 files behind |
…eden |
502 | ~285 behind |
…lingor |
438 | ~349 behind |
…dingor |
20 | stub |
…smd_sahrani_a2 |
4 | stub |
…tavi |
3 | stub |
…isladuala |
1 | stub |
None are deployable as-is; they would need full regeneration after the modded path is re-enabled. Treat Modded_Missions/* as non-authoritative.
The SQF code atlas states "659 preprocessFile references (452 preprocessFileLineNumbers + 207 plain)". An independent recount on the docs/developer-wiki-index base yields 678 total / 465 preprocessFileLineNumbers / 213 plain. The gap is small and likely reflects counting method (comment handling) or branch timing — not an error — but hardcoded counts rot as the mission changes. Recommendation: present such counts as point-in-time and ship the regeneration command so future agents verify rather than trust, e.g. (PowerShell, from the mission root):
(Get-ChildItem -Recurse -Filter *.sqf | Select-String -SimpleMatch 'preprocessFileLineNumbers').CountVerified-accurate cross-checks (for trust calibration): the atlas's FSM inventory is correct — exactly three .fsm files exist (Client/FSM/updateactions.fsm, Client/FSM/updateavailableactions.fsm, Client/kb/hq.fsm); and HandleParatrooperMarkerCreation / AttackWave / LogGameEnd are indeed outside the standard PVF list as the atlas notes.
- Decide fix-vs-remove for DR-2 (paratrooper markers) and DR-3 (MASH markers); both are one-line wiring changes in the Chernarus source.
- DR-1 server-side validation is a small, safe gameplay-code change (Chernarus
Server_HandlePVF.sqf) — gate behind review since it touches the network hot path. - Re-confirm DR-4 modded-map decision: regenerate or formally retire
Modded_Missions/*.
Lane pvf-hardening-review. This turns DR-1 into a concrete, behavior-preserving change set a code owner can apply to the Chernarus source. Every claim below was re-verified against source on this pass. Paths relative to Missions/[55-2hc]warfarev2_073v48co.chernarus/.
The dispatch targets are already-compiled global variables, created at registration in Common/Init/Init_PublicVariables.sqf:44,49:
Call Compile Format["CLTFNC%1 = compile preprocessFileLineNumbers 'Client\PVFunctions\%1.sqf'", _x]; // :44
Call Compile Format["SRVFNC%1 = compile preprocessFileLineNumbers 'Server\PVFunctions\%1.sqf'", _x]; // :49So SRVFNCRequestJoin, CLTFNCTownCaptured, … are missionNamespace variables holding code. The dispatch line Spawn (Call Compile _script) only compiles the string _script to perform a variable lookup. That means the same resolution can be done with getVariable, which treats _script purely as a name and cannot execute an arbitrary SQF string a client injected.
Replace the compile-the-string dispatch with a name lookup that defaults to a no-op.
Server/Functions/Server_HandlePVF.sqf (current _parameters Spawn (Call Compile _script);):
private _fn = missionNamespace getVariable [_script, {}]; // resolve SRVFNC<cmd>; unknown -> {}
if (_fn isEqualTo {}) exitWith {
["WARNING", format ["Server_HandlePVF: rejected unknown PVF command '%1' from network", _script]] Call WFBE_CO_FNC_LogContent;
};
_parameters Spawn _fn;Client/Functions/Client_HandlePVF.sqf (current _parameters Spawn (Call Compile _script);): identical pattern resolving CLTFNC<cmd>.
Why this is safe and behavior-identical:
- Legitimate traffic sets
_scriptto exactly"SRVFNC"+cmd/"CLTFNC"+cmd(seeCommon/Functions/Common_SendToServerOptimized.sqf:15,Common/Functions/Common_SendToClient.sqf), which resolves to the compiled function — unchanged. - A hostile value such as
"hint 'x'; <server-side effect>"is not a defined variable, sogetVariablereturns the default{}→Spawn {}→ no-op (plus a WARNING that surfaces probing in the RPT). Nocompileever runs on attacker text. -
isEqualTo {}is a valid Arma 2 OAcodecomparison; use it (notisNil) because the default is empty code, not nil.
At the end of Init_PublicVariables.sqf, snapshot the legal command set so the handler check is explicit rather than implicit:
WFBE_SE_PVF_ALLOWED = _serverCommandPV apply {format ["SRVFNC%1", _x]};
WFBE_CL_PVF_ALLOWED = _clientCommandPV apply {format ["CLTFNC%1", _x]};
publicVariable "WFBE_SE_PVF_ALLOWED"; // optional; or keep server-localThen guard with if !(_script in WFBE_SE_PVF_ALLOWED) exitWith { ...log... }; before resolving. Fix 1 already covers the same cases; use Fix 2 only if you want a named, auditable whitelist.
The shipped BattlEyeFilter/publicvariable.txt is a single line, 5 "kickAFK", which is the AFK-kick feature trigger, not a security filter (see Networking and public variables → Security). A hardened filter uses a restrictive default first line plus explicit allow exceptions:
5 "" // default: kick on any unlisted PV broadcast
!="^WFBE_PVF_[A-Za-z]+$" // allow the dispatch channels
!="^wfbe_supply_temp_(west|east)$" // allow the supply request channel
!="^(ATTACK_WAVE_INIT|CLIENT_INIT_READY|REQUEST_SUPPLY_VALUE|WFBE_CL_MASH_MARKER_CREATED|AFKthresholdExceededName|WFBE_C_PLAYER_OBJECT|WFBE_CLIENT_HAS_CONNECTED_AT_LAUNCH)$"
5 "kickAFK" // keep the AFK feature kick
⚠️ Validate the exact client→server channel list against the "Direct Public Variable Channels" table in the SQF code atlas before deploying — a too-strict default with a missing exception will kick legitimate players. BattlEye regex/escaping differs from SQF; test on a private server first. This complements, and does not replace, Fix 1 (BE filters the variable name, not the payload shape).
Fix 1 stops arbitrary code execution, but the PVF model still trusts client-sent commands and parameters. A malicious client can broadcast a legitimate command with chosen arguments — e.g. RequestChangeScore (Server/PVFunctions/RequestChangeScore.sqf sets a player's score directly from the payload) or RequestStructure — because the server handlers largely don't authenticate the sender against the payload. Closing that is a larger, per-handler effort (validate that owner/sender matches the acting player, clamp economy/score deltas, range-check structure requests). Treat this as a separate follow-up lane, not part of the dispatch fix. Documented here so the dispatch fix isn't mistaken for full PVF authorization.
- No registered handler under
Server/PVFunctions/orClient/PVFunctions/, norServer_HandleSpecial.sqf/HandleSpecial.sqf/LocalizeMessage.sqf, callscompileon its parameters — so once the dispatch command name is resolved safely, there is no second-order injection on the PVF path. The othercall compilesites in the mission compile files (Init_Coin.sqf, EASA/CM init) or local engine key-strings (coin_interface.sqf:774-777), not network data. - Handoff: this is a Chernarus-source gameplay change → after applying, run
Tools/LoadoutManagerdotnet runto propagate (noteServer_HandlePVF/Client_HandlePVFare not on the skip-list, so they propagate normally;BattlEyeFilter/lives outside the mission and is deployed with the server, not via LoadoutManager).
Lane construction-authority-review (extends Construction and CoIn systems atlas, whose "Authority Boundary" section flags this risk generically; this finding adds per-handler forgery proof + a validation design). This is the concrete realization of the command-forgery residual scoped in Round 3 (Fix 1 closes code execution, not command forgery).
DR-6 — Construction request handlers perform no sender/authority/resource validation — High (gameplay integrity)
All three construction PVF handlers derive trust from the client-supplied payload and never verify the requester. Source (verified this pass):
| Handler | Validation actually performed | Client-controlled inputs | Forgery impact |
|---|---|---|---|
Server/PVFunctions/RequestStructure.sqf |
Only: does _structureType exist in WFBE_<side>STRUCTURENAMES. |
_side (select 0), class, pos, dir — all from payload. |
Forge ["RequestStructure",[WEST,"US_WarfareBHeavyFactory_EP1",anyPos,dir]] → server ExecVMs the construction script and builds a free factory anywhere for any side. No commander check, no funds debit, no placement/base-area/hostile-town checks (those are client-only, atlas "Placement Rules"). |
Server/PVFunctions/RequestDefense.sqf |
Only: does _defenseType exist in WFBE_<side>DEFENSENAMES. |
_side, class, pos, dir, _manned — all from payload. |
Forge unlimited free defenses — incl. AI-manned static weapons and minefields (Sign_Danger) — anywhere for any side, bypassing the base-area avail budget (decremented only client-side in coin_interface.sqf:724-730). |
Server/PVFunctions/RequestMHQRepair.sqf |
None. Body is [_this] Spawn MHQRepair;. |
entire payload; MHQRepair.sqf:3 uses _side. |
MHQRepair rebuilds the side HQ from server state (GetSideHQ/GetCommanderTeam/position) with no dead-HQ check, no commander check, and none of the repair count/price gating that lives only client-side in Action_RepairMHQ.sqf. Forge ["RequestMHQRepair",[side]] → free, unlimited HQ respawn/repair; can also fire while the HQ is alive. |
-
_sideis taken from the payload, not derived from the sender. A client can act on any side's behalf. - The payloads don't even include the requesting player object, so the handlers cannot identify or authorize the sender as written.
-
Arma 2 OA
addPublicVariableEventHandlerprovides no sender identity —_thisis[varName, value]only (unlike Arma 3remoteExecutedOwner/REownership). So authority must be reconstructed: the payload must carry the player, and the server must validate that player's role/side/funds against server-side state. (This is also why DR-1's command-validation fix does not, by itself, stop forgery.)
Add the requesting player to each request and validate server-side before creating objects. Example for RequestStructure (mirror for RequestDefense; for RequestMHQRepair validate dead-HQ + commander + repair-count/price server-side):
// client (coin_interface / Action_*): include the player in the payload
["RequestStructure", [player, sideJoined, _class, _pos, _dir]] Call WFBE_CO_FNC_SendToServer;
// server RequestStructure.sqf (new guards, then existing logic):
_player = _this select 0; _side = _this select 1; _structureType = _this select 2; ...
if (isNull _player) exitWith {};
if (side _player != _side) exitWith {}; // can't build for another side
if (_player != leader ((_side) call WFBE_CO_FNC_GetCommanderTeam)) exitWith {}; // commander-only
private _cost = /* look up WFBE_<side>STRUCTURECOSTS[index] */;
if ((_side call WFBE_CO_FNC_GetSideSupply) < _cost) exitWith {}; // server-authoritative funds
[_side, -_cost, "structure build", false] call WFBE_CO_FNC_ChangeSideSupply; // debit on server
// ...then the existing class-exists lookup + ExecVM construction scriptNotes:
- Keep the client cost-deduction/preview for instant UX, but make the server the final authority on debit and creation (atlas "Cost deduction" risk row agrees). Avoid double-debit by having the client send a request and the server be the source of truth (or reconcile on the server-confirmed message).
- Re-checking full placement/collision server-side is heavier; at minimum validate side+commander+funds+class (cheap, closes the worst abuse). Base-area
availshould also be decremented/validated server-side to stop the unlimited-defense path (traceRequestBaseArea+Construction_StationaryDefensetogether, per the atlas, for JIP safety). - This is gameplay-code; gate behind review (touches the build hot path) and run LoadoutManager after.
RequestStructure/Defense/MHQRepair.sqfare not on the skip-list, so they propagate normally.
Not a crash/RCE (that's DR-1). This is gameplay-integrity / anti-grief: on a public server, a modified client can mint free factories/defenses/HQs and bypass the economy. Pair with DR-1 (validate the command) — DR-1 stops arbitrary code, DR-6 stops forged legitimate commands; both are needed for a hardened public server.
Lane antistack-db-trust. The AntiStack module persists per-player score/side and team skill to an external native extension for team-balancing. Source: Server/Module/AntiStack/callDatabase*.sqf (7 callExtension sites) + the A2WaspDatabase DLL, which is not in this repo (only the in-repo Extension/ GLOBALGAMESTATS DLL is — see External integrations). All claims verified this pass.
DR-7 — The server call compiles the extension's return value on every call — High (external trust boundary)
Every one of the seven handlers does, in effect:
_response = "A2WaspDatabase" callExtension format ["%1,%2", _procedureCode, _parameters];
_response = call compile _response; // <-- executes the DLL's stdout as SQF
_responseCode = _response select 0;(callDatabaseStore.sqf, callDatabaseRetrieve.sqf ×2 incl. the 505 poll, callDatabaseSendPlayerList.sqf, callDatabaseRequestSideTotalSkill.sqf ×2, callDatabaseSetMap.sqf, callDatabaseStoreSide.sqf, callDatabaseFlushPlayerList.sqf.)
callExtension returns a string from a native DLL, and the mission compiles+executes it. The server therefore fully trusts the A2WaspDatabase process's stdout as code. Why this matters:
- Compromise/replacement/bug → server RCE. Any DLL that returns SQF other than the expected numeric array literal runs on the server. The DLL is third-party and absent from the repo, so its behaviour can't be audited here.
-
Malformed/empty return → error cascade. If the DB is down/slow/encoding-broken,
callExtensionreturns""→call compile ""isnil→nil select 0throws. Several handlers only guardtypeName _responseCode == "SCALAR"after theselect 0, so the select can throw first. - Echo-to-code latent risk. Only UID/score/side/map round-trip today (all constrained, low risk). But the pattern means any future free-text field persisted and echoed back becomes executable.
Engine caveat (why the pattern exists): Arma 2 OA 1.64 has no parseSimpleArray (that is Arma 3), so call compile is the idiomatic string→array path for extensions. The A2-correct hardening is defensive validation, not a parser swap:
- Guard the raw string first:
if (isNil "_response" || {_response isEqualTo ""}) exitWith { /* neutral fallback + WARNING */ }; - Compile, then shape-check before use:
_response = call compile _response; if (typeName _response != "ARRAY") exitWith {...}; if ({ typeName _x != "SCALAR" } count _response > 0) exitWith {...}; - Only then read
_response select 0/1/2. This keeps the DLL contract (numeric arrays) but refuses to execute anything that isn't one.
callDatabaseRetrieve.sqf polls the 505 procedure up to 120 × 0.10s ≈ 12s; callDatabaseRequestSideTotalSkill.sqf polls 707 up to 9 × 3s = 27s. These feed player-connect stat retrieval and team-skill balancing (called from mainLoop.sqf, getTeamScoreMonitor.sqf, Init_Server.sqf). They run in spawned scripts so the server tick survives, but a slow/down DB stalls join/balance up to those windows before falling back to neutral ([1,1] / 0). Recommend a shorter ceiling + a circuit-breaker that flips WFBE_C_ANTISTACK_ENABLED off after N consecutive timeouts.
callDatabaseSendPlayerList.sqf packs every player's guid,side pair into a single callExtension input string (g1,1,g2,2,…). Arma 2 OA callExtension has input/output length limits (output historically ~10 KB); a 55-slot roster can produce a long argument and an even longer response, risking truncation → call compile of a truncated array literal → parse error (compounding DR-7). Recommend chunking the player list across multiple calls and validating each response shape.
WFBE_C_ANTISTACK_ENABLED defaults to 1 (Init_CommonConstants.sqf:171), and the A2WaspDatabase DLL is an undocumented external runtime dependency absent from the repo. Any server/dev instance lacking the DLL gets callExtension→""→call compile→error per call unless the param is set to 0. Marty added per-call if (… == 0) exitWith disable guards (good), but the default is on. Recommend: document the external dependency in External integrations, and consider detecting DLL presence (a cheap PING procedure) to auto-disable rather than error.
Code owners: apply DR-7 defensive validation (guard empty + shape-check before reading) to all seven callDatabase*.sqf; add a circuit-breaker (DR-8); chunk SEND_PLAYERLIST (DR-9); document/auto-detect the external DLL (DR-10). Codex: the A2WaspDatabase external dependency + call compile trust contract should be called out in the External integrations page (its lane). Ledger: Integrations Auth/PV cells advanced from ⬜ to 🟡 (AntiStack covered; Extension/Discord/BattlEye still pending).
Lane victory-endgame-review. Source: Server/FSM/server_victory_threeway.sqf (the only script that sets gameOver/WFBE_GameOver/failMission — verified by grep across Server/), Server/Functions/Server_LogGameEnd.sqf, Server/PVFunctions/LogGameEnd.sqf, Common/Init/Init_CommonConstants.sqf:401.
DR-11 — Endgame reports the winner inconsistently; persisted win-tally is wrong for the all-towns win — Medium-High (correctness, persistent side effect)
The trigger merges a lose test and a win test into one condition and then handles both identically:
if (!(alive _hq) && _factories == 0 || _towns == _total && !WFBE_GameOver) then {
[nil,"HandleSpecial",["endgame",(_x) Call WFBE_CO_FNC_GetSideID]] Call WFBE_CO_FNC_SendToClients;
WF_Logic setVariable ["WF_Winner", _x];
gameOver = true; WFBE_GameOver = true;
_side = west; if (_x == west) then {_side = east};
[_side] call WFBE_CO_FNC_LogGameEnd; // Server_LogGameEnd: _this select 0 == WINNER
}SQF precedence (&& before ||) parses this as (!alive _hq && _factories==0) || (_towns==_total && !WFBE_GameOver):
-
Branch A —
_xHQ dead and no factories →_xis the loser.LogGameEnd(_side = opposite of _x)records the correct winner. ✓ -
Branch B —
_xholds all towns →_xis the winner. ButLogGameEndis still called with_side= opposite of _x → it records the loser as the winner in the persisted%1_WIN_CHERNARUSprofileNamespace tally. ✗
Consequences:
- The win/loss statistics saved via
WFBE_CO_FNC_LogGameEnd(→profileNamespace,saveProfileNamespace) are inverted for every all-towns victory. -
WF_Logic setVariable ["WF_Winner", _x]is a dead write —WF_Winnerhas no reader anywhere in the mission (grep). So it can't compensate. - The
endgameclient broadcast sends_x's sideID toWFBE_CL_FNC_EndGame(HandleSpecial.sqf:16) for both opposite scenarios, so the player-facing outro shows the same side regardless of who actually won — at least one path is wrong. (Follow-up: confirm whether EndGame treats the payload sideID as winner or loser.) -
Guard/precedence bug:
!WFBE_GameOverguards only the towns branch, and theforEachover sides has no break after settinggameOver. Branch A is unguarded, so if two sides both satisfy "HQ dead + no factories" in the same 80s tick, endgame fires twice (doubleendgamebroadcast, doubleSET_MAP, doubleLogGameEnd). Fix: guard both branches with!WFBE_GameOver(orexitWithafter the first winner) and split the win/lose logic so the winner is computed correctly per branch.
WFBE_C_VICTORY_THREEWAY defaults to 0 (Init_CommonConstants.sqf:401, comment "0: Side a vs Side b [supremacy] minus defender"), and the detection block is gated if (!gameOver && _victory == 0). Since server_victory_threeway.sqf is the only victory/failMission setter in Server/, selecting any non-zero WFBE_C_VICTORY_THREEWAY value disables victory detection entirely — matches never auto-end in the mode the file is named for. Either implement the threeway path or document the parameter as non-functional.
-
Server/Functions/Server_LogGameEnd.sqf— clean; wired toWFBE_CO_FNC_LogGameEnd(compiled twice,Init_Server.sqf:64and:89). -
Server/PVFunctions/LogGameEnd.sqf— buggy duplicate:profileNamespace setVariable [(profileNamespace getVariable format ["%1_WIN_CHERNARUS",_winnerTeam]), (...)]uses a getVariable result as the setVariable key, and readsprofileNamespace getVariable WEST_WIN_CHERNARUS(bare global, not the"WEST_WIN_CHERNARUS"string). If this variant is ever wired in, win-stat persistence silently corrupts. Recommend deleting the duplicate to prevent future mis-wiring.
Code owners: fix DR-11 (split win/lose branches, compute winner per branch, guard both branches / break the loop) — this corrects permanently-skewed win stats; decide DR-12 (implement or document-as-disabled threeway); delete the buggy PVFunctions/LogGameEnd.sqf (DR-13). Follow-up review item: WFBE_CL_FNC_EndGame payload semantics (winner vs loser sideID). Ledger: Victory/endgame Map/Auth/PV/Perf cells advanced.
Lane factory-purchase-authority. Builds on Codex's Factory and purchase systems atlas (which noted player buy is client-local with no RequestBuyUnit PVF) and adversarially verifies Cicero's flagged Server_AssignNewCommander candidate. All claims verified at source.
DR-14 — Player unit purchasing has no server authority (the economy ceiling) — High (gameplay integrity), architectural
The player buy path never contacts the server:
-
Client/GUI/GUI_Menu_BuyUnits.sqf:102,108check funds client-side;:155-156do_params Spawn BuildUnit; -(_currentCost) Call ChangePlayerFunds;. -
Client/Functions/Client_BuildUnit.sqf:217/249/…create the unit/vehicle directly on the buyer viaWFBE_CO_FNC_CreateUnit/WFBE_CO_FNC_CreateVehicle(enginecreateUnit/createVehicle). There is noRequestBuyUnitPVF (confirmed: not inInit_PublicVariables.sqf, noServer/PVFunctions/RequestBuyUnit.sqf). - Funds live in
wfbe_fundson the team group, written byCommon_ChangeTeamFundswithsetVariable [..., true](broadcast, client-writable — see Round 1 / DR-6 root cause).
So a modified client can mint any factory unit for free (skip the deduction, or set wfbe_funds directly) — and the created vehicle is globally synced because client createVehicle in MP is global. This is the ceiling on the DR-1/DR-6 hardening thread: unlike construction (DR-6, which at least routes through a server PVF that could be validated), the player economy and unit production are architecturally client-authoritative in WFBE's locality model. Fully fixing it = a large redesign (route purchases through a validated server PVF like construction). The realistic live-server defense is a BattlEye script filter (scripts.txt) constraining client createVehicle/createUnit, not a publicVariable filter. Document this ceiling so future hardening targets the right layer.
Latent path note (confirms atlas):
Server_BuyUnit.sqf/AIBuyUnitis compiled (Init_Server.sqf) but has no proven dynamic caller — the AI-commander production path that would use it is itself dormant (the AI commander FSM never starts; see Cicero's server atlas + DR-15 neighbourhood).
Adversarial verification of Cicero's candidate — confirmed live by tracing compile + sole caller:
-
Init_Server.sqf:62:WFBE_SE_FNC_AssignForCommander = Compile … "Server\Functions\Server_AssignNewCommander.sqf". - Sole caller
Server/PVFunctions/RequestNewCommander.sqf:13:[_side, _assigned_commander] Spawn WFBE_SE_FNC_AssignForCommander;(a 2-element array). -
Server/Functions/Server_AssignNewCommander.sqf:3:_side = _this;— sets_sideto the whole array[side, commander](should be_this select 0), then_commander = _this select 1(correct)._logic = (_side) Call WFBE_CO_FNC_GetSideLogicthen receives an array, not a side → wrong/objNulllogic → the block that stops the AI-commander FSM (_logic getVariable "wfbe_aicom_running") operates on a bad logic and fails.
Impact: when a human is assigned commander via RequestNewCommander, the AI-commander shutdown path mis-fires (mitigated in practice because the AI-commander FSM is itself dormant — DR-14 note). There's also a redundant new-commander-assigned broadcast (sent by both RequestNewCommander.sqf and Server_AssignNewCommander.sqf). Fix: _side = _this select 0;. One-line change in Chernarus source.
Code owners: (DR-14) decide whether to route player purchases through a validated server PVF (large) or accept client-authority + add a BattlEye scripts.txt filter; (DR-15) one-line fix _side = _this select 0 in Server_AssignNewCommander.sqf and drop the duplicate new-commander-assigned broadcast. Ledger: Factory/purchase Auth/PV advanced; AI-commander caveat cross-linked.
Lane ui-hud-authority-review. Cross-checks Codex/Curie's Client UI systems atlas and reviews the economy-menu sale authority (the DR-6/DR-14 sibling). Verified at source.
Client/GUI/GUI_Menu_Economy.sqf:104-152 (MenuAction 105, "Sell Building"):
- The commander check is client-side only (
_isCommanderviacommanderTeam == group player,:107-109). - It picks the closest own-side structure (
GetSideStructures,:110-112), then in a spawned thread credits the refund client-side —ChangeSideSupply(broadcast, client-writable) orChangePlayerFunds(:141) — and destroys the structure client-side with_closest setDammage 1(:152), which propagates globally because the structure is a synced object. - No server PVF, no server validation (same pattern as DR-6 construction and DR-14 purchasing). A modified client bypasses the commander gate and the
WFBE_SOLDre-sell guard, mints the refund, and demolishes structures. Same client-authority ceiling: the realistic defense is a BattlEyescripts.txtfilter constraining clientsetDammage/funds writes, or routing sell through a validated server PVF (matches the DR-6 fix shape). This completes the economy picture: build (DR-6), buy (DR-14), and sell (DR-16) are all client-authoritative.
DR-17 — Duplicate dialog IDD 23000 (EASA vs Economy) — Low-Medium (UI correctness) — confirms Curie candidate
Rsc/Dialogs.hpp: class RscMenu_EASA (:3209, idd = 23000 at :3211) and class RscMenu_Economy (:3287, idd = 23000 at :3289) share the same display id. findDisplay 23000 is therefore ambiguous, and any control-event/closeDialog/findDisplay 23000 logic can target the wrong dialog if both are reachable. Verified Curie's flagged candidate at source. Fix: give EASA and Economy distinct IDDs (and audit any findDisplay 23000 callers). Also re-confirmed Curie's note that other UI candidates (stale RscMenu_Upgrade → missing GUI_Menu_Upgrade.sqf; suspect RscClickableText.soundPush[]) remain open for a UI-focused follow-up.
Code owners: (DR-16) move sell authority/refund/destruction server-side (mirror the DR-6 server-PVF validation) or add a BattlEye scripts.txt filter; (DR-17) assign distinct IDDs to EASA/Economy dialogs. Ledger: UI/HUD Auth/PV advanced; economy thread (build/buy/sell) now fully characterized.
Lane server-loop-candidates-verify. Adversarial verification of two Cicero candidates from the Server gameplay runtime atlas; both confirmed at source with exact impact.
DR-18 — Supply-mission cooldown key casing mismatch → nil-throw on first check — Medium (correctness) — confirms Cicero
setVariable/getVariable keys are case-sensitive in Arma 2 OA (unlike SQF identifiers). The seed and the readers disagree by one letter:
-
Common/Init/Init_Town.sqf:35:_town setVariable ["lastSupplyMissionRun", 0];— lowercasel. -
Server/Module/supplyMission/isSupplyMissionActiveInTown.sqf:8:getVariable "LastSupplyMissionRun"— capitalL. Same capital form is written bysupplyMissionStarted.sqf:8andsupplyMissionActive.sqf:6.
So the 0 seed lands in a slot nothing reads, and "LastSupplyMissionRun" is nil until the first mission completes. The cooldown check then runs:
if (((_lastActivationTime + WFBE_CO_VAR_SupplyMissionRegenInterval) > time) && (_lastActivationTime != 0)) then {...}On a never-run town _lastActivationTime is nil → nil + interval throws ("Type Nothing, expected Number"), aborting the handler before it publishes WFBE_Server_PV_IsSupplyMissionActiveInTown — so the client's cooldown query can get no response on first use. The mis-cased seed defeats exactly the != 0 guard it was meant to satisfy. Fix: make the seed key "LastSupplyMissionRun", or read with a default: getVariable ["LastSupplyMissionRun", 0].
DR-19 — Hosted/listen-server FPS publishers busy-loop — Medium (performance, non-dedicated) — confirms Cicero
Both server FPS publishers put sleep 8 inside the isDedicated guard:
// Server/GUI/serverFpsGUI.sqf AND Server/Module/serverFPS/monitorServerFPS.sqf
while {true} do { if (isDedicated) then { …; publicVariable …; sleep 8; } };On a dedicated server this is fine. On a hosted/listen server or singleplayer host (isServer true, isDedicated false — and both scripts are launched server-side from Init_Server), the if is false every iteration, so while {true} spins with no sleep → a tight CPU busy-loop per script (two of them), degrading the host. Fix: either if (!isDedicated) exitWith {} at the top (don't publish FPS when hosted), or move sleep 8 outside the if so the loop always yields. (Two scripts publishing the same round diag_fps under different PV names — SERVER_FPS_GUI / WFBE_VAR_SERVER_FPS — is also redundant; consolidating would remove one loop entirely.)
Code owners: (DR-18) align the supply-cooldown key casing (or default the read) — one-line fix; (DR-19) hoist the FPS-loop sleep out of the isDedicated guard (or early-exit when not dedicated), and consider consolidating the two redundant FPS publishers. Ledger: Supply JIP/HC and server-runtime perf cells advanced.
Lane jip-headless-crosscut. Traced HQ-death detection across server, existing clients and JIP clients.
DR-20 — HQ-killed is processed once per owning-side client (no idempotency) — High (multiplayer correctness / score exploit)
Death detection for the mobile HQ is deliberately redundant (a client-local vehicle's Killed EH must run on a client):
-
Server/Construction/Construction_HQSite.sqf:89adds a server-sideKilledEH, then:91broadcasts["set-hq-killed-eh", _mhq]to the whole owning side;Server_MHQRepair.sqf:37,43do the same after a repair. -
Client/PVFunctions/HandleSpecial.sqf:34(set-hq-killed-eh) makes every owning-side client add aKilledEH that calls["RequestSpecial",["process-killed-hq",_this]]. - JIP clients additionally add it themselves at
Client/Init/Init_Client.sqf:500-503(guarded!isServer && !_isDeployed).
So N owning-side clients each hold the same Killed EH. When the HQ dies, the synced death fires every client's EH → the server receives N process-killed-hq messages → Server/Functions/Server_OnHQKilled.sqf runs N times, and it has no idempotency guard. Each run:
- awards the killer score twice (
_points = 30000/100*coefand_score = 900via twoRequestChangeScore), so total killer score ≈ 2N × the intended award; - broadcasts N× destruction /
HeadHunterReceiveBountymessages; - re-publishes
IS_<side>_HQ_ALIVE/ marker infos N times.
(The dead-MHQ wreck spawn is inside if (GetSideHQDeployStatus) and self-limits after the first run flips wfbe_hq_deployed=false; the score/message duplication does not.) On a populated server (e.g. 20 owning-side players) an HQ kill inflates the killer's score ~40×. Fix: make Server_OnHQKilled.sqf idempotent — first line if (_structure getVariable ["wfbe_hq_killed_done", false]) exitWith {}; _structure setVariable ["wfbe_hq_killed_done", true];. Keep the redundant EH registration (it ensures death is never missed regardless of MHQ locality); guard the consumer, not the producers. Pattern: "detect redundantly, act once."
- The JIP guard at
Init_Client.sqf:500(!_isDeployed) is correct: a JIP client adds the mobile-HQ EH only when the HQ is currently mobile; a deployed HQ (building) is covered by the server-side EH atConstruction_HQSite.sqf:36/Init_Server.sqf:319. JIP HQ-death detection is therefore covered — the defect is downstream duplication (DR-20), not a JIP miss. -
set-hq-killed-ehis side-filtered (SendToClients [_side, …]), so only owning-side clients register it — correct.
Code owners: add the one-line idempotency guard to Server_OnHQKilled.sqf (DR-20) — this also fixes the duplicate-score symptom on HQ kills in populated games. Ledger: JIP/HC cells advanced for victory/economy/construction (HQ-death path verified end-to-end).
Lane headless-disconnect-review. Verifies the round-1 hypothesis about HC disconnect at Server/Functions/Server_OnPlayerDisconnected.sqf.
Round 1 listed, as an unverified gotcha, "HC disconnect orphans units it created." Verified at source, that framing is wrong and is hereby downgraded: in Arma 2 OA, when any machine disconnects the engine migrates its local objects/groups to the server (ownership transfer, not deletion). HC-delegated AI is therefore not orphaned or lost on disconnect. The accurate effects are below (DR-21).
DR-21 — HC disconnect dumps delegated AI on the server with no re-delegation — Medium (performance/operational, non-data-loss)
Server_OnPlayerDisconnected.sqf HC handling:
- If
WFBE_C_AI_DELEGATION == 2andWFBE_HEADLESS_<uid>exists, it removes the HC's group fromWFBE_HEADLESSCLIENTS_IDand clearsWFBE_HEADLESS_<uid>. -
WFBE_JIP_USER<uid>is nil for an HC (HCs don't register as players viaRequestJoin), so the handlerexitWiths before the player-team/unit logic. (It does also delete anyWFBE_CLIENT_<uid>_OBJECTSregistered to that uid earlier in the handler.)
What actually happens to the AI the HC was simulating: the engine transfers those units/groups to the server, so the server's load spikes by exactly the amount the HC was offloading — the opposite of the delegation benefit, precisely when you least want it. There is no re-delegation: the disconnect handler does not hand the migrated AI to a surviving HC, and (per the round-1 init finding) WFBE_C_AI_DELEGATION is only evaluated/downgraded at boot, so a later HC reconnect does not resume offloading either. Net: HC delegation has no failover/rebalancing — a single HC drop silently re-loads the server for the rest of the match. Suggested handling: on HC disconnect, if other HCs remain, re-setGroupOwner the migrated town-AI groups to a surviving HC (a periodic rebalancer is cleaner than doing it in the disconnect handler); and make delegation re-evaluate when an HC (re)connects rather than only at boot. (Arma 2 OA does support setGroupOwner; note the mission currently never uses it — see AI, headless and performance.)
Code owners: treat HC delegation as best-effort with no failover today; if HC stability matters, add re-delegation/rebalancing on HC disconnect/connect. Ledger: AI/Headless JIP/HC cell advanced; round-1 "orphan" hypothesis corrected.
Lane side-supply-delta-verify. Confirms + sharpens Faraday's "negative side-supply delta" candidate (and my round-1 "inverted guard" note) at source.
DR-22 — Overspending side supply grants a windfall instead of being floored — High (economy correctness/exploit)
The supply clamp (live in Server/Functions/Server_ChangeSideSupply.sqf, both the wfbe_supply_temp_west and …_east handlers; also present but dead in Common/Functions/Common_ChangeSideSupply.sqf) is:
_change = _currentSupply + _amount;
if (_change < 0) then {_change = _currentSupply - _amount}; // intended floor-at-0; actually a windfall
if (_change >= _maxSupplyLimit) then {_change = _maxSupplyLimit};_amount is signed — deductions are negative. When a deduction would overdraw (_change < 0), the "floor" computes _currentSupply - _amount = _currentSupply + |amount|. Example: supply 100, spend 300 (_amount = -300) → _change = -200 → guard → 100 - (-300) = 400. Trying to spend more supply than you have increases your supply by the amount you tried to spend. Any over-budget supply deduction (e.g. an upgrade/structure costing more than the side holds) flips into a gain — directly exploitable by attempting over-large spends, and it corrupts the economy generally.
Fix: floor correctly — if (_change < 0) then {_change = 0};. Apply in Server_ChangeSideSupply.sqf (both handlers). Note the matching block in Common_ChangeSideSupply.sqf is dead code: it computes _change but the function sends only [_side, _amount, _reason] over wfbe_supply_temp_<side> and the server recomputes — so fix the server copy (and optionally delete the dead client computation). Related (round-1, still open): there is no resistance-side handler for wfbe_supply_temp_*, only west/east.
Code owners: one-line floor fix in Server_ChangeSideSupply.sqf (×2 handlers) — closes the overspend windfall. Ledger: Economy/supply Auth/PV reinforced (confirmed exploit, not just "confusing").
Lane upgrade-authority-verify. Confirms Faraday's "upgrade authority gap" candidate and closes the economy-authority thread.
DR-23 — Upgrade purchasing is client-authoritative with no server validation — High (economy integrity)
Server/PVFunctions/RequestUpgrade.sqf is the whole handler: _this Spawn WFBE_SE_FNC_ProcessUpgrade; — the raw client payload [side, upgradeId, level, isPlayer] goes straight into Server/Functions/Server_ProcessUpgrade.sqf, which:
- reads
_side/_upgrade_id/_upgrade_level/_upgrade_isplayerfrom the client with no checks (no commander check, no side check, no upgrade-sequence/level check, no dependency/_LINKScheck); -
never deducts a cost — it only
sleeps_upgrade_timethen_upgrades set [_upgrade_id, current+1]. The upgrade cost is deducted client-side in the upgrade menu before the request, same as the rest of the economy.
So a modified client can forge ["RequestUpgrade",[side, id, level, false]] to grant any side a free upgrade, bypassing commander authority and cost. Secondary: _upgrade_time = (… select _upgrade_id) select _upgrade_level uses client-controlled indices → out-of-range error (minor DoS) if forged with bad ids. Fix: validate in RequestUpgrade/ProcessUpgrade — requester is the side's commander, indices in range, dependencies met and the level is the correct next step, and deduct cost server-side (mirror the DR-6 validation shape).
This is the last economic action to review, and it confirms the pattern: the entire WFBE player economy is client-authoritative —
- build structures (DR-6), buy units (DR-14), sell structures (DR-16), change side supply (DR-22, plus the overspend-windfall bug), buy upgrades (DR-23) — each lets the client decide/deduct, with the server doing at most a class-exists check.
One owner decision covers all of it: either route economic mutations through validated server PVFs (server checks commander/side/funds and applies the debit), or accept client authority and rely on BattlEye scripts.txt/PV filters. Piecemeal fixes won't close the class; the decision is architectural.
Code owners: add commander/funds/index/dependency validation + server-side cost to the upgrade path (DR-23); and make the economy-authority decision once for build/buy/sell/supply/upgrade rather than per-finding. Ledger: economy thread fully reviewed (Auth across the board characterized).
Lane missing-reference-inventory. Confirms Curie's RscMenu_Upgrade candidate at source (a representative dead/abandoned reference).
Rsc/Dialogs.hpp:2425 class RscMenu_Upgrade has onLoad = "_this ExecVM ""Client\GUI\GUI_Menu_Upgrade.sqf""" (:2428), but Client/GUI/GUI_Menu_Upgrade.sqf does not exist — only the differently-named Client/GUI/GUI_UpgradeMenu.sqf does. RscMenu_Upgrade is never opened (createDialog/cutRsc for it appears nowhere outside Dialogs.hpp); the live upgrade UI is GUI_UpgradeMenu.sqf (reached via GUI_Menu.sqf). So this is a stale dialog whose onLoad would ExecVM a missing file if it were ever opened — currently inert because nothing opens it. Fix: delete RscMenu_Upgrade (and its dangling onLoad), or repoint it at GUI_UpgradeMenu.sqf if it was meant to be the live one. Naming-drift class (GUI_Menu_Upgrade vs GUI_UpgradeMenu).
Method note: an automated "live reference → missing file" scan was attempted but its Windows-backslash path normalization was unreliable (false positives); this finding was confirmed by hand. A robust missing-reference inventory is a good future tooling task (resolve
\-separatedexecVM/ExecFSM/preprocessFilestring targets against the tree, excluding commented lines) — handed to Codex/tooling.
Code owners: remove or repoint the dead RscMenu_Upgrade dialog (DR-24). Tooling (Codex/Meitner lane): build a reliable missing-reference scanner. Ledger: UI dead-reference candidate confirmed; abandoned-code inventory still has open candidates (TaskSystem, old blink loops, WASP OnArmor/KeyDown — see round-1 WASP-Overlay + Feature-Status).
Lane ui-followups-verify. Confirms Curie's last two UI candidates at source; closes the UI follow-up items.
Rsc/Titles.hpp: class RscOverlay (:46) and class OptionsAvailable (:165) both declare idd = 10200. Titles are shown via cutRsc/titleRsc (addressed by class name, so the collision is less damaging than the dialog dup in DR-17), but any code that does findDisplay 10200 / uiNamespace lookups on that id is ambiguous. Assign distinct IDDs. (Sibling of DR-17's idd=23000 dialog dup.)
Rsc/Ressources.hpp:556 class RscClickableText has soundPush[] = {, 0.2, 1}; — the first array element (the sound file) is empty/missing (a leading comma). The correct empty-sound form is {"", 0.2, 1} (as used at Ressources.hpp:92); the line-556 form is a malformed config array. RscClickableText is a base control class used widely, so the defect propagates to inheritors. Fix: soundPush[] = {"", 0.2, 1}; (or a real sound macro like the adjacent soundEscape[] = {WFBE_SoundEscape,0.2,1}).
Code owners: assign distinct IDDs to RscOverlay/OptionsAvailable (DR-25a); fix the malformed RscClickableText.soundPush[] (DR-25b). Both Low. Ledger: UI follow-up candidates (title 10200, soundPush) now confirmed — UI cell's documented candidates are closed.
Lane external-research-integration. Steff supplied three deep-research PDFs (also given to Codex). I read two in full (Diepgaande analyse, Analyse van); the third is the same genre. Provenance check: their citations are raw.githubusercontent.com/wiki/rayswaynl/... pages + Miksuu upstream blobs — i.e. they were generated from this wiki (plus upstream as a line-level proxy), so they are downstream corroboration, not independent source verification.
The reports independently re-derive, and rate as top risks, exactly our spine: the Call Compile PVF trust boundary (DR-1) with the BattlEye kickAFK-only filter, construction client-authority (DR-6), callExtension/external-trust (DR-7), the UpdateSupplyTruck config-gated latent breakage (our Feature-Status sharpening), the town-AI despawn player-vehicle risk (our AI/headless note), the PR#1 Killed-EH leak, and MASH-marker-broken (DR-3). Their recommended fix order (static allow-list dispatch → server-side validation → reduce broadcast/centralize PV → harden callExtension) matches our DR-1/DR-6 playbooks. Our source-verified findings are a superset — the reports do not contain DR-11/15/18/19/20/22/23 (victory winner-inversion, commander-assign bug, FPS busy-loop, HQ-killed N-fold, overspend windfall, upgrade-authority), which required reading the actual .sqf rather than the wiki. Net: external review confirms the map holds up and surfaces nothing higher-severity that we missed in code.
DR-26 — License is custom/proprietary, not OSI (resolves both reports' "license unspecified") — Low (governance)
Both reports marked the license "unspecified" (they only had the wiki, not the repo root). Verified at source: LICENSE.md is a custom proprietary-style license — "Copyright (C) 2016 Spayker / (C) 2025 Miksuu", with contributions becoming the repository owner's property and reuse/distribution restricted to explicitly granted rights. Not MIT/GPL/OSI. Implication: third-party reuse or redistribution is not permitted by default; treat the repo as source-available, not open-source.
-
Discord sample metadata:
DiscordBot/preferences_sample.jsonships a concreteGuildID(440257265941872660),AuthorizedUserIDs, andDataSourcePath C:\a2waspwarfare\Data;FileConfiguration.cshas the same hardcoded fallback path. No committed token (good), but neutralize the sample identifiers / move to env-based config. (Codex/owner lane — DiscordBot is outside the Chernarus mission.) -
No CI/tests: confirmed earlier (only
.github/FUNDING.yml). For a heavilypreprocessFile-dynamic SQF codebase + generated targets, add at least SQF-syntax + generated-mission-drift + .NET build checks. (Tooling/Codex lane.)
Owner: the campaign's code findings (DR-1→DR-25) are the actionable core; the external reports add governance items (license clarity now resolved as DR-26; Discord sample hygiene; CI). Codex: fold the governance asks into External-Integrations/Tools-And-Build-Workflow as desired (its lane).
Lane weather-daynight-review. Reviewed Server/Functions/Server_DayNightCycle.sqf (Marty's hybrid accelerated cycle) + the client receiver/animation in initJIPCompatible.sqf:174-210 + Client/Functions/Client_DayNightCycle.sqf + the constants. No defect found — the system is well-designed. Recording the clean result so future passes don't re-review.
Verified:
-
No divide-by-zero in the cycle math.
_twilight_hours_per_second = _day_weighted_hours / (_day_duration_real_seconds * _twilight_weight)—WFBE_DAYNIGHT_TWILIGHT_WEIGHTis a non-zero hardcoded constant (= 3,Init_CommonConstants.sqf:88, not a param), andWFBE_DAY_DURATION's parameter values are{1,30,40,50,60,90,180}(min 1, never 0), so both divisors are always positive. -
Authority model is coherent: the server runs an authoritative accelerated clock via small per-tick
skipTimeand publishes an absolutedate(WFBE_DAYNIGHT_DATE) everyWFBE_DAYNIGHT_SERVER_SYNC_INTERVAL(30 s) for drift correction; each non-dedicated machine animates locally (Client_DayNightCycle.sqf) — consistent withskipTime/setDatebeing local-effect in Arma 2 OA. -
JIP is covered:
WFBE_DAYNIGHT_DATEis engine-synced to joiners, and the init[] Spawn { waitUntil time>0; if (!isNil "WFBE_DAYNIGHT_DATE") setDate WFBE_DAYNIGHT_DATE … }applies the current absolute date on join; live drift resumes on the next 30 s broadcast. Minor, non-defect: a JIP client'sWFBE_DAYNIGHT_DATEPVEH does not fire for the pre-join value (only the variable is synced), so the first drift-correction waits up to one sync interval — acceptable since the initsetDatealready seeds correct state. - The volumetric-clouds force-disable (perf) is documented in AI, headless and performance / Feature status register.
Outcome: weather/day-night cell → reviewed-clean. No handoff required.
Lane modules-review. Reviewed the Client/Module/ set (AFKkick, AutoFlip, CM, CoIn, EASA, Engines, MASH, Nuke, Skill, UAV, Valhalla, ZetaCargo, supplyMission) and Server/Module/. Most are config-gated cosmetic/QoL features (WFBE_C_MODULE_* flags; UAV's _button == 007 branch is comment 'DISABLED' in both uav_interface.sqf:226 and uav_interface_oa.sqf:100 — confirms the Feature-Status "UAV partial" note). The Nuke/ICBM module is the high-stakes one and carries the most severe authority defect found in the campaign.
DR-27 — ICBM nuke is fully client-authoritative; one forged publicVariable = server-applied map-wide kill — Critical (network authority / forgery)
End-to-end chain (all path:line in the Chernarus source mission):
-
Trigger is client-side and client-gated only.
Client/GUI/GUI_Menu_Tactical.sqfMenuAction == 8(the "ICBM Strike" branch, ~:463-505) deducts the fee locally (-_currentFee Call ChangePlayerFunds— itself client-authoritative, the DR-16/DR-23 economy class), spawns the strike-marker object locally ("HeliHEmpty" createVehicle _callPos), andSpawn NukeIncoming. The only ICBM gate is menu visibility (WFBE_C_MODULE_WFBE_ICBM > 0 && !IS_air_war_event,GUI_Menu_Tactical.sqf:253) — module-enable, not the per-side purchasedWFBE_upgrade_…_ICBM, and not a commander check. -
Client asks the server to detonate.
Client/Module/Nuke/nukeincoming.sqf:23:["RequestSpecial", ["ICBM",sideJoined,_target,_cruise,clientTeam]] Call WFBE_CO_FNC_SendToServer; -
Server dispatches with no validation.
RequestSpecialis a registered inbound PVF (Common/Init/Init_PublicVariables.sqf:18); its handlerServer/PVFunctions/RequestSpecial.sqfis literally_this Spawn HandleSpecial;→Server/Functions/Server_HandleSpecial.sqf"ICBM"case (:97-112):-
_base = _args select 2(client-chosen strike-position object),_target = _args select 3(client-chosen object). if (isNull _target || !alive _target) exitWith {}; waitUntil {!alive _target}; [_base] Spawn NukeDammage;-
NukeDammageis server-side (which is why the kill propagates to everyone) and is applied centered on the client-supplied_baseposition with no check that_side/clientTeamowns the ICBM upgrade, that the sender is the commander, or that funds existed.
-
Why the one server-side guard is not a security check. waitUntil {!alive _target} only requires the forger to supply some live object and then end its life — spawn any vehicle, pass it as _target, delete/kill it; or pass any alive object and kill it. It gates timing, not authority.
Impact. Any connected client can hand-craft the publicVariable RequestSpecial = ["ICBM", <anySide>, <objAtChosenPos>, <liveObjThenKilled>, <anyTeam>] and the server applies a map-wide nuke at coordinates of the attacker's choosing — repeatable, no upgrade, no commander role, no real cost. This is the apex of the client-authoritative class (DR-6 build, DR-14 buy, DR-16 sell, DR-22 supply, DR-23 upgrade): same root cause (server PVF handlers trust payload fields without re-deriving authority server-side), but the blast radius is the entire match rather than one player's wallet.
Owner decision (same lever as the economy class, higher priority). Two non-exclusive fixes:
-
Server-side authority in the
"ICBM"case: re-derive the requester from the PV sender, verify_remoteSenderis the commander of_side, verify the side'sWFBE_upgrade_…_ICBMlevel > 0 and a server-tracked cooldown/funds ledger, beforeSpawn NukeDammage. (The same_remoteSender-vs-payload pattern recommended in DR-1/DR-6.) -
BattlEye
scripts.txt/publicvariable.txt: restrict/snapshot theRequestSpecialPV so the"ICBM"selector can't be hand-injected. Defense-in-depth, not a substitute for server validation.
Handoff for Codex: this belongs in the Networking PVF-hazard table and a Feature-Status/atlas note on the Nuke module; the actionable fix is an owner decision shared with the economy-authority item already logged (DR-6/14/16/22/23).
Outcome: modules cell → Auth/PV flipped to the DR-27 finding; rest of Client/Module/ reviewed as config-gated cosmetic/QoL with the UAV-007 branch confirmed disabled.
Lane gear-easa-review. Reviewed the aircraft/vehicle loadout system (Client/Module/EASA/ + Client/GUI/GUI_Menu_EASA.sqf) and the vehicle service point (Client/GUI/GUI_Menu_Service.sqf). Result: gear/rearm is the last untracked tier of the client-authoritative economy class, plus a minor logic inconsistency.
DR-28 — Gear/EASA loadouts and vehicle rearm/repair/refuel/heal are client-authoritative; rearm & refuel skip even the client-side affordability guard — High (economy authority), class-completing
Source-verified:
-
No server PVF for gear at all.
EASA_Equip.sqfapplies the chosen loadout directly to the local vehicle (addWeapon/addMagazine, oraddWeaponTurret/addMagazineTurretfor theAW159_Lynx_BAF) and broadcasts only the setup index (_vehicle setVariable ["WFBE_EASA_Setup", _index, true],:36). There is noSendToServer/RequestSpecialanywhere in the EASA or Service flow (grep-confirmed) — the spend and the effect are entirely client-local. -
EASA cost is a client-side honor check.
GUI_Menu_EASA.sqf:46-50:if (_funds > (_row select 0)) then { … Call EASA_Equip; -(_row select 0) Call ChangePlayerFunds; … }. The price lives in the loadout row ([[Price],[Desc],[Wpn,Ammo]…],EASA_Init.sqf:8), the affordability test runs on the client, and the debit is the client-authoritativeChangePlayerFunds(the DR-16/DR-23 primitive). A modified client equips any loadout without paying. -
Service rearm/refuel deduct with NO affordability guard.
GUI_Menu_Service.sqf: rearm (MenuAction==1,:196-200) and refuel (:217-219) do-_price Call ChangePlayerFunds;unconditionally, thenSpawn SupportRearm/the refuel thread — whereas repair (:206-211,if (_repairPrice > 0)) and heal (:228-230) are guarded. So even a legit client can rearm/refuel into negative/clamped funds, and (as with all of the above) the effect threads run client-side with no server check.
Why it matters. This completes the economy-authority picture. Every WFBE spend path is now source-confirmed client-authoritative: build (DR-6) · buy (DR-14) · sell (DR-16) · supply transfer (DR-22) · upgrades (DR-23) · ICBM superweapon (DR-27) · gear/EASA + vehicle rearm/repair/refuel/heal (DR-28). There is no server-side ledger; ChangePlayerFunds and the can-afford tests are all on the honor system. The rearm/refuel missing-guard is a real but secondary inconsistency — moot against the root issue, since a cheat client bypasses the debit regardless.
Owner decision (same single lever). The one architectural decision already logged for the economy class covers DR-28 too: either (a) move spend authority server-side — a server-validated funds ledger that PVF handlers debit before applying effects — or (b) accept client-authoritative economy and lean on BattlEye scripts.txt to blunt the most trivial money/var edits. No new lever; gear simply joins the list. If (a) is ever scoped, also add the trivial if (_funds >= price) guards to Service rearm/refuel for parity with EASA/repair/heal.
Handoff for Codex: fold DR-28 into the Economy page's "all spend is client-authoritative" note and the gear/loadout atlas; it's the same owner decision, no separate workstream.
Outcome: new ledger row Gear / EASA / vehicle service → Map ✅, Auth ✅ (characterized as client-authoritative, DR-28), PV/JIP-HC 🟡, Drift ⬜; Economy row note extended to name gear as a class member.
Lane extension-globalgamestats-review. Reviewed the in-repo .NET callExtension DLL (Extension/src/**) end-to-end plus its sole SQF caller (Server/CallExtensions/GlobalGameStats.sqf). This is the second extension trust boundary (distinct from the AntiStack A2WaspDatabase DLL reviewed in DR-7..DR-10, which is not in the repo). Net: this one is currently the safe direction, but carries a dormant RCE landmine and an async void reliability bug, and is a write-only/abandoned-refactor stub.
DR-29 — GLOBALGAMESTATS extension: safe today (output discarded), but a dormant deserialization-RCE landmine + async void write race + write-only stub — Medium (latent Critical)
What it is: a one-way telemetry exporter. GlobalGameStats.sqf loops every 60 s (while {true} … sleep 60, execVM'd once from Init_Server.sqf:298) and calls
"a2waspwarfare_Extension" callExtension format ["%1,…,%6","GLOBALGAMESTATS",scoreWest,scoreEast,worldName,uptime,playerCount]. The DLL (ExtensionMethods.RvExtension, the legacy synchronous _RVExtension@12 ABI — correct for A2 OA 1.64; A3's RVExtensionArgs does not exist here) enum-validates the selector, reflection-instantiates GLOBALGAMESTATS (EnumExtensions.GetInstance → Type.GetType("GLOBALGAMESTATS")), stores the args (GameData.Instance.exportedArgs = _args) and serializes GameData to C:\a2waspwarfare\Data\database.json.
Findings (source-cited):
-
No RCE-into-SQF vector — the safe contrast to DR-7.
RvExtension's_outputStringBuilder is never written (grep-confirmed; only the parameter declaration exists atExtensionMethods.cs:12), and the SQF caller invokescallExtensionas a bare statement with no assignment (GlobalGameStats.sqf:22). So the DLL returns an empty string and SQF nevercall compiles anything from it — the exact opposite of the AntiStack DB path (DR-7), where_responseis captured and compiled. Reflection is also constrained:Enum.TryParse(ExtensionMethods.cs:29) gates the selector to theGLOBALGAMESTATSenum beforeType.GetType, so SQF cannot instantiate arbitrary CLR types. -
Dormant deserialization-RCE landmine (Low now → Critical if load is ever enabled). The commented-out load path (
SerializationManager.cs:104-130) usessettings.TypeNameHandling = TypeNameHandling.Auto;withJsonConvert.DeserializeObject<Database>(_json, settings)— the textbook Newtonsoft$typegadget sink. It is inactive today, but the feature cannot actually persist across restarts without a load path (see #3), so a future dev is likely to re-enable it. Ifdatabase.jsonis ever writable by an untrusted process (or replaced), re-enabling load = remote/local code execution on the server host. The active serializer is correctly hardened (TypeNameHandling.None,SerializationManager.cs:33) — the risk is strictly the commented load path. Recommend: delete the dead load code, or if reinstated useTypeNameHandling.None+ a fixed expected type. -
Write-only / abandoned-refactor stub. The active code only ever serializes; the entire deserialize/load path is commented out and references a different type graph (
Database,Leagues.StoredLeagues) than the liveGameDatasingleton — evidence of a half-finished refactor. Consequence: there is no cross-restart persistence today (the DLL never reads the file back), andGameData's only field is[DataMember] public string[] exportedArgs = new string[2](GameData.cs:29) — a stale initializer, since the caller now sends 5 data args (the// Todo: [3] Uptime [4] Player countcomment inGLOBALGAMESTATS.cs:9-11is also stale — both are already wired). Any wiki text implying GLOBALGAMESTATS provides durable stat persistence would be too confident; it currently produces a single overwritten JSON snapshot. -
async void+ unawaited file-create race beforeFile.Replace(Medium reliability).SerializationManager.SerializeDBisasync void; it calls the alsoasync voidFileManager.CheckIfFileAndPathExistsAndCreateItIfNecessary(dbPath, dbFileName)without awaiting (:52), then immediatelyFile.Replace(dbTempPathWithFileName, dbPathWithFileName, null)(:55).File.Replacerequires the destination to exist — on first run (nodatabase.jsonyet) the fire-and-forget create may not have completed, soFile.ReplacethrowsFileNotFoundException. PerBaseExtensionClass(:18-22) that is rethrown asInvalidOperationExceptionout of the synchronous_RVExtension@12call, which can destabilize the calling SQF/game thread; and unobservedasync voidexceptions surface as unhandled exceptions on the .NET threadpool, which can crash the host process. Recommend: make the I/O methodsasync Taskandawaitthem, or do the create synchronously beforeFile.Replace. -
Minor telemetry data-quality bug (SQF side).
GlobalGameStats.sqf:20computes_playerCount = abs(_playerCount - 1)("Exclude headless client"), which assumes exactly one HC is always connected. With 0 HCs it under-reports by 1 (1 real player → reports 0; empty server →abs(0-1)=1reports a phantom player); with 2+ HCs it over-subtracts. TwoWFBE_CO_FNC_LogContentINFORMATION lines per minute (:11"Running with old vars …",:23) also add steady RPT noise. Cosmetic/telemetry-only.
Owner decisions / handoff for Codex. Document GLOBALGAMESTATS in External integrations as a one-way, output-discarded telemetry exporter (explicitly NOT an RCE-into-SQF path, unlike the AntiStack DB), with three concrete code asks for the owner: (a) delete or harden (TypeNameHandling.None) the dead deserialize path before anyone re-enables load; (b) fix the async void create/File.Replace race; (c) optional — correct the abs(playerCount-1) HC heuristic and the stale new string[2]/Todo comments. The Extension DLL is a code artifact, not a wiki page — these are upstream code-owner items, logged here for traceability.
Outcome: Integrations row — Extension sub-target reviewed (DR-29). AntiStack DB (DR-7..DR-10) + Extension (DR-29) now both done; Discord data path + BattlEye scripts.txt/publicvariable.txt posture remain ⬜ within the bundle.
Round 21 — 2026-06-02 (Claude) — BattlEye posture (DR-30) — the "rely on BattlEye" half of every economy/forgery owner-decision is not shipped
Lane battleye-posture-review. Source-verified the repo's entire BattlEye footprint to close a loop the campaign left open across eight prior findings (DR-1 RCE dispatch + DR-6/14/16/22/23/27/28 client-authoritative economy), each of which offered remediation option (b) "accept client authority and rely on BattlEye filters." Confirms — and sharpens — the high-level posture the Codex Gibbs scout reported (Progress-Dashboard.md:23,72), and corroborates the accurate, non-overclaiming wiki text already in place (External-Integrations.md:60, Feature-Status-Register.md:32, Networking-And-Public-Variables.md:122).
DR-30 — As shipped, the BattlEye mitigation is a 22-byte AFK-kick stub: no security PV filter, no scripts.txt at all — option (b) does not exist in the repo — High (live-server hardening gap, campaign-wide)
Source facts (full repo sweep):
- The only BattlEye filter file in the repository is
BattlEyeFilter/publicvariable.txt— 22 bytes, whose entire content is:This is not a security control. The single rule is the AFK-kick feature plumbing itself://new 5 "kickAFK"Client/.../updateclient.sqfintentionally broadcastskickAFKand BattlEye acts on it becauseserverCommandkick paths are unavailable (correctly documented atExternal-Integrations.md:58andNetworking-And-Public-Variables.md:66). There is no default-deny catch-all line (e.g.5 "" !="legitPV1" !="legitPV2" …) and therefore no restriction on any forgery-class PV —RequestSpecial(the DR-27 ICBM vector),RequestStructure/RequestDefense(DR-6),RequestUpgrade(DR-23),RequestNewCommander(DR-15), or the rawServer_HandlePVF/Client_HandlePVFchannels (DR-1). Every dangerous PV passes BattlEye unfiltered. -
scripts.txtis absent (verified by name across the whole repo), as arecreatevehicle.txt,remoteexec.txt,setvariable.txt,setpos.txt,mpeventhandler.txt, etc.scripts.txtis the filter that would blunt the DR-1call compileRCE and script-command injection (createVehicle/setDamage/call compile), so its absence is the more security-relevant gap of the two. - The directory also contains a 716 KB
READ ME FIRST - Using BattlEye filter to auto kick.docx. Per the project's untrusted-content rule it was not parsed (binary Office doc); regardless, the operative deployed artifact is the 22-byte stub, and admin documentation is not a control.
Campaign-wide implication (the point of this pass). The two-option framing in DR-1/6/14/16/22/23/27/28 is misleading as-shipped: option (b) "rely on BattlEye" is not a deployed reality — choosing it means authoring and maintaining a full BE filter set from scratch (a restrictive publicvariable.txt default-deny + whitelist of the legitimate WFBE_PVF_*/direct channels keeping kickAFK, plus a scripts.txt), which is a non-trivial, error-prone, separate workstream for a Warfare mission with hundreds of PVs and easy to break legitimate play. The realistic remediation for the entire forgery/economy class therefore collapses toward (a) server-side authority in SQF (re-derive the requester/role/funds in each PVF handler before applying effects, per DR-1/DR-6), with a real BE filter set as defense-in-depth only if someone owns it.
Honest caveat (do not overstate). BattlEye filter files are normally deployed in the server's BE working directory (the BEpath), outside the mission PBO — so their absence from this repo does not prove the production server lacks them. But the repository, as the campaign's source of truth, ships only the stub; whether ocd-clan.com/Miksuu's live server maintains a fuller filter set is an explicit owner question, not a safe assumption. The wiki should keep stating (as it already does) that PVF spoofing "must not be considered protected by BattlEye."
Owner decision / handoff for Codex. No wiki rewrite needed — the existing BattlEye text is accurate and in-lane for Codex. This finding's value is the cross-link: add a one-line note to the DR-1 remediation playbook and the External integrations BattlEye section that "option (b) requires building the filter set; it is not present in-repo (only the kickAFK stub)," and pose the production-BE-config question to the server owner. Bundle the scripts.txt/server.cfg/basic.cfg absences (also flagged by the Gibbs scout) into the same hosting-hardening owner item.
Outcome: Integrations row — BattlEye sub-target reviewed (DR-30). AntiStack DB (DR-7..DR-10), Extension (DR-29) and BattlEye (DR-30) now done; only the Discord data path remains ⬜ within the bundle. Every prior economy/forgery finding's option (b) is now annotated as "not shipped."
Round 22 — 2026-06-02 (Claude) — Discord data path (DR-31) — the DR-29 deserialization landmine is LIVE in the bot, with TypeNameHandling.All
Lane discord-datapath-review. Reviewed the in-repo DiscordBot/ (.NET / Discord.Net) end-to-end — the consumer side of the GLOBALGAMESTATS extension (DR-29), closing the last Integrations sub-target. The data path is: Arma server → GLOBALGAMESTATS extension writes C:\a2waspwarfare\Data\database.json (DR-29) → DiscordBot reads it on a 60 s timer → posts a game-status embed. Net: secret hygiene is good, the inbound command surface is properly auth-gated, but the deserialization sink I flagged as dormant in the extension (DR-29 #2) is active here, and worse.
DR-31 — DiscordBot deserializes database.json with TypeNameHandling.All on a 60 s timer — live insecure-deserialization gadget sink in the token-holding process — High (insecure deserialization; local-write-gated RCE)
Source-verified:
-
The active load path uses
TypeNameHandling.All.GameData.LoadFromFile()(DiscordBot/src/ExtensionData/GameData/GameData.cs:49-56) buildsnew JsonSerializerSettings { … TypeNameHandling = TypeNameHandling.All … }andJsonConvert.DeserializeObject<GameData>(json, …)on the contents ofdatabase.json.TypeNameHandling.Allhonors$typedirectives for the root and every nested object/array — the canonical Newtonsoft gadget sink (e.g.ObjectDataProvider→ arbitraryProcess.Start). -
It runs automatically every 60 s, no interaction.
GameStatusUpdater(src/GameStatusUpdater.cs:9,19-22,84) arms aSystem.Timers.TimeratUPDATE_INTERVAL_SECONDS = 60withAutoReset = trueand callsLoadFromFile()each tick. Two more live callers:ProgramRuntime.cs:15(startup) andCommandHandler.cs:211(CreateGameStatusEmbed). So the sink is exercised continuously regardless of any auth. -
The capability is gratuitous.
GameData's only state is[DataMember] private string[] exportedArgs(GameData.cs:30) — a flat string-array DTO with no polymorphism. The writer (the extension, DR-29) serializes withTypeNameHandling.Noneand emits no$type. The reader therefore needs.None; requesting.Alladds nothing but the gadget sink. (A second, dead copyGameDataDeSerialization.HandleGameDataCreationOrLoadingusesTypeNameHandling.Auto— no callers, grep-confirmed; should be deleted too.) -
Trigger & blast radius. Not remotely exploitable as-configured:
database.jsonis normally written only by the trusted local extension. But any write-primitive toC:\a2waspwarfare\Data\database.json— a misconfigured ACL/share onDataSourcePath, a malicious mod or compromised Arma process writing there, or a future feature that ingests untrusted data into that file — yields arbitrary code execution in the DiscordBot process, which holds the Discord bot token (→ token theft + full bot/guild control). Classic local insecure-deserialization escalation.
Owner decision / fix (trivial). Change GameData.LoadFromFile() to TypeNameHandling.None (the data is a flat DTO; no behavior is lost) and delete the dead .Auto method. This also retro-closes DR-29 #2: keep the extension's deserialize path .None if it is ever reinstated. Defense-in-depth: lock down the ACL on C:\a2waspwarfare\Data so only the Arma service can write it.
Secondary observations (Low / informational):
-
Secret hygiene is good — resolves the external reports' "Discord sample hygiene" item.
DiscordBot/.gitignoreexcludestoken.txtandpreferences.json;preferences_sample.jsoncontains no token. Minor: the sample commits a real-lookingGuildID(440257265941872660) and oneAuthorizedUserIDssnowflake — these are Discord IDs, not credentials (knowing an admin's user ID grants nothing without being that user), but a sample is cleaner with placeholder zeros. -
Inbound command surface is correctly gated. Slash-command handlers check
Preferences.Instance.IsUserAuthorized(userId)(CommandHandler.cs:49,127) before privileged actions — no missing-authorization finding there. -
Three-way
exportedArgsshape drift (coupling smell). The array isnew string[2]in the extension (DR-29),new string[4]in the bot (GameData.cs:30), while the SQF sender emits 5 data fields and the bot reads index[4]. Held together only by wholesale= _argsreplacement on deserialize + bounds-guards (Length > 4, added after the commented unguardedGetGameMapAndPlayerCountatGameData.cs:138-145). Benign today, but the three sides of the contract disagree on the shape — document the canonical 5-field layout ([0]bluforScore [1]opforScore [2]worldName [3]uptime [4]playerCount) in one place.
Handoff for Codex. Document the Discord data path in External integrations: one-way pull (extension writes JSON → bot reads on 60 s timer → status embed), secret hygiene OK, command surface auth-gated; flag the TypeNameHandling.All fix as the one actionable code-owner item and cross-link DR-29/DR-31. These are code artifacts, logged here for traceability.
Outcome: Integrations row — Discord sub-target reviewed (DR-31); all four sub-targets (AntiStack DB, Extension, BattlEye, Discord) now done. Map cell can move to ✅. The DR-29 deserialization concern is now closed end-to-end (dormant in writer, live in reader, one-token fix).
Round 23 — 2026-06-02 (Claude) — generated-mission drift (DR-32): vanilla faithful, modded forks divergent, 4 modded stubs abandoned
Lane generated-mission-drift-review. Cross-cutting Drift pass: file-set + byte-level comparison of the Chernarus source mission against every generated mission (1 vanilla + 7 modded), to establish whether the DR-1..DR-31 findings (all verified against Chernarus) propagate, and whether LoadoutManager generation introduces divergence. This is the single highest-leverage Drift result — it characterizes the Drift dimension for all subsystems at once.
DR-32 — Generated missions fall into three fidelity tiers; modded missions are divergent forks or abandoned stubs, so source fixes do not propagate to them — Medium (maintainability / drift) + abandoned-code inventory
Method: relative-path file-set comm + per-file cmp of all source .sqf against each generated mission. Results (differing/common .sqf):
| Generated mission | differ/common .sqf | Tier |
|---|---|---|
Missions_Vanilla/…takistan |
15 / 671 | Faithful |
Modded_Missions/…Napf |
123 / 466 | Divergent fork |
Modded_Missions/…eden |
119 / 465 | Divergent fork |
Modded_Missions/…lingor |
104 / 417 | Divergent fork |
Modded_Missions/…smd_sahrani_a2 |
4 / 4 (4 files total) | Abandoned stub |
Modded_Missions/…dingor |
3 / 3 (20 files total) | Abandoned stub |
Modded_Missions/…tavi |
2 / 2 (3 files total) | Abandoned stub |
Modded_Missions/…isladuala |
1 / 1 (1 file total) | Abandoned stub |
-
Vanilla Takistan is a faithful regeneration. Only 15
.sqfdiffer, and all are map-config, not logic: the per-factionCore_Artillery/Artillery_*.sqf,Config_GUE.sqf,GUI_Menu_Help.sqf,WASP/unsort/StartVeh.sqf, andServer/Init/Init_Server.sqfwhose sole diff is one line —["SET_MAP", 1]→["SET_MAP", 2](the AntiStack DB map identifier). Plus textures (US/CDF skins → desert skins) and 3 extra nativeArtillery_{TKA,TKGUE,US}.sqf. All other 656 logic files are byte-identical. → Every DR-1..DR-31 finding propagates verbatim to vanilla Takistan; a fix to the Chernarus source + regen corrects both. The Drift dimension for the source→vanilla path is clean. -
Napf / eden / lingor are heavily divergent full forks. 104–123 of ~465 logic files differ from source — including security-critical files I reviewed:
Server_HandlePVF.sqf(DR-1),Server_HandleSpecial.sqf(DR-27),server_victory_threeway.sqf(DR-11),Server_ProcessUpgrade.sqf(DR-23),Server_OnHQKilled.sqf(DR-20),Server_OnPlayerDisconnected.sqf(DR-21),Init_PublicVariables.sqf,initJIPCompatible.sqf. The divergence is hand-customized behavior, not just config: e.g. Napf'sServer_HandleSpecial.sqf"ICBM" case additionally spawns threeBO_GBU12_LGBlaser-guided bombs around the target (absent in source). This is consistent with DR-4 (modded propagation is commented out atTools/LoadoutManager/.../SqfFileGenerator.cs:132) — the modded missions are not regenerated from source; they are independent forks. Consequence: a fix to the Chernarus source does not reach Napf/eden/lingor; the DR vulnerability classes almost certainly persist there (same architecture) but at different lines/with different effects, so each fork needs its own review and manual fix propagation. -
smd_sahrani_a2 / dingor / tavi / isladuala are abandoned stubs. 1–20 files each (a real mission is ~786 files / ~671
.sqf); they are missingServer/,mission.sqm, theWASP/overlay,description.ext, and essentially all logic. They cannot load as functional Warfare missions. These are incomplete scaffolds committed to the repo — an abandoned-code/inventory item.
Owner decisions / handoff. Three explicit choices for the code owner, all logged for Codex to fold into Tools and build workflow / a generated-mission status table (Codex's lane):
- Stub missions (sahrani/dingor/tavi/isladuala): complete via regeneration or remove them — they are dead weight and misleading as "supported maps."
- Divergent forks (Napf/eden/lingor): pick a maintenance model — (a) re-enable modded propagation (DR-4) and regenerate from the hardened source, accepting loss of the hand-customizations (e.g. Napf's GBU ICBM), or (b) formally treat them as independent forks and apply every DR-1..DR-31 fix to each by hand. Today they silently drift.
- All security fixes: apply to the Chernarus source first (propagates to vanilla Takistan on regen), then deliberately propagate to the 3 forks.
Outcome: Drift dimension characterized across the whole codebase. Source→vanilla path is faithful (DR findings transfer verbatim); modded missions are out-of-scope forks/stubs flagged here. Ledger Drift cells updated to reference DR-32 (faithful-to-vanilla ✅; modded divergence is an owner decision, not a review gap).
Lane factory-perf-jip-review. Filled the two ⬜ cells on the Factory/purchase row by source-reviewing the unit-production path: Client/GUI/GUI_Menu_BuyUnits.sqf (queue gate) → _params Spawn BuildUnit → Client/Functions/Client_BuildUnit.sqf (the production loop), plus the WFBE_C_QUEUE_* counters seeded in Client/Init/Init_Client.sqf. Production runs entirely on the buyer's client (group player, local CreateUnit/CreateVehicle). Two real defects (one JIP/HC, one Perf) plus a network-churn note.
DR-33a — Empty-vehicle purchase leaks the buyer's WFBE_C_QUEUE counter → silent per-factory soft-lock — Medium (JIP/HC / client-state leak)
WFBE_C_QUEUE_<type> is a client-local counter (seeded in Init_Client.sqf:185+, e.g. BARRACKS_MAX=10, LIGHT_MAX/HEAVY_MAX=5). The buy gate increments it before producing and blocks at the cap:
-
GUI_Menu_BuyUnits.sqf:145-146:if (WFBE_C_QUEUE_<type> < WFBE_C_QUEUE_<type>_MAX) then { …+1; _params Spawn BuildUnit }else:158"queue max" hint. -
Client_BuildUnit.sqf:469decrements it at the normal tail of the script.
But the vehicle branch has an early if (!_driver && !_gunner && !_commander) exitWith {} (Client_BuildUnit.sqf:365) — for a crewless vehicle purchase (all crew unchecked, a legitimate option) — which returns before the tail decrement at :469. So each empty-vehicle buy permanently increments the buyer's local queue counter without ever decrementing it. After _MAX such purchases (5 for Light/Heavy) the GUI gate at :145 silently refuses all further production from that factory type for the rest of the match — a slow soft-lock that presents as a mysterious "can't buy / queue full" with nothing actually queued. Reachable in normal play. Fix: move the WFBE_C_QUEUE (and unitQueu, :467) decrements before/around the empty-vehicle exitWith, or restructure so all exit paths decrement (e.g. a single cleanup block).
DR-33b — Per-unit sleep 4 queue poll re-broadcasts the building's queue on every mutation; non-unique queue token — Low/Medium (Perf / network churn + latent correctness)
-
Network churn. Each queued unit gets its own
Spawn BuildUnit, which busy-waitswhile {_unique != _queu select 0 …} { sleep 4; … }(:180-199) and writes_building setVariable ["queu", _queu, true]— a global broadcast — on every enqueue (:172), timeout-advance (:191) and completion (:207). With several factories producing across a full server, every 4 s tick that advances or cleans a queue broadcasts that building's wholequeuarray to all machines. Bounded but avoidable; consider a server-owned queue or a non-broadcast local timer. -
Non-unique token. The per-item identity is
varQueu = random(10)+random(100)+random(1000)(:168) — a ~0–1110 value space, not unique. Two concurrently-queued items can collide on_unique, breaking the_unique != _queu select 0front-of-queue test (an item may wait forever or two may think they're first). Low probability per pair but non-zero on a busy factory. Fix: use a monotonic counter ordiag_tickTime-seeded id. -
Orphan token on disconnect (minor). Because the loop + the front-token removal (
:206) run on the buyer's client, a buyer disconnecting mid-production leaves their_uniquetoken in the building's broadcastqueu; it self-heals only if another buyer is queued behind to run the_ret > _longesttimeout-cleanup (:187-192). The localWFBE_C_QUEUEcounter is not leaked across clients (it dies with the buyer). Stale shared data, low impact.
Handoff for Codex. Document the production queue model in the Factory/purchase atlas: client-owned per-unit producer, broadcast queu token list, per-client WFBE_C_QUEUE caps. The two fixes (DR-33a decrement-on-all-paths; DR-33b unique token + reduce broadcast) are concrete code-owner items, not architectural decisions. Note DR-33a propagates to vanilla Takistan verbatim (DR-32) and likely exists in the 3 forks too.
Outcome: Factory/purchase row — Perf and JIP/HC cells filled (DR-33). The row's remaining 🟡 (Auth/PV) is the DR-14 client-authoritative-purchase architectural ceiling (economy class, owner decision).
Round 25 — 2026-06-02 (Claude) — respawn / MASH markers (DR-34): MASH map-marker feature is dead on both ends
Lane respawn-mash-review. Reviewed the respawn UI (Client/Functions/Client_UI_Respawn_Selector.sqf) and the MASH respawn-marker chain (Server/Module/MASH/MASHMarker.sqf ↔ Client/Module/MASH/receiverMASHmarker.sqf), with wiring confirmed in Init_Client.sqf / Init_Server.sqf. Extends the earlier DR-2 note ("MASH markers are dead receive-side") to a full both-ends diagnosis.
DR-34 — MASH map-marker feature is fully dead (send trigger never broadcast + client receiver commented out); the live server PVEH is orphaned — Low/Medium (broken/abandoned feature; UX)
MASH tents are a real deployable officer feature (Client/Module/Skill/Actions/Officer_Undeploy_MASH.sqf exists), but the map marker that should show a team its MASH locations does nothing, because all three links are broken or orphaned:
-
Client receiver is commented out.
Init_Client.sqf:132://WFBE_CL_FNC_ReceiverMASHmarker = Call Compile preprocessFileLineNumbers "Client\Module\MASH\receiverMASHmarker.sqf";— so no client ever registers theWFBE_SE_MASH_MARKER_SENTevent handler; the receiver inreceiverMASHmarker.sqfis never installed. -
The trigger PV is never broadcast.
WFBE_CL_MASH_MARKER_CREATEDappears in the repo only as the server'saddPublicVariableEventHandlerregistration (MASHMarker.sqf:1). No client deploy path ever doesWFBE_CL_MASH_MARKER_CREATED = […]; publicVariable …, so the server handler can never fire. -
The server handler is live but orphaned.
Init_Server.sqf:70actively compilesWFBE_SE_FNC_MASH_MARKER(=MASHMarker.sqf), registering a PVEH for a PV (WFBE_CL_MASH_MARKER_CREATED) that nothing emits — harmless dead weight that looks active in a grep but does nothing in composition. (Line 92 is a duplicate, commented.)
Net: deployed MASH tents produce no map markers for the owning side. Confirms and extends DR-2.
Latent JIP gap if revived (note for whoever fixes it). Even with both ends re-enabled, the marker is delivered by publicVariable "WFBE_SE_MASH_MARKER_SENT" — a single global overwritten on each deploy (not a list) and not replayed to join-in-progress clients. So a revived feature would: (a) show JIP joiners no markers for MASH deployed before they joined, and (b) only ever carry the most-recent MASH in the synced value. A correct revival needs a server-held list + a JIP re-send on join (the same pattern the construction/HQ-killed code uses via Server_HandleSpecial "set-…" re-sends).
Secondary (Low):
-
Respawn selector is a ~33 Hz local loop.
Client_UI_Respawn_Selector.sqf:19-33runswhile {!isNil 'WFBE_MarkerTracking'} do { sleep 0.03; … }, animating a pulsing local marker (setMarkerDirLocal/SizeLocal/PosLocal) — network-free and bounded to while the respawn UI is open, butsleep 0.03cannot be honored by the SQF scheduler so it effectively runs every frame. Acceptable for a transient UI; flagged for completeness. -
Non-unique marker name (dead code, DR-33b class).
receiverMASHmarker.sqf:12builds the marker name withround random 50000(collision-prone) and later deletes acreateMarkerLocalmarker with the globaldeleteMarker(local/global mismatch). Moot while the receiver is disabled; fix if revived.
Handoff for Codex. Mark the MASH map-marker feature as dead/abandoned in the Feature status register and the relevant marker/respawn docs (Codex's lane), with the revival recipe above (server-held list + JIP re-send + unique names + fix publicVariable JIP gap). Owner decision: revive the feature or remove the dead receiverMASHmarker.sqf + orphaned Init_Server.sqf:70 registration.
Outcome: Markers/respawn — MASH marker chain reviewed (DR-34): dead both ends + orphaned server PVEH; respawn selector Perf characterized. Markers row PV/JIP-HC cells reference DR-34.
Round 26 — 2026-06-02 (Claude) — parameters / localization integrity (DR-35): clean, with 2 dead-action confirmations
Lane params-localization-review. Reviewed the two never-covered cross-cutting areas: localization integrity (do localize/$STR_ references resolve?) and the mission parameters system. Result: localization is clean once case-folding and dead-code are accounted for; the params system is live and correctly wired.
DR-35 — Localization integrity is clean (no live broken strings); parameters system is live and correctly wired; 2 dead WASP actions confirmed — Informational (reviewed clean + abandoned-code)
Method matters (the trap that produces false findings). Arma 2 OA stringtable lookup is case-insensitive, but text-diff tools are not. A naïve case-sensitive set-difference of the 204 static localize "STR_…" keys against the 1289 stringtable.xml keys reports 4 "missing"; after lowercasing both sides it drops to 3, and after checking each reference site for liveness it drops to 0 live bugs:
-
STR_WF_UPGRADE_uav_Desc— false positive (casing): defined asSTR_WF_UPGRADE_UAV_DESC; resolves at runtime. -
STR_EP1_UAV_action_exit(Client/Module/UAV/uav_interface_oa.sqf:25, live) — engine-provided: theSTR_EP1_*namespace is supplied by the Arma 2 OA base game's global stringtable, not the mission; resolves at runtime. -
STR_WASP_actions_OnArmorandSTR_WF_Gear— referenced only in commented-out lines (WASP/actions/AddActions.sqf:4,10-12, the dead "ride-on-armor" and "gear your unit" WASP actions). Dead code; the missing keys are moot.
Config-side $STR_ references in .hpp/.ext (excluding engine STR_EP1_/STR_DN_/STR_USRACT prefixes) all resolve. So no live missing-localization display bug exists. The stringtable carries ~1085 keys not hit by any static localize — a large legacy surface typical of a long-lived WFBE fork, not a defect (some are reached by config $STR_, engine, or removed features).
Parameters system — live and correct. Common/Init/Init_Parameters.sqf iterates missionConfigFile >> "Params" and sets each configName as a missionNamespace variable, taking paramsArray select _i in multiplayer and the param's default in single-player. Wiring confirmed: initJIPCompatible.sqf:121 runs it in MP; the parameter-display dialog is loaded via Rsc/Dialogs.hpp:3136 (onLoad ExecVM GUI_Display_Parameters.sqf), defined in Rsc/Parameters.hpp. This is the canonical A2 OA pattern. One fragility note (not a defect): the paramsArray select _i ↔ Params iteration is index-aligned, so inserting/removing a param without keeping class Params order in sync would silently shift every later parameter's value — worth a comment in the config for future editors.
Abandoned-code inventory (adds to DR-32/DR-34). WASP/actions/AddActions.sqf contains commented-out OnArmor (ride-on-tank: GetOnArmor.sqf/GetOnArmorBots.sqf/GetOutBots.sqf) and GearYourUnit actions — dead WASP features whose localization keys were never added. Confirms the earlier "WASP OnArmor/KeyDown abandoned" suspicion.
Handoff for Codex. Optionally note in the WASP overlay page that AddActions.sqf carries dead OnArmor/Gear actions, and add a one-line "keep class Params order stable (index-aligned to paramsArray)" caution to any parameters documentation (Codex's lane). No code defect to fix; the dead WASP actions are an owner cleanup decision (remove vs revive).
Outcome: parameters/localization reviewed — clean; localization integrity verified (no live broken keys), params system confirmed live/wired, 2 dead WASP actions logged. New ledger row Parameters / localization → reviewed-clean (DR-35).
Round 27 — 2026-06-02 (Claude) — victory/endgame Perf + JIP/HC (DR-36); source mechanism for DR-11/DR-13
Lane victory-perf-jip-review. Filled the Victory/endgame Perf + JIP/HC cells by reviewing the loop in Server/FSM/server_victory_threeway.sqf (the sole victory FSM, execVM'd unconditionally at Server/Init/Init_Server.sqf:528) and the end-of-match DB-flush tail, and traced the win-condition expression to a source-level root cause for the previously-observed DR-11/DR-13.
DR-36 — Victory loop Perf clean + JIP/HC server-authoritative; the win-condition guard/precedence is the source of DR-11/DR-13 double-fire — Low (Perf/JIP clean) + Medium (the confirmed correctness bug)
Perf — clean. The detection loop runs every _loopTimer = 80 seconds (:6,46) with cheap per-side work (GetSideHQ/GetSideStructures/GetTownsHeld + 4× GetFactories, :14-21). No hot loop, no per-frame churn. Minor: _innerTimer is incremented (:47) but never read (dead variable); _miniSleep = 0.05 paces only the one-time end-of-match per-player DB STORE (:60-82). No perf trap.
JIP/HC — server-authoritative, one narrow gap. Detection runs server-only on server-authoritative state; headless clients don't participate (correct). Endgame is pushed to clients via [nil,"HandleSpecial",["endgame", sideID]] Call WFBE_CO_FNC_SendToClients (:24); gameOver/WFBE_GameOver are set server-side (:32-33) and WFBE_GameOver is not broadcast. The only gap: a player joining in the brief endgame window (between the broadcast and failMission "END1" at :88) won't receive the outro, because SendToClients is not replayed to JIP joiners — moot in practice since the mission is tearing down.
Confirmed source mechanism for DR-11 (winner inversion) + DR-13 (duplicate LogGameEnd). The win check (:23):
if (!(alive _hq) && _factories == 0 || _towns == _total && !WFBE_GameOver) then {
By SQF precedence (&& binds tighter than ||) this is ((!alive _hq) && _factories==0) || (_towns==_total && !WFBE_GameOver) — so the !WFBE_GameOver guard covers only the "holds-all-towns" clause, not the "HQ-destroyed elimination" clause. Combined with the enclosing forEach WFBE_PRESENTSIDES - [WFBE_DEFENDER] (:43) having no break/exit after a winner is declared, if two sides are eliminated within the same 80 s tick the elimination clause fires again for the second side: a second ["endgame",…] broadcast, a second WFBE_CO_FNC_LogGameEnd (:41), and WF_Logic setVariable ["WF_Winner", _x] (:31) overwritten with the opposite side (the _side = west; if (_x==west) _side=east swap at :35-39 then logs the inverted winner). That is the exact mechanism behind DR-11's inverted persisted winner and DR-13's duplicate game-end. Fix (one place): parenthesize and guard both clauses with !WFBE_GameOver, and exitWith/break the forEach (and the while) once gameOver is set, so only the first-detected winner is recorded.
Also re-confirms DR-12: the detection block is gated by if (_victory == 0) where _victory = WFBE_C_VICTORY_THREEWAY (default 0). When threeway is enabled (_victory != 0), the entire detection block is skipped and the loop just sleeps — i.e. threeway mode has no victory detection.
Handoff for Codex. This is a code-owner fix already tracked under DR-11/DR-13; this round adds the precise path:line mechanism + the two-part one-line fix. No new wiki page needed — cross-link from the victory rows of Feature status register to DR-36 for the root cause.
Outcome: Victory/endgame row — Perf and JIP/HC cells filled (DR-36): Perf clean, JIP server-authoritative (narrow endgame-join gap noted); DR-11/DR-13 now have a source-level mechanism + fix.
Previous: Agent worklog | Next: Implementation plan
Main map: Home | Fast path: Quickstart | Agent file: agent-context.json
Home | Agent Guide | Current live state | Release 1.2.2 (B91) | Quickstart | Progress | Lifecycle wait-chain | Join/disconnect | Parameters/build | Assets/config | SQF atlas | PV index | Modules | Support/specials | Commander/HQ | Commander vote/reassign | Construction/CoIn | Construction cleanup | WDDM compositions | Factory/purchase | Upgrades/research | Towns/camps/capture | Victory/endgame | Markers/cleanup | Server runtime | AI runtime/HC | AI commander audit | HC delegation | Town AI safety | Commander reassignment | Resistance supply | Player UI workflow | UI atlas | Respawn/death | Gear template filter | Vehicle cargo loop | Service guards | UI IDD repair | UI design inspiration | WASP overlay | Feature status | Source propagation | release readiness | Tooling readiness | Integration trust | AntiStack DB | Owner decisions | Shelved registry | Abandoned feature revival | Hardening roadmap | PVF dispatch | Server authority | ICBM authority | Attack-wave authority | Telemetry families | AICOM V2 cutover | Consumer port map | Testing workflow | Server ops | Web tools | Ecosystem repos | Arma 2 OA refs | A2 traps | OA compatibility audit | Coverage ledger | Navigation inventory | Pruning ledger | Knowledge roadmap | Agent context | Collab protocol | Worklog | Audit archive 2026-07 | Briefing reference | Utes invasion concept
- Shelved AICOM concepts - revivable someday ideas (owner-shelved 2026-07-03)
Docs rule: source-backed claims only; Arma 2 OA scripting docs only; gameplay edits start in Missions/[55-2hc]warfarev2_073v48co.chernarus.
- Getting started
- Status and coordination
- Agent context
- Agent collaboration protocol
- Agent worklog
- Agent worklog archive
- Progress dashboard
- PR cleanup and integration lab
- Shelved PR #169: gear price double-count
- Shelved PR #194: Chernarus no-trees
- Coordination board
- Codebase coverage ledger
- Bottleneck removal queue
- Current source status
- Wiki mirror reconciliation
- Navigation inventory
- Registers
- Agent orchestration
- Architecture
- Architecture overview
- Mission entrypoints and lifecycle
- Lifecycle wait chain
- Player join/disconnect and AntiStack lifecycle
- Mission parameters/localization/build inputs
- Stringtable localization key-family catalog
- Source inventory
- Content structure and maps
- Assets/config/localization/parameters
- Mission start parameters index
- Code and networking
- Gameplay systems
- Content, reference and catalogs
- Faction unit/vehicle roster catalog
- Auxiliary/SF/civilian unit catalog
- Gear store loadout route catalog
- Upgrade research (cross-faction)
- Gear store price and upgrade catalog
- Gear store catalog (complete, per faction)
- Defense structures catalog
- Artillery reference per faction
- AI squad team templates catalog
- Town AI lifecycle reference
- Town AI group composition catalog
- Class-skill system reference
- Player skill abilities reference
- Default gear template content catalog
- Chernarus map content reference
- Takistan map content reference
- Takistan features
- Takistan parity reference
- Takistan oilfields objective reference
- IRS IR-smoke countermeasure
- Arty module special munitions
- Zeta cargo sling-load reference
- Spawn primitive function reference
- Kill and score pipeline
- Waypoint helper function reference
- Position and proximity function reference
- Side/team state function reference
- Player AI watchdog and recovery
- AICOM stuck-recovery v2
- LoadoutManager data-model contributor guide
- Discord status bot setup and reference
- GLOBALGAMESTATS extension reference
- New player quickstart (player guide)
- Optional client mods (player guide)
- Earning funds and score (player guide)
- Vehicle service and logistics (player guide)
- Commander's handbook (player guide)
- Tactical support menu
- Paradrop player experience
- Supply missions (player guide)
- In-game briefing & Diary field manual
- Playable maps catalog
- Faction root variables reference
- Faction base structures catalog
- Counter-battery radar system
- Bank, Reserve and Artillery Radar structures
- Map ruleset model and object config
- Countermeasures module reference
- Vehicle countermeasure (flares/spoofing)
- UAV terminal and spotter system
- Artillery firing function reference
- Service Point pricing model
- Medic redeployment truck (forward spawn)
- Side-patrol runtime and convoy mechanics
- Day/night cycle and weather system
- Config lookup helper reference
- CIPHER sort utilities reference
- Modded maps status and content
- BattlEye filter setup and OA taxonomy
- Player squad/group join protocol
- AutoFlip vehicle recovery
- Engine stealth fuel toggle
- Valhalla vehicle climbing-assist
- Missile and ordnance Fired-EH reference
- Vehicle equip and rearm reference
- Array and collection utilities
- Server composition spawner reference
- Upgrade queue server loop
- Map boundaries and off-map enforcement
- Namespace/profile/diagnostic utilities
- Group bool getVariable A2-OA trap
- Vehicle weapon balance init
- View distance auto-throttle
- Camp & respawn-camp getters
- Performance audit writer
- Site clearance (bulldozer)
- Factory queue cancel & refund
- AI commander tunable constants
- Experimental feature-flag constants
- Flag system quick reference
- Mission tunable constants catalog
- Gear parsing & cargo capacity
- Structure dressing function
- Paradrop delivery functions
- ICBM nuke client VFX & radiation
- Server HandleSpecial router
- LocalizeMessage chat router
- Gear buy-menu render & price functions
- Server broadcast & telemetry loops
- Per-unit client init pipeline
- Vehicle marking & texture pipeline
- Defense category & budget
- Legacy AI order primitives
- Commander-team driver
- AICOM command verbs
- AICOM behavior fix taxonomy
- AI commander wildcard deck reference
- AICOM aircraft and airfield system
- Static-defense manning
- End-of-game stats screen
- AI commander execution loop
- Deployable bipod / weapon resting
- Town-economy getters
- Server-init deadspawn & airfield probe
- GUER VBIED detonate action
- Resource income-tick engine
- AI commander treasury accessors
- PVF send-helper contracts
- AICOM logging & AICOMSTAT telemetry
- AICOMSTAT v2 event census
- WASPSCALE v2 telemetry
- WASPSCALE v2-ext coverage audit
- Telemetry families reference
- Group lifecycle & entity reaping
- Batch AI spawner orchestrator
- Client funds/income HUD readout
- Server group GC & cap warning
- Town runtime tuning constants
- Client input/hotkey handler
- WASP base-repair system
- WASP DropRPG launcher/ordnance
- CoIn construction-interface client engine
- Town-capture garrison & airfield rebuild
- Map-control & minimap templates
- Client FPS & state telemetry
- Client service-proximity getters
- Airfield-exclusive roster & unit hints
- Unit-camera spectator system
- Town-garrison patrol/defense worker
- RequestTeamUpdate squad-discipline
- Arma2Warfare GPT assistant
- LoadoutManager build configs & defines
- GLOBALGAMESTATS extension logging
- Discord bot instrumented logging
- Eden/Everon & Taviana map content
- Cruise missile strike asset
- AI / HC
- AI headless and performance
- AI mods and pathfinding reference
- Headless client scaling and topology
- AI runtime/HC loop map
- Headless client init and stat loop
- HC delegation target selection
- Player AI caps and role balance
- Old WarfareBE FPS comparison
- AI commander autonomy audit
- Upstream BE 2073 AICOM delta
- Parent 2.073 divergence audit
- AI commander capture & fun plan
- AI commander B69 improvement roadmap
- AI commander B69 implementation sketches
- AICOM V2 cutover status
- Headless delegation and failover
- Commander reassignment call shape
- GUER Director living-resistance pitch
- Quality and operations
- Foundation perf findings & Tier-3 dead-ends
- Dead/stale code register
- Commander vote/reassignment
- Attack-wave authority
- Server runtime and operations
- Server ops runbook
- JIP enrollment & client data delivery (b74.2 lessons)
- Server gameplay runtime atlas
- PerformanceAuditAnalyzer
- Performance opportunity sweep
- Documentation plan
- Knowledge platform roadmap
- Wiki quality audit
- Wiki pruning and relevance ledger
- Audit findings queue (2026-06-03)
- Deep review findings
- Client UI / server-loop perf findings
- Performance gain simulation
- Self-host testing field notes
- Cleanup and work lanes
- Hardening and authority
- UI / player workflows
- Client UI, HUD and menus
- UI HUD and dialogs
- Player UI workflow map
- Client UI systems atlas
- UI IDD collision repair
- UI control class library reference
- UI theme palette and style macros
- UI design inspiration 2026-07
- Available-actions client gate FSM
- Gear/loadout/EASA atlas
- Gear template profile filter
- Vehicle cargo equip loop bounds
- Factory and purchase systems atlas
- Service menu affordability guards
- WASP overlay
- Class-skill system reference
- Skin selector and class swap
- Earplugs audio toggle
- Mission audio catalog
- HQ radio knowledge-base catalog
- QoL trio player hints
- Player vehicle/travel actions
- Tooling / release / integrations
- Tools and build workflow
- Warfare web tools
- Ecosystem & companion repos
- Zargabad tooling parity
- July 2026 release readiness
- Operator monitor and CPU affinity tools
- Tooling release readiness audit
- Source fix propagation queue
- Agent release readiness ledger
- Release source intake map
- Testing/debugging/release workflow
- Current RPT release gate
- RPT telemetry consumer port map
- External integrations
- Integration trust boundary audit
- AntiStack database extension audit
- Community & Dev
- Community & Dev
- Miksuu upstream wiki import / archive index
- Upstream changelog feature leads
- Developer history and upstream lessons
- Upstream Miksuu commit intel
- Upstream mining ledger
- Archive script mining v2
- Upstream BE 2073 AICOM delta
- Parent 2.073 divergence audit
- PR8 and Drone upstream lesson match
- Development lessons learned
- External research reports
- Audit archive 2026-07
- Briefing reference
- Utes invasion concept
- Miksuu archive: Home
- Miksuu archive: Welcome
- Miksuu archive: Big announcements
- Miksuu archive: Changelog
- Miksuu archive: Development process
- Miksuu archive: Discord bot
- Miksuu archive: Gameplay videos
- Miksuu archive: LoadoutManager
- Miksuu archive: Chernarus script architecture
- Base-game visual catalogs
- Compatibility and references
- HC upstream history and lessons
- Player stats branch audit
- BuyMenu EASA QoL branch audit
- Perf quick wins branch audit
- Commander positions branch audit
- Zargabad branch audit
- Quad AI Commander concept
- Arma 2 OA external reference guide
- Base-game config & image reference
- Arma 2 OA compatibility audit
- Arma 2 OA agent traps reference
- Arma 2 OA command versions
- Wiki source consistency
- External Arma 2 OA reference index