# 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**

- [x] Boot (or first open) shows current server inventory for `dev_player_id`.
- [x] HUD lists all non-empty bag slots and equipment stub slot from GET body.
- [x] 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**

- [x] In-range interact on fresh node updates inventory HUD without manual refresh.
- [x] Depleted node shows **`node_depleted`** (or agreed copy) on HUD.
- [x] **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**

- [x] Player can **`refine_scrap_standard`** and **`make_field_stim_mk0`** from UI when materials allow.
- [x] Denied craft shows **`reasonCode`** on HUD; inventory unchanged (verify via GET).
- [x] **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**

- [x] Manual QA checklist completable by a human in one session with server + client running.
- [x] **`field_stim_mk0`** quantity ≥ 1 in inventory at end of script.
- [x] Epic 3 Slice 3 acceptance re-read: **player** (not Bruno) completes gather → refine → usable item.
- [x] Economy HUD collapse toggle functional ([`NEO-75` manual QA](../manual-qa/NEO-75.md) step 8).

---

## 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)
