chore: Epic 3 Slice 5 client backlog and full-stack epic policy
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.pull/99/head
parent
458e9b10e8
commit
2cd17e293a
|
|
@ -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.
|
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.
|
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
|
## 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.
|
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.
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
## Ownership and success (Level 1)
|
## Ownership and success (Level 1)
|
||||||
|
|
||||||
- **Ownership focus:** Economy Design + Content Engineering
|
- **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.
|
- **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
|
## 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.
|
- 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.
|
- Telemetry hooks: `item_crafted`, `craft_failed` with reason, time-to-first-craft.
|
||||||
|
|
||||||
|
<a id="epic-3-slice-5"></a>
|
||||||
|
|
||||||
|
### 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).
|
||||||
|
|
||||||
<a id="epic-3-slice-4"></a>
|
<a id="epic-3-slice-4"></a>
|
||||||
|
|
||||||
### Slice 4 - Sinks and economy policy (pre-production)
|
### 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
|
## Definition of Done
|
||||||
|
|
||||||
- Prototype gather-craft loop meets plan pass/fail gates.
|
- Prototype gather-craft loop meets plan pass/fail gates **in the Godot client** (Slice 5), not Bruno-only.
|
||||||
- Pre-production adds sinks and policy with dashboard visibility.
|
- 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).
|
||||||
|
|
|
||||||
|
|
@ -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).
|
**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
|
## Source anchors
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
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
|
## Risks and telemetry
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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).
|
**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
|
## Source anchors
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.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.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 |
|
| 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.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. | [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.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. | [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.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) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.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
|
### Epic 4 — World Topology
|
||||||
|
|
||||||
| Module ID | Module Name | Depends On | Contract Needed | Phase Required | Status |
|
| Module ID | Module Name | Depends On | Contract Needed | Phase Required | Status |
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ Working backlog for **Epic 3 — Slice 2** ([gather nodes and outputs](../decomp
|
||||||
|
|
||||||
**Out of scope**
|
**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.
|
- New gather-specific HTTP route.
|
||||||
|
|
||||||
**Acceptance criteria**
|
**Acceptance criteria**
|
||||||
|
|
@ -255,6 +255,7 @@ Working backlog for **Epic 3 — Slice 2** ([gather nodes and outputs](../decomp
|
||||||
## After this backlog
|
## 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)).
|
- **[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.
|
- 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).
|
- 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+).
|
- Add `docs/manual-qa/{NEO-XX}.md` when interact + inventory surfaces are testable (E3M1-07+).
|
||||||
|
|
|
||||||
|
|
@ -188,7 +188,7 @@ Working backlog for **Epic 3 — Slice 3** ([recipes and crafting pipeline](../d
|
||||||
|
|
||||||
**Out of scope**
|
**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.
|
- Station interact / world bench placement.
|
||||||
|
|
||||||
**Acceptance criteria**
|
**Acceptance criteria**
|
||||||
|
|
@ -224,7 +224,8 @@ Working backlog for **Epic 3 — Slice 3** ([recipes and crafting pipeline](../d
|
||||||
|
|
||||||
## After this backlog
|
## 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.
|
- 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).
|
- 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+).
|
- Add `docs/manual-qa/{NEO-XX}.md` when craft HTTP lands (E3M2-06+).
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ Working backlog for **Epic 3 — Slice 1** ([items and inventory MVP](../decompo
|
||||||
|
|
||||||
**Out of scope**
|
**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)).
|
- Gather node depletion ([E3.M1](../decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md)).
|
||||||
|
|
||||||
**Acceptance criteria**
|
**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.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)).
|
- **[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.
|
- 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).
|
- 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+).
|
- Add `docs/manual-qa/{NEO-XX}.md` when HTTP surfaces land (E3M3-06+).
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
Loading…
Reference in New Issue