From a88ef664781561ceb0b712cbd3b3e83a096381af Mon Sep 17 00:00:00 2001 From: dev wells Date: Wed, 17 Jun 2026 10:19:16 -0400 Subject: [PATCH] docs: tickets --- .marksman.toml | 0 AGENTS.md | 19 ++++++ docs/development_path.md | 44 +++++++------ docs/pitch.md | 2 - docs/tickets/todo/002-fixed-step-replay.md | 42 +++++++++++-- docs/tickets/todo/003-headless-run-harness.md | 63 +++++++++++++++++++ ...ic-rendering.md => 004-basic-rendering.md} | 15 +++-- docs/tickets/todo/005-physical-echo-replay.md | 46 ++++++++++++++ .../todo/006-echo-landmarks-deviation.md | 57 +++++++++++++++++ .../todo/007-death-events-corpses-gear.md | 52 +++++++++++++++ 10 files changed, 309 insertions(+), 31 deletions(-) create mode 100644 .marksman.toml create mode 100644 AGENTS.md create mode 100644 docs/tickets/todo/003-headless-run-harness.md rename docs/tickets/todo/{003-basic-rendering.md => 004-basic-rendering.md} (50%) create mode 100644 docs/tickets/todo/005-physical-echo-replay.md create mode 100644 docs/tickets/todo/006-echo-landmarks-deviation.md create mode 100644 docs/tickets/todo/007-death-events-corpses-gear.md diff --git a/.marksman.toml b/.marksman.toml new file mode 100644 index 0000000..e69de29 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..650f166 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,19 @@ +# Overview + +Thanatograph is a dungeon crawler with permadeath where every failed attempt becomes part of the next run. See [core idea](/docs/pitch.md#core-idea) for more. + +It is built in Odin + Raylib using fixed-time step simulation. + +- [pitch for high level](/docs/pitch) +- [tickets for progress tracking](/docs/tickets) +- [development path for high level roadmap](/docs/development_path.md) + +Game architecture is broken into: + +- Main game in [game](/src/game) +- Simulation framework in [sim](/src/sim) +- Library glue code in [lib](/src/lib) + +## Notes + +Use jujutsu (jj) for version control. diff --git a/docs/development_path.md b/docs/development_path.md index 6e9e58b..ec0b8b5 100644 --- a/docs/development_path.md +++ b/docs/development_path.md @@ -18,6 +18,8 @@ Everything else should serve that test until the answer is clearly yes. - Prove the echo mechanic before building a broad roguelike. - Prefer deterministic fixed-step simulation for gameplay, even if rendering stays variable. - Keep persistent run history explicit and inspectable. +- Treat `src/sim` as the authoritative gameplay boundary. It should be runnable and testable without Raylib, rendering, frame-time, or platform APIs. +- Recreate runs from deterministic causes: simulation version/config, seed, initial state descriptor, and one command per tick. Use transcripts for proof and debugging, not as gameplay authority. - Keep dungeon scope tiny until echo interaction is fun. - Build tooling only when it shortens iteration on the core loop. - Avoid engine generality unless the game immediately benefits from it. @@ -25,6 +27,7 @@ Everything else should serve that test until the answer is clearly yes. ## Core Technical Risks - Deterministic replay must be stable enough that echoes feel like past selves, not approximate ghosts. +- Authoritative simulation must avoid platform-dependent behavior, including wall-clock time, render frames, unordered iteration, global random state, and replay-relevant raw floats where quantized/fixed values would be safer. - Echoes need local recovery when the live world diverges, without losing the emotional truth of replay. - Combat must stay readable when live player, enemies, and multiple echoes interact. - Gear recovery needs clear ownership rules to avoid duplication exploits and player confusion. @@ -47,14 +50,15 @@ If this is not compelling with one room, one enemy, one weapon, and one echo, ad ## Suggested Architecture Order -1. Establish an app/game loop split inside `src/game`. -2. Add a fixed-timestep simulation clock and frame-independent rendering interpolation only if needed. -3. Define a minimal world model: tiles, actors, hitboxes, health, attacks, and simple room reset. -4. Record player input per simulation tick, not positions first. -5. Replay an echo by feeding recorded input into the same actor controller. -6. Add divergence handling only after basic replay works. -7. Add death events, remembered gear, and corpse recovery as data owned by run history. -8. Expand dungeon generation/content after the run/echo loop is proven. +1. Establish an app/game loop split inside `src/game` and an authoritative `src/sim` boundary. +2. Add a deterministic fixed-timestep simulation clock and command-history replay substrate. +3. Add a headless run harness that can drive simulation from text/scripted input and emit deterministic transcript/digest output. +4. Render a primitive player/room only after the headless simulation path exists. +5. Define a minimal world model: tiles, actors, hitboxes, health, attacks, and simple room reset. +6. Replay an echo by feeding recorded input into the same actor controller. +7. Add guide tracks, landmarks, deviation scoring, local correction, and severing. +8. Add death events, remembered gear, and corpse recovery as data owned by run history. +9. Expand dungeon generation/content after the run/echo loop is proven. ## Three-Month Milestones @@ -115,14 +119,16 @@ Exit criteria: ## Near-Term Implementation Queue -1. Replace the blank frame with a controllable player dot in a fixed arena. -2. Add fixed-step input sampling and movement state. -3. Add simple tile collision. -4. Add one enemy and health/death. -5. Record input history for a run. -6. Restart after death and spawn an echo from the prior input history. -7. Make the echo share the same movement/combat code path as the player. -8. Add death markers and a simple resolution when an echo reaches its marker. +1. Build deterministic fixed-step simulation and command-history replay in `src/sim`. +2. Add canonical state digest/comparison and a command-line replay test recipe. +3. Add a headless text/script harness that can run simulation without Raylib and emit stable transcript output. +4. Render a controllable player marker in a fixed arena from simulation state. +5. Add simple tile collision. +6. Add one enemy and health/death. +7. Restart after death and spawn an echo from the prior input history. +8. Make the echo share the same movement/combat code path as the player. +9. Add guide tracks, landmarks, deviation scoring, local correction, and severing. +10. Add death markers, corpse/gear ownership, and simple resolution when an echo reaches its marker. ## Early Non-Goals @@ -137,10 +143,10 @@ Exit criteria: ## Open Design Questions - Should echoes collide with the live player, or only with enemies/world geometry? **For now, let's have them phase through player** -- Should replay store raw inputs, resolved intentions, or both? **Need to think through this deeply** +- Should replay store raw inputs, resolved intentions, or both? **Current direction: store normalized, quantized simulation commands as the causative record; store derived transcript/landmarks for proof, debugging, and echo correction.** - Should enemies be deterministic per run seed, or should echoes adapt to changed enemy positions immediately? **Need to think through this still** - How many echoes can be present before readability breaks? -- Is corruption random, condition-based, or both? **All outcomes of echoes at end of life are random. Dissolution should be highest chance, with corruption / allyship as rarer events. My initial thought was 4/6 chance for dissolution, 1/6 for ally, 1/6 for corrupt. +- Is corruption random, condition-based, or both? **All outcomes of echoes at end of life are random. Dissolution should be highest chance, with corruption / allyship as rarer events. My initial thought was 4/6 chance for dissolution, 1/6 for ally, 1/6 for corrupt.** ## Design Notes @@ -161,6 +167,6 @@ Movement is continuous and real-time Visibility is low light / fog for gameplay readability, not just atmosphere Fixed authoritative simulation at 60hz with variable rendering -- game state only changes in fixed simulation tickets, rendering reads state and draws it +- game state only changes in fixed simulation ticks, rendering reads state and draws it - real frame time -> accumulator -> 0..N fixed sim ticks -> render once - SIM_HZ = 60, SIM_DT = 1.0 / 60.0 diff --git a/docs/pitch.md b/docs/pitch.md index 44a2302..56c6635 100644 --- a/docs/pitch.md +++ b/docs/pitch.md @@ -1,7 +1,5 @@ # Thanatograph -# Working Title: Echo Dungeon - ## Core Idea A brutally difficult dungeon crawler with permadeath where every failed attempt becomes part of the next run. diff --git a/docs/tickets/todo/002-fixed-step-replay.md b/docs/tickets/todo/002-fixed-step-replay.md index 090ba45..503eb68 100644 --- a/docs/tickets/todo/002-fixed-step-replay.md +++ b/docs/tickets/todo/002-fixed-step-replay.md @@ -1,8 +1,8 @@ -# T002: Build Fixed-Step Simulation and Replay Machinery +# T002: Build Deterministic Fixed-Step Simulation and Replay Substrate ## Goal -Build the deterministic simulation clock and replay/input-history foundation before rendering gameplay. +Build the deterministic simulation clock, command-history foundation, and replay proof before rendering gameplay. The project should be able to prove, in code, that the same initial state plus the same tick-indexed input stream produces the same resulting simulation state. @@ -10,7 +10,20 @@ The project should be able to prove, in code, that the same initial state plus t Thanatograph depends on past runs becoming physical echoes. That means the simulation must be authoritative, tick-based, and replayable from the beginning. Rendering should never be required to verify replay correctness. -This is a core programming slice, not a visual slice. +This is a core programming slice, not a visual slice. The long-term target is that an entire run can be recreated from a deterministic record: simulation version/config, seed, initial state descriptor, and one command per tick. A derived transcript may describe what happened, but replay authority should come from the command stream and deterministic simulation, not from recorded positions. + +The `src/sim` package is the boundary for this work. It should remain free of Raylib, rendering, frame-time, and platform APIs so replay correctness can be tested without opening a window. + +## Deterministic Run Contract + +Separate two related records: + +- **Causative run record:** the data needed to recreate a run, starting with config/version identity, seed, initial state descriptor, and a tick-indexed command stream. +- **Derived transcript:** deterministic facts emitted by simulation for inspection, debugging, text tests, and later echo guidance. Examples include state digests, actor positions, deaths, damage events, item events, landmarks, and echo resolution events. + +The causative record recreates the run. The transcript proves and explains the run. + +For this ticket, the transcript can be minimal. It only needs enough information to prove deterministic replay. The important part is establishing the boundary and avoiding an event-log design where derived facts become the authority for gameplay. ## Requirements @@ -23,6 +36,12 @@ This is a core programming slice, not a visual slice. - Provide a way to replay a recorded command stream from tick `0` into a fresh simulation state. - Add deterministic test coverage for replay behavior without requiring Raylib rendering. - Keep all gameplay-relevant randomness behind deterministic seeds, even if randomness is only stubbed in this ticket. +- Add a canonical simulation digest or explicit state comparison path for replay tests. +- Keep `src/sim` independent from Raylib, wall-clock frame time, rendering state, hardware input, and platform APIs. +- Treat `sim_tick` as the only authoritative gameplay mutation path. +- Store gameplay timers as integer ticks, not seconds. +- Avoid authoritative simulation dependence on pointer addresses, unordered iteration, global random state, wall-clock time, render frame count, or raw struct memory layout. +- Prefer quantized/integer/fixed-point simulation values for replay-relevant state. Rendering may convert simulation state to floats later. ## Suggested Implementation Direction @@ -31,6 +50,10 @@ This is a core programming slice, not a visual slice. - Cap max simulation ticks per rendered frame to avoid death spirals. - Store timers as ticks, not seconds, for gameplay-relevant state. - Keep replay tests focused on simple state transitions first, such as position changing under input commands. +- If `Input_Command` contains analog values, quantize them before they become persistent replay data. +- Add a small deterministic PRNG state owned by `Sim_State`, even if this ticket only verifies that seeded state round-trips. +- Hash or compare canonical fields explicitly for replay verification. Do not hash raw struct memory. +- Keep player movement minimal if added here. The goal is determinism proof, not game feel. Recommended constants: @@ -54,6 +77,14 @@ Example scenario: The test does not need enemies, collision, rendering, or real player art. +Useful first test variants: + +- Run a fixed command sequence from a known seed and capture final state/digest. +- Re-initialize from the same seed and replay the recorded commands. +- Assert identical final tick, final state, command count, and digest. +- Run the same command stream through different artificial frame-delta batches and assert the same final state. +- Verify the command history contains exactly one command for each simulated tick. + ## Acceptance Criteria - Simulation state advances at exactly one logical tick per fixed update. @@ -62,10 +93,13 @@ The test does not need enemies, collision, rendering, or real player art. - A recorded input stream can be replayed into a fresh simulation state with identical results. - At least one deterministic replay test can run from a command line recipe. - Gameplay code does not depend on `rl.GetFrameTime()` for simulation mutation. +- `src/sim` can be checked/tested without Raylib and without opening a window. +- Replay verification uses canonical state comparison or digesting, not recorded positions as authority. +- Simulation randomness, even if unused by gameplay, is seed-driven and owned by simulation state. - `just check` passes. ## Notes - This ticket intentionally comes before visual player rendering. - Position recording may be useful for debugging, but replay should be driven by input commands, not authoritative position playback. -- The test harness can be minimal. It only needs to protect the core assumption that echoes are possible. +- A text transcript is useful, but the fuller headless/text workflow belongs in T003. This ticket only needs enough transcript/digest support to prove replay determinism. diff --git a/docs/tickets/todo/003-headless-run-harness.md b/docs/tickets/todo/003-headless-run-harness.md new file mode 100644 index 0000000..2b5a5ca --- /dev/null +++ b/docs/tickets/todo/003-headless-run-harness.md @@ -0,0 +1,63 @@ +# T003: Add Headless Run Harness and Text Transcript + +## Goal + +Create a command-line, no-render simulation harness that can run scripted inputs and emit deterministic text output. + +## Context + +T002 proves that deterministic replay works in code. This ticket makes that proof easy to inspect and iterate on without opening a window. + +The game should be testable as plain text before it is visually interesting. A developer should be able to feed a small script into the simulation, run it from the terminal, and compare the output transcript or final digest. + +This is still not a gameplay-content ticket. The transcript can describe a tiny prototype state. The goal is to establish the habit that simulation behavior can be exercised, reproduced, and audited headlessly. + +## Requirements + +- Add a headless executable or `just` recipe that runs `src/sim` without Raylib. +- Accept a small deterministic input script or hard-coded fixture format for prototype runs. +- Convert scripted input into the same normalized simulation command type used by replay. +- Emit a stable text transcript with tick-indexed simulation facts. +- Emit a final canonical state digest or explicit final-state summary. +- Keep transcript output deterministic across repeated runs. +- Keep the transcript derived from simulation state. It must not become the authoritative replay source. +- Add at least one fixture that can be re-run from the command line. +- Keep the harness small and deleteable if a better test runner replaces it later. + +## Suggested Script Shape + +The exact format is flexible. A simple line-oriented fixture is enough: + +```text +seed 123 +ticks 30 move_right +ticks 10 move_up +ticks 5 attack +``` + +Potential output shape: + +```text +run seed 123 +tick 000030 actor player pos 30,0 +tick 000040 actor player pos 30,-10 +tick 000045 event attack actor player +final tick 45 +final digest abc123 +``` + +Do not overbuild the parser. It only needs to support the small command vocabulary required by current simulation tests. + +## Acceptance Criteria + +- A command-line recipe can run a deterministic simulation fixture without opening a window. +- The same fixture produces identical transcript/digest output across repeated runs. +- The fixture path exercises the same simulation tick and command-recording machinery as replay. +- Text output is stable enough to be used in future regression tests. +- No Raylib or renderer dependency is introduced into `src/sim`. +- `just check` passes. + +## Notes + +- No rendering, enemies, inventory, dungeon generation, echo visuals, or combat depth in this ticket. +- This ticket intentionally comes before the first visible player marker. diff --git a/docs/tickets/todo/003-basic-rendering.md b/docs/tickets/todo/004-basic-rendering.md similarity index 50% rename from docs/tickets/todo/003-basic-rendering.md rename to docs/tickets/todo/004-basic-rendering.md index f6538aa..45cba58 100644 --- a/docs/tickets/todo/003-basic-rendering.md +++ b/docs/tickets/todo/004-basic-rendering.md @@ -1,14 +1,14 @@ -# T003: Render Player in a Small Room +# T004: Render Player in a Small Room ## Goal -Render the first visible prototype scene on top of the fixed-step simulation foundation: a player represented by a simple shape inside a small room. +Render the first visible prototype scene on top of the fixed-step simulation and headless replay foundation: a player represented by a simple shape inside a small room. ## Context -This ticket should happen after the fixed-step and replay slice is in place. Rendering should observe simulation state, not drive it. +This ticket should happen after the deterministic simulation substrate and headless text harness are in place. Rendering should observe simulation state, not drive it. -The visual target is intentionally primitive. The goal is to confirm the architecture supports drawing world state cleanly. +The visual target is intentionally primitive. The goal is to confirm the architecture supports drawing world state cleanly while preserving the ability to test the same behavior without graphics. ## Requirements @@ -17,8 +17,9 @@ The visual target is intentionally primitive. The goal is to confirm the archite - Move the player using normalized simulation input and fixed-step updates. - Use a player-follow camera. - Keep rendering independent from simulation mutation. -- Add basic debug text for simulation tick and frame timing. +- Add basic debug text for simulation tick, frame timing, and replay/digest state if already available. - Preserve hot reload behavior. +- Do not introduce gameplay behavior that cannot also run through the headless simulation path. ## Suggested Prototype Details @@ -26,6 +27,7 @@ The visual target is intentionally primitive. The goal is to confirm the archite - Use a single hard-coded room before building tile maps. - Draw the player as a circle with an aim/facing indicator if input already supports aim. - Keep the camera centered on the player, with smoothing deferred unless needed. +- Convert simulation coordinates into render coordinates at the boundary. Avoid storing render-only floats in authoritative simulation state. ## Acceptance Criteria @@ -33,9 +35,10 @@ The visual target is intentionally primitive. The goal is to confirm the archite - Player movement is simulation-driven and consistent across render frame rates. - Rendering uses current simulation state and optional interpolation state; it does not mutate gameplay state. - Debug overlay shows at least current simulation tick. +- The same movement behavior remains testable through the headless harness. - `just check` passes. ## Notes - No fog of war, enemies, attacks, inventory, dungeon generation, or echo visuals in this ticket. -- If interpolation is cheap after T002, include it. Otherwise, defer it. +- If interpolation is cheap after T002/T003, include it. Otherwise, defer it. diff --git a/docs/tickets/todo/005-physical-echo-replay.md b/docs/tickets/todo/005-physical-echo-replay.md new file mode 100644 index 0000000..1f00135 --- /dev/null +++ b/docs/tickets/todo/005-physical-echo-replay.md @@ -0,0 +1,46 @@ +# T005: Replay a Prior Run as a Physical Echo + +## Goal + +Spawn a previous run as a physical echo actor that advances inside the current simulation by consuming the prior run's recorded command stream. + +## Context + +This is the first ticket where replay becomes visible as gameplay. The echo should be a real simulation actor, not a rendered ghost path and not a position playback movie. + +The first version does not need local recovery, deviation scoring, remembered gear, or rich combat. It needs to prove the core architecture: a recorded run can become an actor in a new run while sharing the same deterministic simulation rules as the live player. + +## Requirements + +- Store at least one completed run history that can be used by a later run. +- Start a new run from the same deterministic initial world setup. +- Spawn an echo actor associated with a prior `Run_History` or equivalent. +- Advance the echo one simulation tick at a time by reading the prior run's command for the corresponding tick. +- Make the echo use the same movement/controller path as the player wherever practical. +- Distinguish live-player commands from echo replay commands without duplicating gameplay logic. +- Keep the live player and echo in the same authoritative simulation world. +- Keep replay driven by command stream, not recorded positions. +- Emit transcript/debug facts that make echo tick, source run id, and replay cursor visible. + +## Suggested Implementation Direction + +- Add actor kind/state for `Player` and `Echo` only if the current world model requires it. +- Add a replay cursor per echo: source run id, current replay tick, and replay state. +- Treat missing commands past the end of a run as an explicit end-of-timeline state, not silent idle forever. +- Use a hard-coded restart/death trigger if needed; full death-event ownership belongs later. +- Keep collision/combat behavior minimal. If collisions are not ready, the echo can initially share movement in an empty arena. + +## Acceptance Criteria + +- A completed command history can be replayed as an echo in a later run. +- The echo consumes exactly one prior command per simulation tick while following the recorded timeline. +- The echo exists in simulation state and can be rendered/debugged as an actor. +- Replaying the same history from the same seed produces identical echo state/digests. +- The live player can still be controlled independently while the echo replays. +- `just check` passes. + +## Notes + +- Do not add local recovery or deviation heuristics in this ticket. +- Do not add corpse, gear, or resolution outcomes in this ticket unless a tiny placeholder is needed for flow. +- Echoes should phase through the live player for now, matching the current design note. diff --git a/docs/tickets/todo/006-echo-landmarks-deviation.md b/docs/tickets/todo/006-echo-landmarks-deviation.md new file mode 100644 index 0000000..fb582ae --- /dev/null +++ b/docs/tickets/todo/006-echo-landmarks-deviation.md @@ -0,0 +1,57 @@ +# T006: Add Echo Landmarks and Deviation Tracking + +## Goal + +Formalize how echoes know whether they are still following their original timeline, how they locally correct, and when they become independent emergent actors. + +## Context + +Echoes are not meant to be brittle recordings. They should mostly repeat the original run, but the live world may interfere: an echo can be blocked, displaced, attacked, saved, delayed, or pulled into a different fight. + +Under small divergence, the echo should try to recover toward its original fate. Past a threshold, the echo should become severed from replay and continue as an independent AI timeline. + +This ticket introduces the data model and first heuristic. It does not need to make the heuristic perfect. + +## Requirements + +- Add sparse guide data derived from a run history, such as actor position/facing every N ticks. +- Add semantic landmarks derived from simulation events, such as room entry, attack, damage, item use, enemy engagement, death point, or other locally meaningful milestones. +- Track each echo's replay mode: following, correcting, severed, and resolved or equivalent. +- Compute a deterministic deviation score for an echo. +- Allow small deviation to enter local correction instead of immediately abandoning replay. +- Allow large deviation to sever the echo from its original command stream. +- Keep deviation scoring deterministic and testable without rendering. +- Emit transcript/debug facts for replay mode, current landmark, and deviation score. + +## Suggested Deviation Inputs + +- Spatial distance from expected guide position. +- Tick delay or lead relative to expected timeline. +- Missed or reordered semantic landmarks. +- Unexpected displacement or blocked duration. +- Unexpected damage, death, or target changes. +- Distance from original death/fate path. + +The first implementation can use only a subset. Prefer one understandable score over several half-built systems. + +## Suggested Implementation Direction + +- Generate guide samples after a run completes, not during every echo tick, unless it is simpler to do both together. +- Keep guide samples sparse so long runs do not become expensive to store. +- Start with correction toward the next guide sample or landmark before introducing full pathfinding. +- Use deterministic thresholds configured in `src/sim/config.odin` or nearby simulation config. +- Make severing explicit. Once severed, an echo should stop consuming replay commands unless a later design intentionally supports reattachment. + +## Acceptance Criteria + +- Echoes have an explicit replay/deviation mode in simulation state. +- A deterministic deviation score can be inspected in headless transcript output. +- A mildly displaced echo can correct toward its timeline. +- A heavily displaced echo can become severed and stop acting as a strict replay. +- Re-running the same scripted scenario produces the same mode transitions and final digest. +- `just check` passes. + +## Notes + +- This is the foundation for emergent echo behavior. Keep it small but make the state model durable. +- Do not tune for final game feel yet. Tune for legibility, determinism, and debuggability. diff --git a/docs/tickets/todo/007-death-events-corpses-gear.md b/docs/tickets/todo/007-death-events-corpses-gear.md new file mode 100644 index 0000000..5801bb8 --- /dev/null +++ b/docs/tickets/todo/007-death-events-corpses-gear.md @@ -0,0 +1,52 @@ +# T007: Add Death Events, Corpses, and Remembered Gear Ownership + +## Goal + +Represent player death as durable run history that can produce future echoes, death markers, recoverable corpses, and remembered gear without duplicating loot freely. + +## Context + +Thanatograph's persistence model is not broad world persistence. The dungeon resets, but history remains. Death events are the anchor for that history. + +An echo is trying to reach the fate that created it. If it reaches that fate and no longer dies, it resolves. If it dies early, that echo's story ends. Remembered gear should become recoverable through corpse/death-event/echo resolution rules, not by spawning duplicate items at run start. + +## Requirements + +- Add a durable `Death_Event` or equivalent owned by run history. +- Record death tick, death position, source run id, and enough context to drive an echo fate marker. +- Record remembered gear/loadout as data associated with the death event or run history. +- Spawn a death marker or corpse representation in later runs. +- Make an echo aware of its target death event/fate. +- Add a simple resolution path when an echo reaches its death marker/end of timeline. +- Preserve the rule that echoes use remembered gear but do not duplicate live-run loot into the dungeon at run start. +- Keep death events and remembered gear deterministic and serializable in principle. + +## Suggested Resolution Outcomes + +- Evaporate: the echo vanishes, its timeline complete. +- Corrupt: the echo becomes hostile and continues as an independent actor. +- Ally: the echo joins the player temporarily. + +Initial odds can be simple and deterministic through seeded simulation RNG. A starting design target is evaporation as the most common outcome, with corruption and allyship rarer. + +## Suggested Implementation Direction + +- Start with one gear/item placeholder if inventory does not exist yet. +- Add the ownership rules before adding loot variety. +- Treat remembered gear as echo equipment, not a physical duplicate in the live dungeon. +- Make gear recoverability explicit at corpse or resolution time. +- Keep output visible in the headless transcript before investing in rendering polish. + +## Acceptance Criteria + +- Player death creates a durable death event tied to the completed run. +- A later run can spawn an echo that targets its original death event. +- A death marker/corpse can be inspected in simulation state and transcript output. +- Remembered gear is associated with history and does not duplicate as normal live-run loot at run start. +- Echo end-of-timeline resolution is deterministic for a given seed and state. +- `just check` passes. + +## Notes + +- This ticket may stay visually primitive. The important work is ownership, persistence boundaries, and deterministic behavior. +- Full inventory UI, loot tables, and final combat balance are out of scope. -- knotmirror 0.0.1