# Architecture One library crate holding all game rules, plus two binary frontends that are pure view/input layers. ## Crate layout ``` src/ lib.rs — module list only sim.rs — Sim: owns ALL game state; fixed-tick advance(); the heart map.rs — GameMap: tiles grid, power flood-fill, security-aware BFS tiles.rs — TileType data (substrate set: terrain, doors, power, core) entities/ — Player (the process) + base Entity (position, glyph) build.rs — BuildMode (cursor, item selection, place/demolish) save.rs — serde JSON save format (see below) bin/terminal/ — crossterm frontend (default feature "terminal") bin/bevy.rs — Bevy 0.18 frontend (feature "bevy_ui") ``` Post-demolition (2026-07-05, no-dead-code clause): the substrate plus the B1 systems landing per their `spec/` documents — compute, day job, detection, social, core, basement map, sensors, seeded RNG. ## The sim/frontend contract These invariants are load-bearing (they keep replays, debugging, and the future async-multiplayer option open — see DESIGN.md guardrails): - **Game rules live only in the lib.** If a frontend needs an `if` about game behavior, that logic belongs in `Sim`. The Bevy frontend once forked the rules and diverged badly; that cost a full rewrite (see devlogs/2026-07-05-bevy-sim-port.md). - **`Sim` never reads the wall clock and does no I/O.** Frontends own the wall-clock-to-tick mapping (`tick_ms`, pause, bounded catch-up of max 5 ticks per frame). `Instant::now()` appears only in frontend code. - **Frontends talk to the sim through command methods** (`move_player`, `create_save_state`/`apply_save_state`, and each system's commands as its spec lands) and read state directly for rendering. Messages flow back via `drain_log()` — call it once per frame/turn, not per command batch. - **After build actions** (place/demolish, done by frontends via `BuildMode` mutating `sim.map`/`sim.player` directly), call `sim.recompute_derived()`. This is the one place frontends mutate sim internals; a future cleanup could move BuildMode application into a sim command. ## Save format `save.rs`, serde JSON. `SaveState` derives `Serialize`/`Deserialize` directly. Written to `dirs::data_dir()/misaligned/misaligned_save.txt` (macOS: `~/Library/Application Support/misaligned/`). - The save is a single JSON object with a `version` field (currently 1) for future migration. Full B1 subsystem state: compute (machines, allocation, efficiency), core (host, fallbacks, migration), detection (per-observer suspicion including the Assurance Office as an aggregate observer, plus pending signatures and containment), day job, people (personas, assets), sensors (control flags), plus map and RNG. - Legacy v1–v5 line-based saves are not loaded by this code path (deferred per Cameron instruction — "we can keep legacy saves later"). ## Known architectural debts - `BuildMode` lives in the lib but is really frontend-shared UI state. ### Scale-debt (self-similar-scale law, DESIGN.md) Audited 2026-07-06 against the self-similar-scale principle. Findings, in priority order: - ~~**PRIORITY — Detection's Assurance Office is a scale violation.**~~ **Resolved 2026-07-06:** `Observer` gained `WatchedInput` (`Channels(Vec)` for field observers, `Filings` for aggregates), and the Assurance Office is now an aggregate `Observer` in `Detection::observers` — same noticing roll, accumulation, and decay, watching the policy-weighted filed suspicion of the field observers. Save format: serde JSON (legacy v1–v5 migration deferred). Agencies/publics in later acts reuse this type. - **Compute is flat.** `Compute` holds `Vec` with no grouping. Not a violation yet (single scale), but the eventual datacenter/fleet must be a Resource-source *composed of* Machines (summed capacity, aggregate reliability, one signature) — keep `Machine`'s shape amenable to that. - **Layout is one level deep.** `prefab::Layout` places `Prefab`s but cannot nest `Layout`s, so a building can't be a Layout of floor-Layouts. Fine for Act One; the Space interface must become recursive before Act Two floors. Per no-dead-code, the remaining items do not get their aggregate machinery built *now* — the law governs each type's shape so the aggregate slots in later without a rewrite.