# Reactor Maintenance Tasks This backlog tracks what must change so the implementation matches `docs/design.md`, `docs/UX.md`, and `docs/CAMPAIGN.md`. ## Audit Snapshot - Current simulation tests pass: `60/60` in `tests/ReactorMaintenance.Simulation.Tests`. - Godot level play includes pulse step playback, terminal-gated layer controls, campaign loading, and in-game level editing with JSON save. - Campaign data follows the tutorial plus six-group campaign from `docs/CAMPAIGN.md`. - Unrelated Godot metadata or generated `.uid` files are not part of this backlog unless a later implementation task intentionally touches them. ## P0 Simulation Contract - [x] Rename the public environment tick model from turn-based `AdvanceTurn`/`EndTurn` semantics to `Pulse` semantics. - One accepted `LengthyAction` triggers exactly one `Pulse`. - One `Pulse` contains a fixed balance-defined number of deterministic `Step`s. - The fixed step count must not vary by action type, forecast result, or danger level. - Keep isolated step or pulse advancement available only for tests, editor tooling, or debug use. - [x] Remove player-facing wait/fast-forward behavior from normal gameplay. - `MoveRobot`, selection, inspection, and terminal layer viewing remain `QuickAction`s. - `InteractProp`, `InteractLeak`, `ApplyHeatShield`, and accepted powered-prop no-op interactions are `LengthyAction`s. - `ActivateReactor` wins when `ReactorReadiness` is true and must not require a separate wait. - [x] Add `IsolationValveProp` as a first-class prop. - Store carrier binding and `Open`/`Closed` state. - Block intentional underground propagation across the authored branch boundary. - Preserve downstream starvation/readiness consequences for consumers and reactor feed. - Add editor placement, validation, serialization, and rendering support. - [x] Add `SprinklerControlProp` and wall-mounted `SprinklerValve`. - A `SprinklerControlProp` links to exactly one `SprinklerValve`. - The valve is wall-mounted, not directly interactive, and has exactly one outlet/access floor face. - Discharge creates `Water` only while linked control is `Enabled` and the water branch is fed. - Discharge applies deterministic local water pressure debt. - Add editor placement/linking, validation, serialization, and rendering support. - [x] Rework surface water into `Water`. - Rename code-facing concepts where practical; otherwise make names and UI text consistently mean water, not a generic hazard. - `water` pipe failures should inject `Water`, not a damaging liquid. - `Water` alone must not cause `UnsafeEntryLoss`. - [x] Update leak injection. - Leaks inject only when the underground leak cell has positive amount and positive pressure/voltage after propagation. - Isolating a leak stops fresh injection without repairing the underlying fault. - Repair restores structural integrity and stops future injection but does not clean existing surface values. - [x] Implement the approved surface interaction order. - Resolve leak/sprinkler injection per `Step`. - Resolve water mitigation before ignition and electrical spread. - Implement `Dilute`, `Quench`, value-based `Evaporate`, wet-electric `Conduct`, and `Ignite`. - Preserve deterministic same-cell and adjacent-cell delta accumulation. - Closed powered doors and remedy blocks must gate only the interactions they explicitly block. - [x] Implement value-based evaporation. - Add balance values for ambient evaporation, heat-driven evaporation, and evaporation cooling. - Hot cells should evaporate `Water` faster than cold cells. - Evaporation happens during useful action pulses; there is no campaign wait command. - [x] Implement `Unsafe` as derived movement safety. - `Unsafe` is recalculated after authored setup and after each `Pulse`. - `Unsafe` is caused by unsafe `Heat`, unsafe `LeakedElectricity`, or the wet-electric unsafe rule. - `LeakedFuel` alone and `Water` alone are not `Unsafe`. - `UnsafeEntryLoss` happens only when `MoveRobot` enters an `Unsafe` destination without applicable protection. - A `Pulse` must not kill a stationary robot just because the current cell becomes `Unsafe`. - [x] Implement powered prop behavior. - `DoorProp` and `AllSeeingEyeTerminal` require positive local electricity amount and voltage for their interactions to take effect. - Interacting with an unpowered `PoweredProp` is accepted as a `LengthyAction`, changes no prop state, reveals no terminal information, and still triggers one `Pulse`. - Powered doors keep their last physical open/closed state when power is lost. - [x] Gate all-seeing-eye information. - Underground topology, numeric underground values, and `Forecast` output are visible only while the robot is at an active and powered `AllSeeingEyeTerminal`. - Terminal access is local and does not persist after the robot leaves. - Forecasts are systemic simulations over copied state, never authored level prose. - [x] Update `ReactorReadiness` checks as the invariant source of victory. - Every network present beneath `ReactorControlProp` must have positive amount and intensity. - Required per-carrier consumer counts must be `Enabled` and `Producing`. - Missing readiness blocks `Ready` but does not directly cause `Lost`. ## P0 Simulation Tests - [x] Update existing tests so their names and assertions use `Pulse`, `Step`, `Water`, `Unsafe`, and `ReactorReadiness` terminology. - [x] Add tests for fixed pulse length. - Every accepted `LengthyAction` advances one `Pulse`. - Each pulse resolves the configured number of `Step`s. - `MoveRobot` and inspection-like calls do not resolve a pulse. - [x] Add tests for no normal wait/fast-forward dependency. - Player-facing session/action APIs should not require `EndTurn` to reach readiness after a lengthy action. - Debug/test-only pulse advancement, if retained, must be clearly named and excluded from campaign UI. - [x] Add tests for `IsolationValveProp`. - Open valve allows branch propagation. - Closed valve isolates damaged branches and can starve downstream consumers/reactor feed. - Toggling a valve triggers exactly one `Pulse`. - [x] Add tests for `SprinklerControlProp` and `SprinklerValve`. - Valve discharge requires a linked enabled control and fed water branch. - Direct valve interaction is invalid or unavailable. - Discharge creates `Water` at the authored outlet and applies pressure debt. - Disabling the linked control or isolating the sprinkler branch stops fresh discharge. - [x] Add tests for updated leak injection. - Fed fuel, water, and electricity leaks inject to the correct access face. - Isolated leaks stop new surface injection. - Repairs restore structural integrity without cleaning existing surface values. - [x] Add tests for surface interactions. - `Water` dilutes `LeakedFuel`. - `Water` quenches `Heat`. - Evaporation removes water and cools heat according to balance values. - Wet cells conduct electricity faster than dry cells. - Fuel plus electricity or heat can ignite and create heat while consuming fuel. - Closed doors block designed surface propagation paths. - [x] Add tests for `Unsafe`. - Moving into unsafe heat loses without active heat protection. - Moving into unsafe electricity loses. - Moving into wet-electric unsafe cells loses. - Moving into fuel-only or sprinkler-water-only cells does not lose. - A pulse that makes the robot's current cell unsafe does not immediately lose. - [x] Add tests for powered props. - Powered door toggles and blocks/unblocks surface propagation. - Unpowered door interaction changes no door state but still triggers a pulse. - Powered terminal interaction enables local visibility and forecasts. - Unpowered terminal interaction reveals nothing and still triggers a pulse. - Leaving the terminal removes underground/forecast visibility. - [x] Add tests for campaign authoring invariants. - Every campaign level loads and validates. - Tutorial is solvable with exactly one `LengthyAction` before `ActivateReactor`. - Every non-tutorial level has at least two valid first `LengthyAction` choices. - No campaign level requires a wait/fast-forward command. - No level before 3-2 requires underground visibility to understand the intended first decisions. - Campaign manifest order matches `docs/CAMPAIGN.md`. ## P1 Editor, Schema, And Level Data - [x] Bump the level schema version when adding new prop/link/outlet state. - [x] Update serialization round trips for new fields. - `IsolationValveProp` carrier and open/closed state. - `SprinklerControlProp` enabled/disabled state and linked valve id or position. - `SprinklerValve` wall position, outlet/access face, linked control, and water connection. - Powered terminal active state if it becomes serialized runtime state. - [x] Update `LevelEditor` tools. - Add isolation valve placement. - Add sprinkler control placement. - Add wall-mounted sprinkler valve placement and outlet/access cycling. - Keep electricity leak wall access cycling. - Prevent invalid prop placement on walls except designed wall-mounted sprinkler valves. - [x] Update `LevelValidator`. - Validate powered doors have valid geometry and local electricity. - Validate terminal power requirements where needed. - Validate wall-mounted sprinkler valve geometry, outlet/access face, water connection, and exactly one linked control. - Validate isolation valves sit on exactly one matching underground carrier. - Warn on initially unready reactors, initially starved required consumers, unused supplies, and sprinkler valves with no useful suppression or pressure tradeoff. - [x] Replace placeholder campaign files. - Create tutorial plus Groups 1-6 from `docs/CAMPAIGN.md`. - Update `default_campaign_manifest.json` to the final order. - Remove or demote old placeholder levels so they are not presented as campaign content. - Add stable ids and short flavor text for every authored level. - [x] Add test/build helpers for level construction. - Prefer shared builders for linear networks, forks, leaks, wall electricity faces, doors, controls, consumers, and reactors. - Avoid duplicating low-level array setup across tests. - [x] Add Godot level editing support. - Expose editor tool, carrier, and remedy selection from the level screen. - Apply `LevelEditor` commands to grid clicks in edit mode. - Validate and save edited levels back through `LevelSerializer`. ## P1 Godot UX Integration - [x] Remove player-facing `End Turn` from the normal action bar. - Replace it with contextual `LengthyAction` commands and `ActivateReactor` when ready. - Keep any debug pulse control behind an explicit development-only path. - [x] Update `GameSession` API names and events to match pulse semantics. - Use `PulseAdvanced` or equivalent instead of `TurnAdvanced`. - Ensure accepted no-op powered-prop interactions still notify pulse playback. - Ensure refused invalid actions do not mutate state or trigger pulse playback. - [x] Animate `Pulse` playback as a short cascade of `Step`s. - Show leak growth, sprinkler discharge, evaporation, quenching, ignition, wet conduction, and readiness updates. - Disable conflicting inputs during playback. - End playback on the final post-pulse decision state. - [x] Gate underground layer controls and forecasts. - Hide or disable layer toggles unless the robot is at an active and powered `AllSeeingEyeTerminal`. - Show why terminal access is unavailable when unpowered or away from the terminal. - Use `Pulse +N` wording in forecast UI. - [x] Update grid rendering and inspector text. - Render `Water` separately from underground `water`. - Render `Unsafe` cells with a distinct movement warning treatment. - Render isolation valve state, sprinkler control state, wall-mounted sprinkler outlet, powered door state, and powered terminal state. - Inspector should display visible surface values, prop state, consumer per-carrier state, and underground values only when terminal access allows it. - [x] Update action affordances. - Movement remains direct and quick. - Prop interactions should explain unavailable power, invalid position, missing remedy, depleted supply, and reactor-not-ready causes. - Disabled actions remain inspectable so players can understand why an action is unavailable. ## P2 Polish And Release Tasks - [x] Add concise pulse-result feedback for major outcomes: isolated leak, restored pressure, downstream starvation, reactor ready, wet-electric risk, and terminal heat danger. - [x] Add campaign completion flow for the final Group 6 level. - [x] Add loading and malformed-level error states for campaign level loading. - [x] Revisit art labels/icons for `Water`, `Unsafe`, powered props, and sprinkler controls after mechanics are implemented. ## Verification Rules - [x] After each implementation iteration, run the focused simulation tests that cover the changed system. - [x] Run full `dotnet test` before committing simulation or serializer changes. - [x] For code changes on Windows, run the repo-required CRLF normalization and cleanup steps after implementation. - [x] For documentation-only iterations, no cleanup pass is required. - [x] Keep documentation aligned whenever code changes terminology or behavior. - [x] Commit each completed iteration with a brief summary.