From 59b18b23bc46f1cef8e77814ea7437ace8285fa7 Mon Sep 17 00:00:00 2001 From: Frank Tovar Date: Thu, 14 May 2026 14:56:59 +0200 Subject: [PATCH] Replace tasks with procedural generation backlog --- TASKS.md | 357 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 183 insertions(+), 174 deletions(-) diff --git a/TASKS.md b/TASKS.md index a49d2ef..3f0a1b5 100644 --- a/TASKS.md +++ b/TASKS.md @@ -1,195 +1,204 @@ # Reactor Maintenance Tasks -This backlog tracks what must change so the implementation matches `docs/design.md`, `docs/UX.md`, and `docs/CAMPAIGN.md`. +This backlog tracks procedural level generation, reusable exhaustive solving, Godot random play, and Godot-assisted campaign authoring automation. ## 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. +- The next implementation replaces the placeholder random-level flow with seed-driven generation and reusable solver analysis. +- Win2D is not part of this backlog. -## P0 Simulation Contract +## P0 Generator 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`. +- [ ] Add a parameterized `LevelGenerationRequest`. + - Include `Seed`, display name, optional max dimensions, `SolverDepthLimit`, target complexity, and `MaxAttempts`. + - Require `InvolvedSystems` to contain at least one of `Fuel`, `Water`, or `Electricity`. + - Specify exact available consumer counts per involved carrier. + - Specify exact required consumer counts per involved carrier. + - Specify the exact carrier set directly connected to the reactor control. + - Reject impossible specs before generation, including required consumers greater than available consumers. +- [ ] Add a player-facing seed profile expander. + - Use the seed to choose involved systems. + - Use the seed to choose available consumer counts. + - Use the seed to choose required consumers as none, some, or all of the placed consumers. + - Use the seed to choose how many involved systems directly connect to the reactor. + - Expand to a concrete `LevelGenerationRequest` so random play and authoring use one generator path. +- [ ] Generate levels without fixed archetypes. + - Compose generated content from the requested systems, consumers, reactor connectivity, and difficulty target. + - Avoid named campaign-group archetypes as public generation modes. + - Let multi-system hazards emerge from generated overlapping fuel, water, electricity, heat, leak, sprinkler, and powered-prop placements. +- [ ] Grow levels organically from the reactor. + - Start the generated graph at the `ReactorControlProp`. + - Grow carrier networks, branches, rooms, corridors, access routes, and player decision points outward from the reactor graph. + - Place surrounding walls after gameplay geometry exists. + - Calculate the occupied bounding box after generation. + - Offset all coordinates into positive level space before creating final arrays. + - Preserve valid wall geometry for doors, wall electricity leaks, and wall-mounted sprinkler valves. +- [ ] Generate structural-integrity and pressure interactions. + - Author weakened underground segments with controlled pressure or voltage exposure. + - Generate pressure-fed and voltage-fed leaks that can be isolated, repaired, or allowed to worsen. + - Generate hazards that restrict movement through `Unsafe` heat, electricity, or wet-electric combinations. + - Include pressure tradeoffs from sprinkler discharge and consumer/reactor starvation. + - Ensure generated hazards are reachable, readable, and tied to player choices. -## P0 Simulation Tests +## P0 Reusable Solver -- [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`. +- [ ] Add a reusable `LevelSolver` in the simulation project. + - Accept a `LevelState` and `SolverRequest`. + - Return a `SolverReport` with terminal counts, complexity metrics, diagnostics, and representative traces. + - Keep the solver independent from Godot so generator, editor, tests, and future tools can share it. +- [ ] Define solver choices as reachable lengthy actions. + - Collapse quick movement into safe reachability from the current robot position. + - Enumerate all reachable prop interactions, leak repairs, remedy uses, heat shield uses, and reactor activation attempts. + - Exclude inspection, selection, terminal viewing, and individual quick movement branches from primary metrics. + - Sort canonical choices deterministically before evaluation. +- [ ] Evaluate every bounded branch. + - Explore all possible choice permutations to the configured lengthy-action depth limit. + - Count `Win`, `Lose`, and `Inconclusive` leaves. + - Mark branches inconclusive when the depth limit or timeout is reached before terminal outcome. + - Treat no-choice non-ready states as losing dead ends. + - Preserve exact branch counts while using transposition caching to avoid duplicate expansion work. +- [ ] Add solver complexity metrics. + - Report min and max player choices to win. + - Report min and max player choices to loss. + - Report max and average available choices per decision state. + - Report lose/win ratio across all bounded permutations. + - Report inconclusive ratio. + - Report explored node count and cache hit count. + - Provide representative shortest winning and losing traces. +- [ ] Parallelize branch evaluation. + - Issue all canonical choices from a state in parallel when budget allows. + - Wait for all choice evaluations from that state. + - Aggregate results in canonical order for deterministic diagnostics. + - Use ThreadPool or TPL work stealing for nested parallel branch work. + - Respect max parallelism, timeout, and cancellation. +- [ ] Keep solver performance and memory usage controlled. + - Clone level states only at branch boundaries. + - Add per-thread reusable buffers or `LevelState` clone pools where practical. + - Avoid retaining full state graphs when only metrics are needed. + - Keep only bounded representative traces. + - Evaluate whether `record struct` or other value-oriented refactors reduce heap pressure without harming maintainability. + - Add allocation or stress tests for representative generated levels. -## P1 Editor, Schema, And Level Data +## P1 Generation Acceptance And Difficulty -- [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`. +- [ ] Validate every generated candidate. + - Run `LevelValidator`. + - Run bounded solver analysis. + - Reject candidates with validation errors. + - Reject candidates with no winning branch. + - Reject candidates whose required systems, consumer counts, or reactor-connected carrier set do not exactly match the request. + - Reject candidates whose hazards cannot affect movement or meaningful decisions. +- [ ] Add difficulty target filtering. + - Filter by minimum and maximum choices to win. + - Filter by maximum and average available choices. + - Filter by lose/win ratio range. + - Filter by maximum inconclusive ratio. + - Filter by required first-choice variety. + - Make defaults suitable for random play and configurable for campaign authoring. +- [ ] Support campaign progression targets. + - Early targets use fewer involved systems, lower available-choice counts, and low lose/win ratios. + - Mid targets increase first-choice variety and introduce more losing branches. + - Late targets allow more systems, more branching, higher lose/win ratio, and lower inconclusive tolerance. + - Make target definitions data-driven enough for campaign automation scripts or Godot UI. +- [ ] Add diagnostics for rejected candidates. + - Report invalid spec reasons. + - Report validation errors and warnings. + - Report solver failure reasons. + - Report mismatch against requested systems, consumers, reactor feeds, and complexity target. + - Keep diagnostics concise enough for Godot UI and detailed enough for tests. -## P1 Godot UX Integration +## P1 Godot Random Play And Authoring Automation -- [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. +- [ ] Replace placeholder random-level flow. + - Generate a level from a player seed profile. + - Save generated JSON under `user://generated/`. + - Load generated levels through `LevelStateLoader`. + - Retry the same generated level from the saved JSON. + - Complete random levels by returning to generation or regenerating from a new seed. +- [ ] Add authoring controls to `GenerationScreen`. + - Toggle involved systems. + - Set available consumers per carrier. + - Set required consumers per carrier. + - Toggle reactor-connected carriers. + - Set seed, max attempts, solver depth limit, and target complexity. + - Generate, regenerate, analyze, save JSON, begin play, and return to menu. +- [ ] Surface solver metrics in Godot. + - Show win, lose, and inconclusive counts. + - Show min and max choices to win. + - Show max and average available choices. + - Show lose/win ratio and inconclusive ratio. + - Show concise representative trace summaries for authoring review. +- [ ] Reuse generated JSON in Godot editor mode. + - Open generated levels in `LevelScreen`. + - Allow normal edit-mode changes. + - Validate and save back to the generated JSON path. + - Preserve generated metadata needed for retry and review. +- [ ] Keep Godot generation responsive. + - Run generation and solver analysis off the main UI path. + - Show progress, cancellation, and failure diagnostics. + - Prevent starting a stale or failed generated candidate. -## P2 Polish And Release Tasks +## P1 Tests -- [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. +- [ ] Add generator determinism tests. + - Same request and seed serialize to identical JSON. + - Different seeds produce meaningfully different layouts for the same request. + - Player seed profile expansion is deterministic. +- [ ] Add generation spec-compliance tests. + - Generated involved systems match the request exactly. + - Available consumer counts match the request exactly. + - Required consumer counts match the request exactly. + - Reactor-connected carriers match the request exactly. + - Organic bounding and coordinate offset produce valid positive coordinates and correct array sizes. +- [ ] Add generated hazard tests. + - Generated pressure-fed leaks inject only when fed. + - Structural-integrity hazards can create or worsen leaks under generated pressure or voltage. + - Generated hazards can restrict movement through `Unsafe` rules. + - Generated sprinkler pressure debt can affect consumer or reactor service. +- [ ] Add solver correctness tests. + - Known tiny levels report expected win, lose, and inconclusive counts. + - Depth-limited branches become inconclusive. + - No-choice non-ready states count as losing dead ends. + - Canonical action ordering produces stable diagnostics. + - Parallel and single-threaded solver runs produce identical reports. +- [ ] Add solver performance tests. + - Branch-heavy generated samples finish within the configured timeout. + - Representative solving does not retain unbounded traces. + - Clone or pooling behavior does not leak mutable state across branches. +- [ ] Add Godot integration coverage where practical. + - Generated JSON loads through `LevelStateLoader`. + - Generated JSON saves through the existing level save path. + - `FrontendSession` can point random mode at generated JSON. + +## P2 Documentation And Tooling + +- [ ] Update `docs/design.md`. + - Document procedural generation inputs. + - Document solver outcomes and metrics. + - Document generated structural-integrity and pressure-hazard expectations. + - Document random play seed behavior. +- [ ] Update `docs/UX.md`. + - Replace placeholder random-level wording. + - Describe generation controls, authoring controls, metrics display, progress, cancellation, and failure states. + - Describe generated JSON editing and save-back flow. +- [ ] Add authoring guidance. + - Explain how generated levels can be promoted into campaign candidates. + - Explain how increasing choices and lose/win ratio supports campaign progression. + - Explain recommended solver depth and target complexity ranges. +- [ ] Keep task status current. + - Check off items as implementation lands. + - Remove outdated task text instead of adding past-tense prose. + - Keep verification commands aligned with repo instructions. ## 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. +- [ ] Run focused solver and generator tests after solver or generation changes. +- [ ] Run full `dotnet test` before committing simulation, serializer, or generated-data changes. +- [ ] Run `dotnet build ReactorMaintenance.slnx --no-restore` and `dotnet test ReactorMaintenance.slnx --no-restore` sequentially. +- [ ] For code changes on Windows, run `python D:\Code\crlf.py` for recognized touched files. +- [ ] For code changes on Windows, run `jb cleanupcode --verbosity:ERROR ReactorMaintenance.slnx`. +- [ ] For documentation-only iterations, no cleanup pass is required. +- [ ] Commit each completed iteration with a brief summary.