From 2cd17e293a7cb2ce77963892008bfa6c028b344a Mon Sep 17 00:00:00 2001 From: VinPropane Date: Sun, 24 May 2026 16:16:51 -0400 Subject: [PATCH] chore: Epic 3 Slice 5 client backlog and full-stack epic policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add E3S5-client-prototype-backlog (NEO-72–NEO-75), epic_03 Slice 5, full-stack epics rule in decomposition README, and cross-links from E3 module docs and prototype backlogs. --- docs/decomposition/README.md | 10 + .../epics/epic_03_crafting_economy.md | 23 ++- .../E3_M1_ResourceNodeAndGatherLoop.md | 2 +- .../E3_M2_RefinementAndRecipeExecution.md | 2 +- .../E3_M3_ItemizationAndInventorySchema.md | 2 +- ...umentation_and_implementation_alignment.md | 6 +- .../modules/module_dependency_register.md | 2 + docs/plans/E3M1-prototype-backlog.md | 3 +- docs/plans/E3M2-prototype-backlog.md | 5 +- docs/plans/E3M3-prototype-backlog.md | 3 +- docs/plans/E3S5-client-prototype-backlog.md | 171 ++++++++++++++++++ 11 files changed, 215 insertions(+), 14 deletions(-) create mode 100644 docs/plans/E3S5-client-prototype-backlog.md diff --git a/docs/decomposition/README.md b/docs/decomposition/README.md index 2e7b42f..1f72a05 100644 --- a/docs/decomposition/README.md +++ b/docs/decomposition/README.md @@ -20,6 +20,16 @@ This workspace contains detailed planning artifacts derived from the finalized m 3. Use stable IDs (`E1`, `E1.M1`, etc.) for core game epics; use **`CT.M1`**-style IDs for [content tooling](tooling/internal_authoring.md) so tooling stays out of the E1–E9 sequence. 4. Every new slice must reference telemetry and validation where applicable. +## Full-stack epics + +**Epics deliver playable game features**, not server-only vertical slices. When decomposing a prototype backlog (`docs/plans/E*M*-prototype-backlog.md` or slice-specific files like [E3S5-client-prototype-backlog.md](../plans/E3S5-client-prototype-backlog.md)): + +1. **Pair server and client stories** where the feature is player-visible (mirror Epic 1: NEO-23 + NEO-24). +2. **Create all Linear issues and `blockedBy` links in the same decomposition pass** — including client slices — not as undocumented “optional follow-ups.” +3. **Bruno / manual QA** prove contracts; **Godot** proves the prototype fun/readability gates in [vision](../../neon_sprawl_vision.plan.md). + +Epic 3 established this pattern with **Slice 5 — Client economy integration** after Slices 1–3 server work. Apply the same pattern to other epics going forward. + ## Linear alignment Engineering work is tracked as **issues** in **Linear** (team **NEO**), grouped under **projects** that mirror epics and modules. **Do not** recreate a Jira-style **Feature** issue tier—module- or slice-level grouping is **labels on the issue** only. diff --git a/docs/decomposition/epics/epic_03_crafting_economy.md b/docs/decomposition/epics/epic_03_crafting_economy.md index 04252a9..9729ca0 100644 --- a/docs/decomposition/epics/epic_03_crafting_economy.md +++ b/docs/decomposition/epics/epic_03_crafting_economy.md @@ -7,8 +7,8 @@ ## Ownership and success (Level 1) -- **Ownership focus:** Economy Design + Content Engineering -- **Success criteria:** Crafting is a primary progression lane with healthy supply-demand loops and consistent item relevance. +- **Ownership focus:** Economy Design + Content Engineering + **Client presentation (Godot)** +- **Success criteria:** Crafting is a primary progression lane with healthy supply-demand loops and consistent item relevance — **playable in the client**, not server/Bruno-only proof. ## Objective @@ -82,6 +82,20 @@ Implement gathering from world nodes, item/inventory representation, recipe exec - Player completes gather to refine to usable item used in combat or quest. - Telemetry hooks: `item_crafted`, `craft_failed` with reason, time-to-first-craft. + + +### Slice 5 - Client economy integration (prototype) + +- Scope: Godot clients + HUD for **E3.M3** inventory, **E3.M1** gather feedback, **E3.M2** craft UI; playable **gather → refine → make** session in the client (vision prototype gates). +- Dependencies: Slice 1–3 server APIs landed ([NEO-55](https://linear.app/neon-sprawl/issue/NEO-55), [NEO-63](https://linear.app/neon-sprawl/issue/NEO-63), [NEO-70](https://linear.app/neon-sprawl/issue/NEO-70)); [E2.M2](https://linear.app/neon-sprawl/issue/NEO-37) skill-progression GET for XP visibility. +- Acceptance criteria: + - Inventory HUD reflects server state after gather and craft. + - Player completes **gather → refine → usable item** in Godot without Bruno. + - **Salvage** / **refine** skill progression visible after gather/craft (Epic 2 Slice 3 integration AC). +- Telemetry hooks: reuse Slice 1–3 server hook sites; client dev **`print`** / HUD feedback only until E9.M1 ingest. + +**Linear backlog:** [E3S5-client-prototype-backlog.md](../../plans/E3S5-client-prototype-backlog.md) — [NEO-72](https://linear.app/neon-sprawl/issue/NEO-72) → [NEO-75](https://linear.app/neon-sprawl/issue/NEO-75). + ### Slice 4 - Sinks and economy policy (pre-production) @@ -101,5 +115,6 @@ Implement gathering from world nodes, item/inventory representation, recipe exec ## Definition of Done -- Prototype gather-craft loop meets plan pass/fail gates. -- Pre-production adds sinks and policy with dashboard visibility. +- Prototype gather-craft loop meets plan pass/fail gates **in the Godot client** (Slice 5), not Bruno-only. +- Slices 1–3 + Slice 5 together satisfy [vision prototype in-scope features](../../../neon_sprawl_vision.plan.md) for crafting loop and progression visibility. +- Pre-production adds sinks and policy with dashboard visibility (Slice 4). diff --git a/docs/decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md b/docs/decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md index 5c27c9c..17d7760 100644 --- a/docs/decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md +++ b/docs/decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md @@ -102,7 +102,7 @@ Epic 3 **Slice 2** — [gather nodes and outputs](../epics/epic_03_crafting_econ **Resource node instance depletion store (NEO-61):** **`IResourceNodeInstanceStore`** + **`ResourceNodeInstanceOperations`** — lazy-init remaining gathers from catalog **`maxGathers`**, atomic decrement, **`node_depleted`** / **`unknown_node`** reason codes; Postgres **`V006`** or in-memory fallback. Plan: [NEO-61 implementation plan](../../plans/NEO-61-implementation-plan.md). -**Linear backlog (decomposed):** [E3M1-prototype-backlog.md](../../plans/E3M1-prototype-backlog.md) — **E3M1-01** [NEO-57](https://linear.app/neon-sprawl/issue/NEO-57) through **E3M1-08** [NEO-64](https://linear.app/neon-sprawl/issue/NEO-64). +**Linear backlog (decomposed):** [E3M1-prototype-backlog.md](../../plans/E3M1-prototype-backlog.md) — **E3M1-01** [NEO-57](https://linear.app/neon-sprawl/issue/NEO-57) through **E3M1-08** [NEO-64](https://linear.app/neon-sprawl/issue/NEO-64). **Client (Slice 5):** gather feedback — [E3S5-client-prototype-backlog.md](../../plans/E3S5-client-prototype-backlog.md) **E3S5-02** [NEO-73](https://linear.app/neon-sprawl/issue/NEO-73). ## Source anchors diff --git a/docs/decomposition/modules/E3_M2_RefinementAndRecipeExecution.md b/docs/decomposition/modules/E3_M2_RefinementAndRecipeExecution.md index 0080e6c..2aca9fc 100644 --- a/docs/decomposition/modules/E3_M2_RefinementAndRecipeExecution.md +++ b/docs/decomposition/modules/E3_M2_RefinementAndRecipeExecution.md @@ -74,7 +74,7 @@ The **first shipped eight-recipe spine** under `content/recipes/*.json` is **fro Epic 3 **Slice 3** — gather → refine → item used in combat or quest; telemetry `item_crafted`, `craft_failed`, time-to-first-craft. -**Linear backlog (decomposed):** [E3M2-prototype-backlog.md](../../plans/E3M2-prototype-backlog.md) — **E3M2-01** [NEO-65](https://linear.app/neon-sprawl/issue/NEO-65) (content + CI) through **E3M2-07** [NEO-71](https://linear.app/neon-sprawl/issue/NEO-71) (telemetry hooks). +**Linear backlog (decomposed):** [E3M2-prototype-backlog.md](../../plans/E3M2-prototype-backlog.md) — **E3M2-01** [NEO-65](https://linear.app/neon-sprawl/issue/NEO-65) (content + CI) through **E3M2-07** [NEO-71](https://linear.app/neon-sprawl/issue/NEO-71) (telemetry hooks). **Client (Slice 5):** craft UI — [E3S5-client-prototype-backlog.md](../../plans/E3S5-client-prototype-backlog.md) **E3S5-03** [NEO-74](https://linear.app/neon-sprawl/issue/NEO-74). ## Risks and telemetry diff --git a/docs/decomposition/modules/E3_M3_ItemizationAndInventorySchema.md b/docs/decomposition/modules/E3_M3_ItemizationAndInventorySchema.md index 2665878..b823d21 100644 --- a/docs/decomposition/modules/E3_M3_ItemizationAndInventorySchema.md +++ b/docs/decomposition/modules/E3_M3_ItemizationAndInventorySchema.md @@ -74,7 +74,7 @@ Epic 3 **Slice 1** — MVP inventory; `item_created`, transfer failures. **Inventory telemetry hooks (NEO-56):** comment-only **`item_created`** (successful add) and **`inventory_transfer_denied`** + **`reasonCode`** anchors in **`PlayerInventoryOperations`**; [server README — Player inventory (NEO-56)](../../../server/README.md#player-inventory-neo-54-store-neo-55-http). Plan: [NEO-56 implementation plan](../../plans/NEO-56-implementation-plan.md); manual QA [`NEO-56`](../../manual-qa/NEO-56.md). -**Linear backlog (decomposed):** [E3M3-prototype-backlog.md](../../plans/E3M3-prototype-backlog.md) — **E3M3-01** [NEO-50](https://linear.app/neon-sprawl/issue/NEO-50) (content + CI) through **E3M3-07** [NEO-56](https://linear.app/neon-sprawl/issue/NEO-56) (telemetry hooks). +**Linear backlog (decomposed):** [E3M3-prototype-backlog.md](../../plans/E3M3-prototype-backlog.md) — **E3M3-01** [NEO-50](https://linear.app/neon-sprawl/issue/NEO-50) (content + CI) through **E3M3-07** [NEO-56](https://linear.app/neon-sprawl/issue/NEO-56) (telemetry hooks). **Client (Slice 5):** inventory HUD — [E3S5-client-prototype-backlog.md](../../plans/E3S5-client-prototype-backlog.md) **E3S5-01** [NEO-72](https://linear.app/neon-sprawl/issue/NEO-72). ## Source anchors diff --git a/docs/decomposition/modules/documentation_and_implementation_alignment.md b/docs/decomposition/modules/documentation_and_implementation_alignment.md index 86af2a2..63ec1ba 100644 --- a/docs/decomposition/modules/documentation_and_implementation_alignment.md +++ b/docs/decomposition/modules/documentation_and_implementation_alignment.md @@ -53,9 +53,9 @@ Rows appear when work starts; default for unlisted modules is **Planned** / not | E2.M1 | In Progress | **NEO-33 landed:** frozen prototype trio **`salvage`** / **`refine`** / **`intrusion`** in [`content/skills/prototype_skills.json`](../../../content/skills/prototype_skills.json); PR gate + [`validate_content.py`](../../../scripts/validate_content.py) enforce schema, duplicate `id`, exact trio ids, and category coverage; designer note on **`allowedXpSourceKinds`** in [E2_M1](E2_M1_SkillDefinitionRegistry.md) + [`content/README.md`](../../../content/README.md). **NEO-34 landed:** fail-fast server load of `content/skills/*.json` at startup — `server/NeonSprawl.Server/Game/Skills/` ([NEO-34](../../plans/NEO-34-implementation-plan.md)); config + discovery in [server README — Skill catalog](../../../server/README.md#skill-catalog-contentskills-neo-34). **NEO-35 landed:** `ISkillDefinitionRegistry` / `SkillDefinitionRegistry` + DI ([NEO-35](../../plans/NEO-35-implementation-plan.md)). **NEO-36 landed:** versioned **`GET /game/world/skill-definitions`** ([NEO-36](../../plans/NEO-36-implementation-plan.md)) — `SkillDefinitionsWorldApi` + `SkillDefinitionsListDtos` in `server/NeonSprawl.Server/Game/Skills/`; Bruno `bruno/neon-sprawl-server/skill-definitions/`; manual QA [`NEO-36`](../../manual-qa/NEO-36.md). **E2.M2 consumer (NEO-38 landed):** grant path validates `skillId` + `sourceKind` vs catalog **`allowedXpSourceKinds`** on **`POST …/skill-progression`** ([NEO-38](../../plans/NEO-38-implementation-plan.md)); see [server README — Skill progression grant](../../../server/README.md#skill-progression-grant-neo-38) and [E2_M2](E2_M2_XpAwardAndLevelEngine.md). | [NEO-33](../../plans/NEO-33-implementation-plan.md), [NEO-34](../../plans/NEO-34-implementation-plan.md), [NEO-35](../../plans/NEO-35-implementation-plan.md), [NEO-36](../../plans/NEO-36-implementation-plan.md); [E2_M1](E2_M1_SkillDefinitionRegistry.md); [module_dependency_register.md](module_dependency_register.md) **E2.M1 note**; `server/NeonSprawl.Server/Game/Skills/`; [`docs/manual-qa/NEO-36.md`](../../manual-qa/NEO-36.md); [server README — Skill definitions (NEO-36)](../../../server/README.md#skill-definitions-neo-36) | | E2.M3 | In Progress | **NEO-45 landed:** prototype **`salvage`** mastery catalog + CI gates (see [NEO-45 plan](../../plans/NEO-45-implementation-plan.md)). **NEO-46 landed:** fail-fast server load under `server/NeonSprawl.Server/Game/Mastery/` — `MasteryCatalogLoader`, `IMasteryCatalogRegistry`, cross-check vs `ISkillDefinitionRegistry`, Slice 4 + **`tierIndex`** 1..N gate; see [NEO-46 plan](../../plans/NEO-46-implementation-plan.md). **NEO-47 landed:** `PerkUnlockEngine`, `IPlayerPerkStateStore` + **`V004`**, level-up hook in skill XP grants; see [NEO-47 plan](../../plans/NEO-47-implementation-plan.md). **NEO-49 landed:** comment-only **`perk_unlock`** telemetry hook site in [`PerkUnlockEngine.TryUnlockPerks`](../../../server/NeonSprawl.Server/Game/Mastery/PerkUnlockEngine.cs) ([NEO-49 plan](../../plans/NEO-49-implementation-plan.md), [`NEO-49` manual QA](../../manual-qa/NEO-49.md)); [server README — Perk unlock telemetry (NEO-49)](../../../server/README.md#perk-unlock-engine-and-telemetry-hooks-neo-47-neo-49). **NEO-48 landed:** **`GET`/`POST /game/players/{id}/perk-state`** — `PerkStateApi` + DTOs in `Game/Mastery/` ([NEO-48](../../plans/NEO-48-implementation-plan.md), [`NEO-48` manual QA](../../manual-qa/NEO-48.md)); [server README — Perk state (NEO-48)](../../../server/README.md#perk-state-neo-48); Bruno `bruno/neon-sprawl-server/perk-state/`. | [NEO-45](../../plans/NEO-45-implementation-plan.md), [NEO-46](../../plans/NEO-46-implementation-plan.md), [NEO-47](../../plans/NEO-47-implementation-plan.md), [NEO-48](../../plans/NEO-48-implementation-plan.md), [NEO-49](../../plans/NEO-49-implementation-plan.md), [E2M3-pre-production-backlog](../../plans/E2M3-pre-production-backlog.md), [E2_M3](E2_M3_MasteryAndPerkUnlocks.md) | | E2.M2 | In Progress | **NEO-37 landed:** versioned **`GET /game/players/{id}/skill-progression`** ([NEO-37](../../plans/NEO-37-implementation-plan.md)) — read model for every registered skill; known-player gate via `IPositionStateStore`; [server README — Skill progression snapshot (NEO-37)](../../../server/README.md#skill-progression-snapshot-neo-37); manual QA [`NEO-37`](../../manual-qa/NEO-37.md). **NEO-38 landed:** **`POST`** same path — grant apply, persistence (`IPlayerSkillProgressionStore`, `V003` migration), structured denies + **`levelUps`** ([NEO-38](../../plans/NEO-38-implementation-plan.md)); manual QA [`NEO-38`](../../manual-qa/NEO-38.md); Bruno `bruno/neon-sprawl-server/skill-progression/`; [server README — Skill progression grant (NEO-38)](../../../server/README.md#skill-progression-grant-neo-38). **NEO-39 landed:** data-driven `LevelCurve` content + schema + CI validation (`*_level_curve.json`) with fail-fast startup schema checks; progression GET/POST level resolution now uses `ISkillLevelCurve` content-backed thresholds ([NEO-39](../../plans/NEO-39-implementation-plan.md)); manual QA [`NEO-39`](../../manual-qa/NEO-39.md). **NEO-40 landed:** comment-only telemetry hook sites in [`SkillProgressionSnapshotApi.cs`](../../../server/NeonSprawl.Server/Game/Skills/SkillProgressionSnapshotApi.cs) on **`POST …/skill-progression`** for future **`xp_grant`** / **`level_up`** ([NEO-40](../../plans/NEO-40-implementation-plan.md), [`NEO-40` manual QA](../../manual-qa/NEO-40.md)). **NEO-41 landed:** gather prototype — **`POST …/interact`** with **`kind: resource_node`** grants **`salvage`** + **`activity`** (10 XP) via [`SkillProgressionGrantOperations`](../../../server/NeonSprawl.Server/Game/Skills/SkillProgressionGrantOperations.cs) ([NEO-41](../../plans/NEO-41-implementation-plan.md), [`NEO-41` manual QA](../../manual-qa/NEO-41.md)); [server README — Interaction](../../../server/README.md#interaction-neo-9). **NEO-42 landed (prep):** **`RefineActivitySkillXpGrant`** / **`RefineSkillXpConstants`** + deny-registry factory + tests — same NEO-38 grant stack; **E3.M2** must invoke on craft/refine success ([NEO-42](../../plans/NEO-42-implementation-plan.md), [`NEO-42` manual QA](../../manual-qa/NEO-42.md)); [server README — Craft / refine hook (NEO-42)](../../../server/README.md#craft--refine-hook--skill-xp-neo-42). **NEO-43 landed (prep):** **`MissionRewardSkillXpGrant`** / **`MissionRewardSkillXpConstants`** + deny-registry factory + tests — same NEO-38 grant stack with fixed **`sourceKind: mission_reward`**; **E7.M2** must invoke from quest hand-in ([NEO-43](../../plans/NEO-43-implementation-plan.md), [`NEO-43` manual QA](../../manual-qa/NEO-43.md)); [server README — Mission / quest reward (NEO-43)](../../../server/README.md#mission--quest-reward--skill-xp-neo-43). **Slice 3 still open:** [NEO-44](https://linear.app/neon-sprawl/issue/NEO-44). See [epic_02 — E2.M2 + Slice 3](../epics/epic_02_skills_and_progression.md). | [NEO-37](../../plans/NEO-37-implementation-plan.md), [NEO-38](../../plans/NEO-38-implementation-plan.md), [NEO-39](../../plans/NEO-39-implementation-plan.md), [NEO-40](../../plans/NEO-40-implementation-plan.md), [NEO-41](../../plans/NEO-41-implementation-plan.md), [NEO-42](../../plans/NEO-42-implementation-plan.md), [NEO-43](../../plans/NEO-43-implementation-plan.md), [E2_M2](E2_M2_XpAwardAndLevelEngine.md); label **`E2.M2`** on NEO-37–NEO-41, NEO-42–NEO-44 | -| E3.M1 | Ready | **NEO-41 landed (prototype, superseded on interact by NEO-63):** inline XP on **`resource_node`** interact. **NEO-57–NEO-61** — content, registry, HTTP defs, depletion store (see prior alignment). **NEO-62 landed:** **`GatherOperations`** + **`GatherResult`**. **NEO-63 landed:** **`POST …/interact`** **`resource_node`** → gather engine; **four** **`PrototypeInteractableRegistry`** anchors; Bruno gather → inventory + depletion deny ([NEO-63](../../plans/NEO-63-implementation-plan.md), [`NEO-63` manual QA](../../manual-qa/NEO-63.md)); [server README — Gather via interact (NEO-63)](../../../server/README.md#gather-via-interact-neo-63). **NEO-64 landed:** comment-only **`resource_gathered`** / **`gather_node_depleted`** hook sites in **`GatherOperations.TryGather`** ([NEO-64](../../plans/NEO-64-implementation-plan.md), [`NEO-64` manual QA](../../manual-qa/NEO-64.md)); Epic 3 Slice 2 backlog **E3M1-01**–**E3M1-08** complete. | [NEO-41](../../plans/NEO-41-implementation-plan.md) … [NEO-64](../../plans/NEO-64-implementation-plan.md), [E3_M1](E3_M1_ResourceNodeAndGatherLoop.md); `server/NeonSprawl.Server/Game/Gathering/`, `Game/Interaction/` | -| E3.M3 | In Progress | **NEO-50 landed:** frozen prototype six-item catalog in [`content/items/prototype_items.json`](../../../content/items/prototype_items.json); [`item-def.schema.json`](../../../content/schemas/item-def.schema.json); PR gate + [`validate_content.py`](../../../scripts/validate_content.py). **NEO-51 landed:** fail-fast server load of `content/items/*_items.json` at startup — `server/NeonSprawl.Server/Game/Items/` ([NEO-51](../../plans/NEO-51-implementation-plan.md)); [server README — Item catalog](../../../server/README.md#item-catalog-contentitems-neo-51). **NEO-52 landed:** injectable **`IItemDefinitionRegistry`** + lookup tests ([NEO-52](../../plans/NEO-52-implementation-plan.md)). **NEO-53 landed:** **`GET /game/world/item-definitions`** — `ItemDefinitionsWorldApi` + DTOs in `Game/Items/` ([NEO-53](../../plans/NEO-53-implementation-plan.md), [`NEO-53` manual QA](../../manual-qa/NEO-53.md)); [server README — Item definitions (NEO-53)](../../../server/README.md#item-definitions-neo-53); Bruno `bruno/neon-sprawl-server/item-definitions/`. **NEO-54 landed:** **`IPlayerInventoryStore`** + **`PlayerInventoryOperations`** — 24 bag + 1 equipment slots, stack rules, `V005` migration ([NEO-54](../../plans/NEO-54-implementation-plan.md)). **NEO-55 landed:** **`GET`/`POST /game/players/{id}/inventory`** — `PlayerInventoryApi` + DTOs in `Game/Items/` ([NEO-55](../../plans/NEO-55-implementation-plan.md)); [server README — Player inventory (NEO-54 store, NEO-55 HTTP)](../../../server/README.md#player-inventory-neo-54-store-neo-55-http); Bruno `bruno/neon-sprawl-server/inventory/`. **NEO-56 landed:** comment-only **`item_created`** / **`inventory_transfer_denied`** telemetry hook sites in [`PlayerInventoryOperations`](../../../server/NeonSprawl.Server/Game/Items/PlayerInventoryOperations.cs) ([NEO-56](../../plans/NEO-56-implementation-plan.md), [`NEO-56` manual QA](../../manual-qa/NEO-56.md)); no E9.M1 ingest. | [NEO-50](../../plans/NEO-50-implementation-plan.md), [NEO-51](../../plans/NEO-51-implementation-plan.md), [NEO-52](../../plans/NEO-52-implementation-plan.md), [NEO-53](../../plans/NEO-53-implementation-plan.md), [NEO-54](../../plans/NEO-54-implementation-plan.md), [NEO-55](../../plans/NEO-55-implementation-plan.md), [NEO-56](../../plans/NEO-56-implementation-plan.md), [E3M3-prototype-backlog](../../plans/E3M3-prototype-backlog.md), [E3_M3](E3_M3_ItemizationAndInventorySchema.md) | -| E3.M2 | Planned | **NEO-42 landed (prep):** **`RefineActivitySkillXpGrant`** — craft/refine success should award **`refine`** XP via shared NEO-38 grant path; no craft route yet. **Slice 3 backlog in Linear:** [NEO-65](https://linear.app/neon-sprawl/issue/NEO-65) → [NEO-71](https://linear.app/neon-sprawl/issue/NEO-71); [E3M2-prototype-backlog.md](../../plans/E3M2-prototype-backlog.md) — **E3M2-01**–**E3M2-07**. Upstream: E3.M1 **Ready**, E3.M3 inventory landed. | [NEO-42](../../plans/NEO-42-implementation-plan.md), [NEO-65](https://linear.app/neon-sprawl/issue/NEO-65) … [NEO-71](https://linear.app/neon-sprawl/issue/NEO-71), [E3M2-prototype-backlog](../../plans/E3M2-prototype-backlog.md), [E3_M2](E3_M2_RefinementAndRecipeExecution.md) | +| E3.M1 | Ready | **NEO-41 landed (prototype, superseded on interact by NEO-63):** inline XP on **`resource_node`** interact. **NEO-57–NEO-61** — content, registry, HTTP defs, depletion store (see prior alignment). **NEO-62 landed:** **`GatherOperations`** + **`GatherResult`**. **NEO-63 landed:** **`POST …/interact`** **`resource_node`** → gather engine; **four** **`PrototypeInteractableRegistry`** anchors; Bruno gather → inventory + depletion deny ([NEO-63](../../plans/NEO-63-implementation-plan.md), [`NEO-63` manual QA](../../manual-qa/NEO-63.md)); [server README — Gather via interact (NEO-63)](../../../server/README.md#gather-via-interact-neo-63). **NEO-64 landed:** comment-only **`resource_gathered`** / **`gather_node_depleted`** hook sites in **`GatherOperations.TryGather`** ([NEO-64](../../plans/NEO-64-implementation-plan.md), [`NEO-64` manual QA](../../manual-qa/NEO-64.md)); Epic 3 Slice 2 backlog **E3M1-01**–**E3M1-08** complete. **Slice 5 client (planned):** gather feedback HUD [NEO-73](https://linear.app/neon-sprawl/issue/NEO-73) — [E3S5 backlog](../../plans/E3S5-client-prototype-backlog.md). | [NEO-41](../../plans/NEO-41-implementation-plan.md) … [NEO-64](../../plans/NEO-64-implementation-plan.md), [E3S5-client-prototype-backlog](../../plans/E3S5-client-prototype-backlog.md), [E3_M1](E3_M1_ResourceNodeAndGatherLoop.md); `server/NeonSprawl.Server/Game/Gathering/`, `Game/Interaction/` | +| E3.M3 | In Progress | **NEO-50 landed:** frozen prototype six-item catalog in [`content/items/prototype_items.json`](../../../content/items/prototype_items.json); [`item-def.schema.json`](../../../content/schemas/item-def.schema.json); PR gate + [`validate_content.py`](../../../scripts/validate_content.py). **NEO-51 landed:** fail-fast server load of `content/items/*_items.json` at startup — `server/NeonSprawl.Server/Game/Items/` ([NEO-51](../../plans/NEO-51-implementation-plan.md)); [server README — Item catalog](../../../server/README.md#item-catalog-contentitems-neo-51). **NEO-52 landed:** injectable **`IItemDefinitionRegistry`** + lookup tests ([NEO-52](../../plans/NEO-52-implementation-plan.md)). **NEO-53 landed:** **`GET /game/world/item-definitions`** — `ItemDefinitionsWorldApi` + DTOs in `Game/Items/` ([NEO-53](../../plans/NEO-53-implementation-plan.md), [`NEO-53` manual QA](../../manual-qa/NEO-53.md)); [server README — Item definitions (NEO-53)](../../../server/README.md#item-definitions-neo-53); Bruno `bruno/neon-sprawl-server/item-definitions/`. **NEO-54 landed:** **`IPlayerInventoryStore`** + **`PlayerInventoryOperations`** — 24 bag + 1 equipment slots, stack rules, `V005` migration ([NEO-54](../../plans/NEO-54-implementation-plan.md)). **NEO-55 landed:** **`GET`/`POST /game/players/{id}/inventory`** — `PlayerInventoryApi` + DTOs in `Game/Items/` ([NEO-55](../../plans/NEO-55-implementation-plan.md)); [server README — Player inventory (NEO-54 store, NEO-55 HTTP)](../../../server/README.md#player-inventory-neo-54-store-neo-55-http); Bruno `bruno/neon-sprawl-server/inventory/`. **NEO-56 landed:** comment-only **`item_created`** / **`inventory_transfer_denied`** telemetry hook sites in [`PlayerInventoryOperations`](../../../server/NeonSprawl.Server/Game/Items/PlayerInventoryOperations.cs) ([NEO-56](../../plans/NEO-56-implementation-plan.md), [`NEO-56` manual QA](../../manual-qa/NEO-56.md)); no E9.M1 ingest. **Slice 5 client (planned):** inventory HUD [NEO-72](https://linear.app/neon-sprawl/issue/NEO-72) — [E3S5 backlog](../../plans/E3S5-client-prototype-backlog.md). | [NEO-50](../../plans/NEO-50-implementation-plan.md), [NEO-51](../../plans/NEO-51-implementation-plan.md), [NEO-52](../../plans/NEO-52-implementation-plan.md), [NEO-53](../../plans/NEO-53-implementation-plan.md), [NEO-54](../../plans/NEO-54-implementation-plan.md), [NEO-55](../../plans/NEO-55-implementation-plan.md), [NEO-56](../../plans/NEO-56-implementation-plan.md), [E3S5-client-prototype-backlog](../../plans/E3S5-client-prototype-backlog.md), [E3M3-prototype-backlog](../../plans/E3M3-prototype-backlog.md), [E3_M3](E3_M3_ItemizationAndInventorySchema.md) | +| E3.M2 | Planned | **NEO-42 landed (prep):** **`RefineActivitySkillXpGrant`** — craft/refine success should award **`refine`** XP via shared NEO-38 grant path; no craft route yet. **Slice 3 backlog in Linear:** [NEO-65](https://linear.app/neon-sprawl/issue/NEO-65) → [NEO-71](https://linear.app/neon-sprawl/issue/NEO-71); [E3M2-prototype-backlog.md](../../plans/E3M2-prototype-backlog.md) — **E3M2-01**–**E3M2-07**. Upstream: E3.M1 **Ready**, E3.M3 inventory landed. **Slice 5 client (planned):** craft UI [NEO-74](https://linear.app/neon-sprawl/issue/NEO-74); capstone playable loop [NEO-75](https://linear.app/neon-sprawl/issue/NEO-75) — [E3S5 backlog](../../plans/E3S5-client-prototype-backlog.md). | [NEO-42](../../plans/NEO-42-implementation-plan.md), [NEO-65](https://linear.app/neon-sprawl/issue/NEO-65) … [NEO-75](https://linear.app/neon-sprawl/issue/NEO-75), [E3M2-prototype-backlog](../../plans/E3M2-prototype-backlog.md), [E3S5-client-prototype-backlog](../../plans/E3S5-client-prototype-backlog.md), [E3_M2](E3_M2_RefinementAndRecipeExecution.md) | --- diff --git a/docs/decomposition/modules/module_dependency_register.md b/docs/decomposition/modules/module_dependency_register.md index a80b71d..11f28d0 100644 --- a/docs/decomposition/modules/module_dependency_register.md +++ b/docs/decomposition/modules/module_dependency_register.md @@ -54,6 +54,8 @@ Fleshed-out scope, contracts, and integration notes live in **per-module documen **E3.M2 note:** Epic 3 **Slice 3** backlog in Linear ([Epic 3 — Crafting, Gathering, and Itemization Economy](https://linear.app/neon-sprawl/project/epic-3-crafting-gathering-and-itemization-economy-65785ed05bc2)): [NEO-65](https://linear.app/neon-sprawl/issue/NEO-65) → [NEO-71](https://linear.app/neon-sprawl/issue/NEO-71); label **`E3.M2`**. See [E3M2-prototype-backlog.md](../../plans/E3M2-prototype-backlog.md), [E3_M2_RefinementAndRecipeExecution.md](E3_M2_RefinementAndRecipeExecution.md). **NEO-42** (refine XP prep helper) is **Done**; **NEO-65**–**NEO-71** created at decomposition. Upstream: E3.M1 **Ready**, E3.M3 inventory landed. +**E3 Slice 5 (client) note:** Epic 3 **client economy integration** — [NEO-72](https://linear.app/neon-sprawl/issue/NEO-72) → [NEO-75](https://linear.app/neon-sprawl/issue/NEO-75); labels **`client`** + module ids. See [E3S5-client-prototype-backlog.md](../../plans/E3S5-client-prototype-backlog.md), [epic_03 Slice 5](../epics/epic_03_crafting_economy.md#epic-3-slice-5). Required for prototype **playable** gather→craft loop (not Bruno-only). + ### Epic 4 — World Topology | Module ID | Module Name | Depends On | Contract Needed | Phase Required | Status | diff --git a/docs/plans/E3M1-prototype-backlog.md b/docs/plans/E3M1-prototype-backlog.md index c08e426..435524d 100644 --- a/docs/plans/E3M1-prototype-backlog.md +++ b/docs/plans/E3M1-prototype-backlog.md @@ -214,7 +214,7 @@ Working backlog for **Epic 3 — Slice 2** ([gather nodes and outputs](../decomp **Out of scope** -- Godot gather HUD (optional follow-up). +- Godot gather HUD — **[Epic 3 Slice 5](E3S5-client-prototype-backlog.md#e3s5-02--client-gather-feedback-on-interact-e3m1)** ([NEO-73](https://linear.app/neon-sprawl/issue/NEO-73)). - New gather-specific HTTP route. **Acceptance criteria** @@ -255,6 +255,7 @@ Working backlog for **Epic 3 — Slice 2** ([gather nodes and outputs](../decomp ## After this backlog - **[E3.M2](../decomposition/modules/E3_M2_RefinementAndRecipeExecution.md)** Slice 3 decomposed — [E3M2-prototype-backlog.md](E3M2-prototype-backlog.md) ([NEO-65](https://linear.app/neon-sprawl/issue/NEO-65)–[NEO-71](https://linear.app/neon-sprawl/issue/NEO-71)). +- **Epic 3 Slice 5 (client)** — [E3S5-client-prototype-backlog.md](E3S5-client-prototype-backlog.md) ([NEO-72](https://linear.app/neon-sprawl/issue/NEO-72)–[NEO-75](https://linear.app/neon-sprawl/issue/NEO-75)); gather HUD is **E3S5-02** [NEO-73](https://linear.app/neon-sprawl/issue/NEO-73). - Track delivery in Linear; keep `blockedBy` links synchronized if scope changes. - For each issue kickoff, add `docs/plans/{NEO-XX}-implementation-plan.md` per [story-kickoff](../../.cursor/rules/story-kickoff.md). - Add `docs/manual-qa/{NEO-XX}.md` when interact + inventory surfaces are testable (E3M1-07+). diff --git a/docs/plans/E3M2-prototype-backlog.md b/docs/plans/E3M2-prototype-backlog.md index db796ce..cb6bac7 100644 --- a/docs/plans/E3M2-prototype-backlog.md +++ b/docs/plans/E3M2-prototype-backlog.md @@ -188,7 +188,7 @@ Working backlog for **Epic 3 — Slice 3** ([recipes and crafting pipeline](../d **Out of scope** -- Godot craft UI (optional follow-up). +- Godot craft UI — **[Epic 3 Slice 5](E3S5-client-prototype-backlog.md#e3s5-03--client-craft-ui--recipe-list-e3m2)** ([NEO-74](https://linear.app/neon-sprawl/issue/NEO-74)). - Station interact / world bench placement. **Acceptance criteria** @@ -224,7 +224,8 @@ Working backlog for **Epic 3 — Slice 3** ([recipes and crafting pipeline](../d ## After this backlog -- Epic 3 prototype **gather→craft** loop is complete for Phase 1 crafting relevance gate; Slice 4 (**E3.M4** + **E3.M5**) remains pre-production. +- Epic 3 **prototype server** gather/craft spine complete when **E3M2-07** lands; **playable client loop** completes with **[Epic 3 Slice 5](E3S5-client-prototype-backlog.md)** ([NEO-72](https://linear.app/neon-sprawl/issue/NEO-72)–[NEO-75](https://linear.app/neon-sprawl/issue/NEO-75)). +- Slice 4 (**E3.M4** + **E3.M5**) sinks/policy remains pre-production. - Track delivery in Linear; keep `blockedBy` links synchronized if scope changes. - For each issue kickoff, add `docs/plans/{NEO-XX}-implementation-plan.md` per [story-kickoff](../../.cursor/rules/story-kickoff.md). - Add `docs/manual-qa/{NEO-XX}.md` when craft HTTP lands (E3M2-06+). diff --git a/docs/plans/E3M3-prototype-backlog.md b/docs/plans/E3M3-prototype-backlog.md index 02d4f3a..a207ff2 100644 --- a/docs/plans/E3M3-prototype-backlog.md +++ b/docs/plans/E3M3-prototype-backlog.md @@ -162,7 +162,7 @@ Working backlog for **Epic 3 — Slice 1** ([items and inventory MVP](../decompo **Out of scope** -- Godot HUD (optional follow-up). +- Godot HUD — **[Epic 3 Slice 5](E3S5-client-prototype-backlog.md#e3s5-01--client-inventory-snapshot-hud-e3m3)** ([NEO-72](https://linear.app/neon-sprawl/issue/NEO-72)). - Gather node depletion ([E3.M1](../decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md)). **Acceptance criteria** @@ -198,6 +198,7 @@ Working backlog for **Epic 3 — Slice 1** ([items and inventory MVP](../decompo - **[E3.M1](../decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md)** Slice 2 decomposed — [E3M1-prototype-backlog.md](E3M1-prototype-backlog.md) ([NEO-57](https://linear.app/neon-sprawl/issue/NEO-57)–[NEO-64](https://linear.app/neon-sprawl/issue/NEO-64)). - **[E3.M2](../decomposition/modules/E3_M2_RefinementAndRecipeExecution.md)** Slice 3 decomposed — [E3M2-prototype-backlog.md](E3M2-prototype-backlog.md) ([NEO-65](https://linear.app/neon-sprawl/issue/NEO-65)–[NEO-71](https://linear.app/neon-sprawl/issue/NEO-71)). +- **Epic 3 Slice 5 (client)** — [E3S5-client-prototype-backlog.md](E3S5-client-prototype-backlog.md) ([NEO-72](https://linear.app/neon-sprawl/issue/NEO-72)–[NEO-75](https://linear.app/neon-sprawl/issue/NEO-75)); inventory HUD is **E3S5-01** [NEO-72](https://linear.app/neon-sprawl/issue/NEO-72). - Track delivery in Linear; keep `blockedBy` links synchronized if scope changes. - For each issue kickoff, add `docs/plans/{NEO-XX}-implementation-plan.md` per [story-kickoff](../../.cursor/rules/story-kickoff.md). - Add `docs/manual-qa/{NEO-XX}.md` when HTTP surfaces land (E3M3-06+). diff --git a/docs/plans/E3S5-client-prototype-backlog.md b/docs/plans/E3S5-client-prototype-backlog.md new file mode 100644 index 0000000..2a536ba --- /dev/null +++ b/docs/plans/E3S5-client-prototype-backlog.md @@ -0,0 +1,171 @@ +# Epic 3 — Slice 5: Client economy integration (prototype) + +Working backlog for **Epic 3 — Slice 5** ([client economy integration](../decomposition/epics/epic_03_crafting_economy.md#epic-3-slice-5)). Completes the **full stack** for gather → inventory → craft in the **Godot client** — not Bruno-only proof. + +**Policy (from decomposition):** Epics deliver **playable game features**, not server-only vertical slices. Slices 1–3 landed server + content + Bruno; **Slice 5** is the required client half. Slice 4 (E3.M4/M5 sinks) remains pre-production. + +**Labels (Linear):** every issue carries module label(s) **`E3.M1`** / **`E3.M2`** / **`E3.M3`** as listed; add **`client`** + **`Story`**. + +**Pattern:** Mirror [E1.M3 client pairing](../plans/E1M3-prototype-backlog.md#e1m3-02--client-tab-target--lock-ui-synced-to-server) — thin HTTP client nodes, `main.gd` wiring, HUD labels, GdUnit doubles, `docs/manual-qa/{KEY}.md`. + +**Upstream (server must be landed):** + +| Module | Minimum server stories | +|--------|-------------------------| +| **E3.M3** | [NEO-55](https://linear.app/neon-sprawl/issue/NEO-55) inventory GET/POST; [NEO-53](https://linear.app/neon-sprawl/issue/NEO-53) item defs (display names) | +| **E3.M1** | [NEO-63](https://linear.app/neon-sprawl/issue/NEO-63) interact → gather; [NEO-60](https://linear.app/neon-sprawl/issue/NEO-60) resource-node defs (optional preview) | +| **E3.M2** | [NEO-68](https://linear.app/neon-sprawl/issue/NEO-68) recipe defs GET; [NEO-70](https://linear.app/neon-sprawl/issue/NEO-70) craft POST | +| **E2.M2** | [NEO-37](https://linear.app/neon-sprawl/issue/NEO-37) skill-progression GET (XP visibility) | + +**Linear issues (created):** attach `docs/plans/NEO-*-implementation-plan.md` on the same branch as implementation work. + +| Slug | Linear | +|------|--------| +| E3S5-01 | [NEO-72](https://linear.app/neon-sprawl/issue/NEO-72) | +| E3S5-02 | [NEO-73](https://linear.app/neon-sprawl/issue/NEO-73) | +| E3S5-03 | [NEO-74](https://linear.app/neon-sprawl/issue/NEO-74) | +| E3S5-04 | [NEO-75](https://linear.app/neon-sprawl/issue/NEO-75) | + +**Dependency graph in Linear:** E3S5-02 (NEO-73) blocked by E3S5-01 (NEO-72) and [NEO-63](https://linear.app/neon-sprawl/issue/NEO-63). E3S5-03 (NEO-74) blocked by E3S5-01 (NEO-72), [NEO-68](https://linear.app/neon-sprawl/issue/NEO-68), and [NEO-70](https://linear.app/neon-sprawl/issue/NEO-70). E3S5-04 (NEO-75) blocked by E3S5-02 (NEO-73) and E3S5-03 (NEO-74). + +**Board order:** estimates **1–4** matching slug order. On the Epic 3 project board, sort by **Estimate** (ascending). + +--- + +## Story order (recommended) + +| Order | Slug | Depends on | +|-------|------|------------| +| 1 | **E3S5-01** | [NEO-55](https://linear.app/neon-sprawl/issue/NEO-55), [NEO-53](https://linear.app/neon-sprawl/issue/NEO-53) | +| 2 | **E3S5-02** | E3S5-01, [NEO-63](https://linear.app/neon-sprawl/issue/NEO-63) | +| 3 | **E3S5-03** | E3S5-01, [NEO-68](https://linear.app/neon-sprawl/issue/NEO-68), [NEO-70](https://linear.app/neon-sprawl/issue/NEO-70) | +| 4 | **E3S5-04** | E3S5-02, E3S5-03 | + +--- + +## Kickoff decisions (decomposition defaults) + +| Topic | Decision | Rationale | +|-------|----------|-----------| +| HUD fidelity | **Prototype debug panels** (Labels / simple lists) — not final art | Matches NEO-24/NEO-28 cast/target HUD pattern; polish is pre-production | +| Inventory refresh | **GET after mutating actions** (interact gather, craft POST) | Server is source of truth; no client-side stack math | +| Craft UI scope | **List all prototype recipes** + single **Craft** button per row | No station placement, batch quantity slider, or drag-drop in Slice 5 | +| Skill XP display | **Salvage + refine levels/XP** on HUD; refresh after gather/craft | Epic 2 Slice 3 AC + vision **progression gate** | +| Gather wire | **Reuse `POST …/interact`** — no new gather HTTP on client | E3.M1 prototype contract; extend `interaction_request_client.gd` | +| Authority | Client **displays only**; all mutations via existing server routes | [client_server_authority.md](../decomposition/modules/client_server_authority.md) | + +--- + +### E3S5-01 — Client inventory snapshot HUD (E3.M3) + +**Goal:** Godot **`GET /game/players/{id}/inventory`** client + readable bag/equipment panel; boot hydrate + manual refresh entrypoint for later stories. + +**In scope** + +- `inventory_client.gd` (or equivalent): GET snapshot, parse v1 envelope, emit signal with slots/stacks. +- HUD: `InventoryLabel` or scroll-friendly list under `UICanvas` showing **bag** + **equipment** rows (item id, quantity, slot kind). +- Optional: resolve **`displayName`** via cached **`GET /game/world/item-definitions`** (NEO-53) for readable labels. +- GdUnit: HTTP double, parse happy path + error path. +- `client/README.md` section; input binding for **refresh** (e.g. **I**) if useful for QA. +- `docs/manual-qa/NEO-72.md`. + +**Out of scope** + +- Drag-drop, split stacks, equip UX polish. +- POST inventory mutations from UI (craft/gather stories own refresh triggers). + +**Acceptance criteria** + +- [ ] Boot (or first open) shows current server inventory for `dev_player_id`. +- [ ] HUD lists all non-empty bag slots and equipment stub slot from GET body. +- [ ] Failed GET surfaces visible error/warning (match interaction client pattern). + +--- + +### E3S5-02 — Client gather feedback on interact (E3.M1) + +**Goal:** After successful **resource_node** interact, player **sees** inventory change and **salvage** XP movement — not Output-panel-only proof. + +**In scope** + +- Extend gather interact path: on `allowed=true` for resource nodes, call **inventory refresh** + **skill-progression GET** (`salvage` row). +- Feedback line: e.g. `GatherFeedbackLabel` — “+N scrap_metal_bulk” (derive delta from before/after inventory or document server-truth refresh-only copy). +- Map **`node_depleted`** deny to readable HUD message (not silent). +- Wire all four prototype resource node ids (not only `prototype_resource_node_alpha`) if interact keys or targeting supports them; document bindings. +- GdUnit: mock interact 200 → refresh invoked. +- `docs/manual-qa/NEO-73.md`. + +**Out of scope** + +- New gather HTTP route; node respawn visuals; gather VFX. + +**Acceptance criteria** + +- [ ] In-range interact on fresh node updates inventory HUD without manual refresh. +- [ ] Depleted node shows **`node_depleted`** (or agreed copy) on HUD. +- [ ] **Salvage** skill level or XP visible and changes after successful gather (Epic 2 Slice 3 visibility). + +--- + +### E3S5-03 — Client craft UI + recipe list (E3.M2) + +**Goal:** Player selects a prototype recipe and **`POST /game/players/{id}/craft`** from Godot; sees success/deny and updated inventory + **refine** XP. + +**In scope** + +- `recipe_definitions_client.gd`: GET world recipe defs (NEO-68). +- `craft_client.gd`: POST `{ recipeId, quantity? }`; parse success/deny + `reasonCode`. +- HUD: simple recipe list (id / displayName, inputs summary); **Craft** per row for qty **1**. +- On success: refresh inventory + skill-progression (**refine**); show feedback line. +- Deny paths documented in manual QA: insufficient materials, bag full, unknown recipe. +- GdUnit: POST payload shape, deny parsing. +- `docs/manual-qa/NEO-74.md`. + +**Out of scope** + +- Station/bench world objects; craft quantity spinner; recipe filtering by skill level. + +**Acceptance criteria** + +- [ ] Player can **`refine_scrap_standard`** and **`make_field_stim_mk0`** from UI when materials allow. +- [ ] Denied craft shows **`reasonCode`** on HUD; inventory unchanged (verify via GET). +- [ ] **Refine** skill XP visible and increases on successful craft. + +--- + +### E3S5-04 — Playable gather→refine→make loop in client (capstone) + +**Goal:** Prove Epic 3 prototype acceptance **in Godot**: gather **`scrap_metal_bulk`** → **`refine_scrap_standard`** → **`make_field_stim_mk0`** without Bruno; satisfies vision **crafting loop** + **progression gate** smoke test. + +**In scope** + +- `main.gd` integration checklist: interact → inventory → craft panel flow documented in **`client/README.md`**. +- **`docs/manual-qa/NEO-75.md`**: numbered session script (move to node, gather ×N, refine, make stim, verify consumable in bag). +- Optional: toggle/collapse HUD sections so prototype scene stays usable (document layout). +- Cross-link Epic 3 Slice 5 complete in module docs + alignment register when done. + +**Out of scope** + +- Quest UI (E7); combat consumable use (E5 follow-up); art pass. + +**Acceptance criteria** + +- [ ] Manual QA checklist completable by a human in one session with server + client running. +- [ ] **`field_stim_mk0`** quantity ≥ 1 in inventory at end of script. +- [ ] Epic 3 Slice 3 acceptance re-read: **player** (not Bruno) completes gather → refine → usable item. + +--- + +## After this backlog + +- Epic 3 **prototype** is **full-stack complete** for gather/craft/inventory (Slices 1–3 server + Slice 5 client). +- Slice 4 (**E3.M4** + **E3.M5**) sinks/policy remains **pre-production**. +- Apply the same **server + client pairing** pattern when decomposing other epics (see [decomposition README](../decomposition/README.md#full-stack-epics)). +- Track delivery in Linear; keep `blockedBy` synchronized if scope changes. + +## Related docs + +- [epic_03_crafting_economy.md](../decomposition/epics/epic_03_crafting_economy.md) +- [E3M1-prototype-backlog.md](E3M1-prototype-backlog.md), [E3M2-prototype-backlog.md](E3M2-prototype-backlog.md), [E3M3-prototype-backlog.md](E3M3-prototype-backlog.md) +- [client_server_authority.md](../decomposition/modules/client_server_authority.md) +- [neon_sprawl_vision.plan.md — Prototype Scope](../../neon_sprawl_vision.plan.md)