Faction Architecture Inventory
This inventory captures the active faction boundary for the current pre-alpha faction rollout. It records what exists today, names the temporary compatibility shims, and points later phases at focused checks. It does not define the final faction catalog shape.
Compatibility Boundary
Faction work is pre-alpha and does not preserve compatibility with old replay artifacts, persisted match-history replay payloads, compact snapshot versions, or old protocol payloads. Later phases may break those formats when they add explicit faction identity. Preserve current live gameplay behavior for the existing faction unless a later phase explicitly changes it.
Active Faction Boundary Sources
This document owns the active faction lifecycle taxonomy and the current catalog-id status table.
server/crates/rules/src/faction.rs owns catalog facts, loadouts, and ability availability.
server/src/lobby/faction_validation.rs owns lifecycle admission. docs/design/protocol.md owns
wire vocabulary and payload shapes, and docs/design/server-sim.md owns the Game API and sim
boundary wording.
plans/archive/faction/* files are historical-only evidence from the earlier faction rollout. They
are not active checker inputs and must not be treated as lifecycle policy unless a future plan
explicitly copies a rule back into an active design document. Guard scripts may check that the
archive exists and is named as historical, but they must not read archived phase files as the source
of current faction truth.
Catalog Id Statuses
Lifecycle status is explicit and separate from catalog existence:
playable: allowed in normal product match starts where the owning lifecycle path accepts a playable faction id.playable-human-only: allowed for human selection but not for AI, prediction, or replay-capable starts until those lifecycle paths explicitly opt in. No current catalog id uses this status.test-fixture-only: allowed only by explicit fixture/test contexts and never by normal product selectors or replayable starts.reserved/future: named for future work but not admitted by catalog, lobby, replay, AI, or prediction paths. No current catalog id uses this status.historical-only: retained as archive evidence and never treated as active lifecycle policy.
| Faction id or path | Status | Current lifecycle policy |
|---|---|---|
kriegsia | playable | Default faction for missing non-replay requests. Supported by normal human lobby, quickstart/debug starts, AI seats, dev starts, self-play defaults, replay/branch records, match-history replay, post-match replay, spectator metadata, and local prediction when version/build metadata is compatible. |
ekat | playable | Human-selectable through normal lobby faction selection. Explicit playable validation accepts it for start/replay-capable contexts, and schema-2 replay/branch records may carry it. Public AI seat creation has no faction selector and still defaults to kriegsia; current local prediction is disabled when the local player is ekat. |
phase2_empty_fixture | test-fixture-only | Catalog and loadout exist for explicit Rust/test fixture coverage. It is rejected by normal lobby, quickstart, AI, replay, branch, dev scenario, self-play, match-history, and post-match paths unless the caller uses the TestFixture validation context or a direct lower-level sim test helper that deliberately owns the fixture. |
plans/archive/faction/* | historical-only | Archived phase plans, handoffs, and lifecycle matrices are not active faction policy and are not checker lifecycle inputs. |
Current Entity Identity
Runtime identity is still global EntityKind. The current roster has 21 global kinds: 10 units,
9 buildings, and 2 resource nodes. Server rules own the stable ids in
server/crates/rules/src/kind.rs; protocol mirrors expose the same string ids in
server/crates/protocol/src/lib.rs and client/src/protocol.js.
The current production catalog is in server/crates/rules/src/defs.rs:
- Units: Worker, Rifleman, Machine Gunner, Anti-Tank Gun, Mortar Team, Artillery, Scout Car, Tank, Command Car, and Ekat.
- Buildings: City Centre, Zamok, Depot, Barracks, Training Centre, R&D Complex, Factory, Gun Works, and Tank Trap. Tank Trap construction is server-authoritative after Training Centre eligibility and is exposed through the mirrored worker build menu.
- Resource nodes: Steel and Oil.
Temporary compatibility shim policy: direct global kind checks are approved in the current rules
catalog, protocol adapters, setup/loadout code, AI, dev scenarios, command execution, production,
economy, combat, world-query helpers, and tests. New production files that introduce direct
current-faction kind checks should either use the faction catalog API or be added to
scripts/check-faction-assumptions.mjs with a short reason. High-risk approved files have a direct
special-case count ratchet so newly added current-faction checks inside those large files are also
visible during review. The ratchet is an inventory review tool, not approval to expand Kriegsia,
Ekat, or fixture special cases casually.
Current Economy Shape
Steel, Oil, and Supply are the only player resources in snapshots, compact snapshots, replay
analysis, match history replay artifacts, and the HUD. Start-map resources are still only Steel and
Oil nodes. Current starting values are STARTING_STEEL = 75, STARTING_OIL = 0,
STARTING_WORKERS = 4, with quickstart resources set to 99_999 Steel and 99_999 Oil.
Compact snapshots encode resources as fixed scalar slots: tick, Steel, Oil, Supply used, and Supply
cap. Spectator/replay player_resources use the same Steel/Oil/Supply fields. Later generic
resource work must be a separate plan; this faction plan keeps the current resource payload shape.
Approved direct-resource modules are listed in docs/design/balance.md under the faction economy
contract. Future direct Steel/Oil/Supply references outside those owners should either route
through catalog-aware cost/loadout helpers or update that approved inventory deliberately.
Current Starting Loadout
The standard Kriegsia match start is defined by the kriegsia.standard faction loadout in
server/crates/rules/src/faction.rs and assembled by server/crates/sim/src/game/setup.rs: each
player gets one completed City Centre, four Workers in a ring, nearby Steel/Oil resource clusters,
starting Steel and Oil, and supply from the City Centre. Unknown non-empty faction ids receive no
catalog loadout, starting entities, starting Steel/Oil, or Kriegsia supply credit; lifecycle owners
must validate before building a Game. Debug quickstart adds human-only extra buildings, combat
units, resources, debug path overlays, and an inert enemy mortar corner for inspection.
The standard Ekat match start is defined by the ekat.standard faction loadout: one completed
Zamok and one Ekat hero, with no starting Steel/Oil or Supply requirement. The
phase2_empty_fixture.scout_depot loadout starts one Depot and one Scout Car for explicit
fixture tests only; catalog existence does not make that id product-playable.
Replay starts reconstruct from recorded per-player PlayerStartingLoadout records. Replay
validators reject missing loadouts, records for unknown players, faction mismatches, empty loadout
ids, and loadout ids that do not exist in the player’s faction catalog. Global starting Steel/Oil
constructors remain compatibility helpers for tests and debug starts rather than replay/lifecycle
reconstruction APIs.
Current Tech Tree
Workers build City Centre, Depot, Barracks, Training Centre, R&D Complex, Factory, and Gun Works. City Centre trains Workers. Barracks trains Riflemen and Machine Gunners. Factory trains Scout Cars, Tanks, and Command Cars. Gun Works trains Mortar Teams, Anti-Tank Guns, and Artillery.
Research unlocks live in server/crates/sim/src/game/upgrade.rs and client descriptors in
client/src/config.js: Methamphetamines, Anti-Tank Gun Unlock, Tank Unlock, Artillery Unlock,
Command Car Unlock, and Mortar Autocast.
Current Ability Surface
Current ability ids are Charge, Smoke, Mortar Fire, Point Fire, Breakthrough, Ekat Teleport, Ekat
Line Shot, and Ekat Magic Anchor. The Rust faction catalog in
server/crates/rules/src/faction.rs is authoritative for ability id, carrier, target mode,
range, cooldown/charge, resource cost, queueability, autocast support, and command-card affordance
metadata. client/src/config.js is the checked client projection, while
server/crates/sim/src/game/services/ability_orders.rs, server/crates/sim/src/game/ability.rs,
and server/crates/sim/src/rules/projection.rs own execution and projection hooks. Protocol
ability vocabulary and compact codes remain mirrored through server/crates/protocol/src/lib.rs
and client/src/protocol.js.
Current Client Command Cards
The command-card renderer is local JS in client/src/hud_command_card.js; faction-sensitive
build, train, research, and ability descriptors are driven by the checked catalog mirror in
client/src/config.js. Kriegsia and Ekat command ids are namespaced by faction, unknown valid ids
fail closed to an empty catalog, and fixture catalogs remain test-only. node tests/hud_command_card.mjs
is the focused command-card guard, and node scripts/check-faction-catalog-parity.mjs compares
client-exposed descriptor data against the Rust catalog dump.
Current AI Coupling
AI is Kriegsia-only through the public lobby seat flow. The AI decision layer assumes Workers gather
Steel/Oil, City Centres anchor bases and expansions, Barracks/Factory/Gun Works drive production,
Tanks influence oil demand, and Steel/Oil/Supply budgets are fixed fields. Public addAi requests
do not accept a faction id and always create Kriegsia AI seats; non-Kriegsia AI support needs an
explicit AI phase.
Current Prediction And WASM Coupling
Prediction/WASM assumes the current start payload, global entity ids, current command set,
Steel/Oil/Supply scalar resources, and compact snapshot version. Local prediction is currently
supported only for local Kriegsia players; local Ekat or fixture players disable prediction with the
stable unsupported-local-faction reason until the WASM simulation and adapter support those
contracts intentionally.
Lifecycle Paths
This section is the maintained source of truth for match creation, playback, replay branch, spectator, dev scenario, self-play, quickstart, AI, prediction, match-history, and post-match replay paths. Later phases must update this section whenever they touch one of those lifecycle paths.
| Path | Faction source | Allowed factions | AI behavior | Prediction behavior | Replay/branch behavior | Tests or checks |
|---|---|---|---|---|---|---|
| Normal lobby start | LobbyPlayer.factionId and PlayerInit.faction_id, defaulted by lobby::faction_validation | kriegsia and ekat; fixture and unknown ids reject | No AI assignment by setFaction; AI seats are separate | Enabled only for local Kriegsia when build/version metadata is compatible | Schema 2 records player faction id plus per-player loadout record | tests/faction_integration.mjs, tests/prediction_controller.mjs, server/src/lobby/faction_validation.rs tests |
| Quickstart/debug start | Human lobby selection plus quickstart validation/defaulting | kriegsia and ekat; fixture and unknown ids reject | AI seats still default Kriegsia | Enabled only for local Kriegsia | Schema 2 records faction id and per-player debug/standard loadout records | server/crates/sim/src/game/setup/tests.rs, server/src/lobby/faction_validation.rs tests |
| AI add/remove/start | AI PlayerInit.faction_id, created by public addAi | Public AI seats default to kriegsia; no public Ekat selector | Kriegsia-only through public lobby controls | Not applicable | Schema 2 records AI faction and per-player loadout if match starts | tests/ai_integration.mjs, tests/server_integration.mjs |
| Fixture/dev faction start | Explicit Rust test/dev harness only | phase2_empty_fixture only in TestFixture validation or direct lower-level tests | Rejected unless a later phase explicitly adds fixture AI | Disabled when local fixture player is unsupported | Fixture ids stay in explicit test artifacts only | server/crates/sim/src/game/setup/tests.rs, tests/prediction_controller.mjs, scripts/check-faction-assumptions.mjs |
| Replay playback | ReplayArtifactV1.players[].faction_id and playerLoadouts[] in artifact schema 2 | Recorded playable ids kriegsia or ekat; missing, unknown, and fixture ids reject | From artifact only | Disabled for replay viewers | Load from artifact schema, never lobby state | server/crates/sim/src/game/replay.rs tests, server/src/lobby/room_task.rs replay tests |
| Replay branch staging/launch | Branch seed seats copy recorded factionId from replay players | Recorded playable ids kriegsia or ekat; unsupported seat faction ids reject before live launch | From recorded branch seed only | Disabled unless supported by branch schema/WASM | Reconstruct from branch seed and cloned keyframe | server/src/lobby/room_task.rs tests, tests/protocol_parity.mjs |
| Dev scenarios | Scenario definition plus validation/defaulting | Current bundled scenarios default to Kriegsia; explicit playable ids may be accepted by an owning scenario | Not applicable unless scenario declares AI | Enabled only for local Kriegsia | Not replayed unless scenario recording exists | server/crates/sim/src/game/setup/dev_scenarios/tests.rs, docs/context/testing.md |
| Self-play | Self-play PlayerInit.faction_id, validated by lobby::faction_validation | Current bundled self-play defaults to Kriegsia; explicit Ekat needs a self-play script that owns it | Kriegsia-only in current live AI scripts | Not applicable | Artifact schema 2 records faction ids and per-player loadouts | server/crates/ai/src/selfplay tests |
| Match history replay | Stored schema-2 match artifact | Recorded playable ids kriegsia or ekat; missing, unknown, and fixture ids reject | From artifact only | Disabled for replay viewers | Load from persisted schema; schema 1 is incompatible for faction/loadout reconstruction | server/src/main.rs replay compatibility tests, docs/design/match-history.md |
| Spectator/no-fog view | Live match start payload or replay schema | Match factions from start/replay metadata | Not applicable | Disabled | Preserve recorded faction metadata | tests/server_integration.mjs |
| Post-match replay | Captured schema-2 match artifact | Recorded playable ids kriegsia or ekat; missing, unknown, and fixture ids reject | From artifact only | Disabled for replay viewers | Load from captured schema with Steel/Oil/Supply resource payloads | tests/server_integration.mjs |
Current Guardrail Checks
scripts/check-faction-assumptions.mjsvalidates this inventory’s anchors and ratchets the current files that may contain direct current-faction kind or ability special cases.server/crates/rules/src/defs.rstests lock the current production catalog.server/crates/sim/src/game/setup/tests.rslocks the current standard and debug start loadouts.tests/protocol_parity.mjslocks protocol kind, ability, upgrade, compact snapshot, and resource code parity.tests/hud_command_card.mjslocks representative current command-card descriptors.node scripts/check-faction-catalog-parity.mjscompares every client-exposed catalog with the Rust dump across catalog ids, loadout ids, train and research keys, builder/gatherer/production anchors, ability command-card metadata, costs, and playable selector ids. It verifies that all Rust catalogs are dumpable, that fixture catalogs stay mirrored for tests, and that fixture/future catalogs are not exposed as playable lobby options. Every real-faction descriptor exposed inclient/src/config.jsmust be compared against the Rust dump by this gate.
Guardrail Map For Future Faction Work
When faction behavior changes, update the owning source and its guard in the same change:
- Faction catalog facts, loadouts, and ability availability: update
server/crates/rules/src/faction.rs, the Rust catalog dump,client/src/config.js, andscripts/check-faction-catalog-parity.mjs. - Lifecycle admission for lobby, quickstart, AI, replay, branch, dev scenario, self-play, match
history, and fixture contexts: update
server/src/lobby/faction_validation.rs, this inventory’s lifecycle table, and focused server or Node tests for the touched path. - Wire vocabulary, payload fields, compact codes, default ids, and replay schema shape: update
server/crates/protocol/src/lib.rs,server/src/protocol.rsif it adapts the payload,client/src/protocol.js,docs/design/protocol.md, andtests/protocol_parity.mjs. - Client command cards, hotkeys, UI faction selectors, prediction compatibility, and client-visible
mirrors: update the relevant
client/src/*module,docs/design/client-ui.md,tests/hud_command_card.mjs,tests/hotkey_profiles.mjs,tests/client_contracts.mjs, ortests/prediction_controller.mjsas applicable. - Server simulation starts, loadouts, setup helpers, AI scripts, self-play artifacts, and replay
reconstruction: update
docs/design/server-sim.mdplus the focused Rust tests under the touched crate. - Guard wiring: keep
tests/run-all.sh,tests/select-suites.mjs, anddocs/design/testing.mdaligned so faction-sensitive files select the assumption checker and catalog parity checker. - Archive policy: archived plans under
plans/archive/faction/*are evidence only. Do not import lifecycle policy, status tables, checker allowlists, or source paths from archived plan files; copy any still-current rule into this inventory or another active design doc before using it.