Privatize the Simulation player-action mutators (tryPlaceBuilding, demolish,
applySchematicChoice) and the mutable subsystem accessors (now buildingsMutable/
beltsMutable; only the const buildings()/belts() stay public). Production's only
handle to a subsystem is through Simulation, and every production buildings()/
belts() call is a const query, so this fully locks gameplay out of any
command-bypassing mutation path -- such code now fails to compile instead of
silently desyncing replays.
Tests reach the private mutators through SimulationTestAccess, a friend struct
under src/test (off the lib/ui/app include path), so they keep calling the real
mutators and keep their return values -- no id-by-position recovery needed. The
BuildingSystem subsystem mutators stay public (BuildingTest unit-tests a bare
subsystem; unreachable from production anyway).
Upgrades the Phase 1 "convention only" decision to structural enforcement.
All targets build; 354 cases / 3418 assertions pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DUsFgd2Ga6pmLz8giS8WUn