diff --git a/content/README.md b/content/README.md index e171a27..d88f5d3 100644 --- a/content/README.md +++ b/content/README.md @@ -7,9 +7,12 @@ Data-driven definitions (skills, items, recipes, quests) validated in CI with ** | [`schemas/`](schemas/) | JSON Schema files (`*.schema.json`) | | [`skills/`](skills/) | Skill catalogs; each row matches [`schemas/skill-def.schema.json`](schemas/skill-def.schema.json) — **stable `id`**, **`allowedXpSourceKinds`** for [E2.M1](../docs/decomposition/modules/E2_M1_SkillDefinitionRegistry.md) / [E2.M2](../docs/decomposition/modules/E2_M2_XpAwardAndLevelEngine.md) | | [`mastery/`](mastery/) | Mastery catalogs; each file matches [`schemas/mastery-catalog.schema.json`](schemas/mastery-catalog.schema.json) — **stable `branchId` / `perkId`**, tier gates via skill level ([E2.M3](../docs/decomposition/modules/E2_M3_MasteryAndPerkUnlocks.md)) | +| [`items/`](items/) | Item catalogs (planned); each row matches `schemas/item-def.schema.json` — **stable `id`**, stack/slot metadata for [E3.M3](../docs/decomposition/modules/E3_M3_ItemizationAndInventorySchema.md) | **Prototype Slice 1 (NEO-33):** CI expects **exactly three** skill rows with ids **`salvage`**, **`refine`**, **`intrusion`** (gather + process + tech). Each row must declare **`allowedXpSourceKinds`** (non-empty); see [E2.M1 — Designer note: `allowedXpSourceKinds`](../docs/decomposition/modules/E2_M1_SkillDefinitionRegistry.md#designer-note-allowedxpsourcekinds-and-grant-call-sites) for what each kind means for grant wiring. +**Prototype Slice 1 — items (NEO-50, planned):** CI will expect **exactly six** item rows with ids **`scrap_metal_bulk`**, **`refined_plate_stock`**, **`field_stim_mk0`**, **`survey_drone_kit`**, **`contract_handoff_token`**, **`prototype_armor_shell`** — see [E3M3-prototype-backlog](../docs/plans/E3M3-prototype-backlog.md) and [E3.M3 freeze note](../docs/decomposition/modules/E3_M3_ItemizationAndInventorySchema.md#related-implementation-slices). + **Prototype Slice 4 (NEO-45):** CI expects **exactly one** `MasteryTrack` for **`salvage`** only (`refine` / `intrusion` have no mastery rows yet). Tier 1 @ skill level **2** is a **mutually exclusive** branch pick (`scrap_efficiency` vs `bulk_haul`) with **no** perks; tier 2 @ level **4** unlocks one perk per branch path. **Do not rename** `branchId` / `perkId` after ship—change `displayName` only. See [E2.M3 — Designer note](../docs/decomposition/modules/E2_M3_MasteryAndPerkUnlocks.md#designer-note-tiers-branches-and-level-gates) and [freeze table](../docs/decomposition/modules/E2_M3_MasteryAndPerkUnlocks.md#prototype-slice-4-freeze--salvage-flagship-neo-45). Server load path and hot-reload policy are TBD; keep files versioned here as the source of truth. diff --git a/docs/decomposition/modules/E3_M3_ItemizationAndInventorySchema.md b/docs/decomposition/modules/E3_M3_ItemizationAndInventorySchema.md index 198dcec..bc7442e 100644 --- a/docs/decomposition/modules/E3_M3_ItemizationAndInventorySchema.md +++ b/docs/decomposition/modules/E3_M3_ItemizationAndInventorySchema.md @@ -7,7 +7,7 @@ | **Module ID** | E3.M3 | | **Epic** | [Epic 3 — Crafting Economy](../epics/epic_03_crafting_economy.md) | | **Stage target** | Prototype | -| **Status** | Planned (see [dependency register](module_dependency_register.md)) | +| **Status** | Planned — Slice 1 backlog [NEO-50](https://linear.app/neon-sprawl/issue/NEO-50)–[NEO-56](https://linear.app/neon-sprawl/issue/NEO-56) ([E3M3-prototype-backlog](../../plans/E3M3-prototype-backlog.md); see [dependency register](module_dependency_register.md)) | ## Purpose @@ -37,6 +37,8 @@ Item definitions, rarity/quality, stackability, and equipment metadata plus `Inv Epic 3 **Slice 1** — MVP inventory; `item_created`, transfer failures. +**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). Prototype **frozen item ids:** `scrap_metal_bulk`, `refined_plate_stock`, `field_stim_mk0`, `survey_drone_kit`, `contract_handoff_token`, `prototype_armor_shell`. + ## Source anchors - Master plan: [`neon_sprawl_vision.plan.md`](../../../neon_sprawl_vision.plan.md) — Epic 3. diff --git a/docs/decomposition/modules/module_dependency_register.md b/docs/decomposition/modules/module_dependency_register.md index 6f26ff0..215310d 100644 --- a/docs/decomposition/modules/module_dependency_register.md +++ b/docs/decomposition/modules/module_dependency_register.md @@ -48,6 +48,8 @@ Fleshed-out scope, contracts, and integration notes live in **per-module documen | E3.M4 | SinkAndDurabilityLifecycle | E3.M3, E8.M3 | DurabilityState, ItemSinkEvent, RepairCostRule | Pre-production | Planned | | E3.M5 | EconomyBalancePolicy | E3.M4, E9.M2 | EconomyPolicy, PriceBandRule, FaucetSinkRatio | Pre-production | Planned | +**E3.M3 note:** Epic 3 **Slice 1** 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-50](https://linear.app/neon-sprawl/issue/NEO-50) → [NEO-56](https://linear.app/neon-sprawl/issue/NEO-56); label **`E3.M3`**. See [E3M3-prototype-backlog.md](../../plans/E3M3-prototype-backlog.md), [E3_M3_ItemizationAndInventorySchema.md](E3_M3_ItemizationAndInventorySchema.md). **NEO-50+** moves the register row to **In Progress** when slices land. + ### Epic 4 — World Topology | Module ID | Module Name | Depends On | Contract Needed | Phase Required | Status | diff --git a/docs/plans/E3M3-prototype-backlog.md b/docs/plans/E3M3-prototype-backlog.md new file mode 100644 index 0000000..8eb0b90 --- /dev/null +++ b/docs/plans/E3M3-prototype-backlog.md @@ -0,0 +1,207 @@ +# E3.M3 — Prototype story backlog (ItemizationAndInventorySchema) + +Working backlog for **Epic 3 — Slice 1** ([items and inventory MVP](../decomposition/epics/epic_03_crafting_economy.md#slice-1---items-and-inventory-mvp)). Decomposition and contracts: [E3.M3 — ItemizationAndInventorySchema](../decomposition/modules/E3_M3_ItemizationAndInventorySchema.md). + +**Labels (Linear):** every issue **`E3.M3`**; add **`server`** / **`Feature`** or **`Story`** as listed per issue. + +**Precursor (do not re-scope):** gather **skill XP** on `resource_node` interact is **E3.M1** anchor only ([NEO-41](https://linear.app/neon-sprawl/issue/NEO-41)) — no `GatherResult` / inventory yet. This module owns **`ItemDef`**, **`ItemInstance`**, **`InventorySlot`**, and server-authoritative player inventory. + +**Prototype item spine (frozen in E3M3-01):** six rows covering **material → intermediate → consumable → utility → quest token → equip stub** for the gather→refine→craft loop ([items.md](../game-design/items.md), [gathering.md](../game-design/gathering.md), [crafting.md](../game-design/crafting.md)). + +**Linear issues (created):** attach `docs/plans/NEO-*-implementation-plan.md` on the same branch as implementation work. + +| Slug | Linear | +|------|--------| +| E3M3-01 | [NEO-50](https://linear.app/neon-sprawl/issue/NEO-50) | +| E3M3-02 | [NEO-51](https://linear.app/neon-sprawl/issue/NEO-51) | +| E3M3-03 | [NEO-52](https://linear.app/neon-sprawl/issue/NEO-52) | +| E3M3-04 | [NEO-53](https://linear.app/neon-sprawl/issue/NEO-53) | +| E3M3-05 | [NEO-54](https://linear.app/neon-sprawl/issue/NEO-54) | +| E3M3-06 | [NEO-55](https://linear.app/neon-sprawl/issue/NEO-55) | +| E3M3-07 | [NEO-56](https://linear.app/neon-sprawl/issue/NEO-56) | + +**Dependency graph in Linear:** E3M3-02 blocked by E3M3-01. E3M3-03 blocked by E3M3-02. E3M3-04 and E3M3-05 blocked by E3M3-03. E3M3-06 blocked by E3M3-05. E3M3-07 blocked by E3M3-05 (may parallel E3M3-06). + +--- + +## Story order (recommended) + +| Order | Slug | Depends on | +|-------|------|------------| +| 1 | **E3M3-01** | None (content spine) | +| 2 | **E3M3-02** | E3M3-01 | +| 3 | **E3M3-03** | E3M3-02 | +| 4 | **E3M3-04** | E3M3-03 | +| 5 | **E3M3-05** | E3M3-03 | +| 6 | **E3M3-06** | E3M3-05 | +| 7 | **E3M3-07** | E3M3-05 | + +**Downstream (separate modules):** [E3.M1](../decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md) Slice 2 gather yields → inventory grants; [E3.M2](../decomposition/modules/E3_M2_RefinementAndRecipeExecution.md) craft I/O; [NEO-42](https://linear.app/neon-sprawl/issue/NEO-42) refine XP hook invokes after craft success. + +--- + +### E3M3-01 — Prototype ItemDef starter set + schemas + CI + +**Goal:** Lock content shape and CI validation for a **frozen six-item** prototype catalog before any server load. + +**In scope** + +- `content/schemas/item-def.schema.json` (or equivalent single-catalog schema). +- `content/items/prototype_items.json` with stable ids: `scrap_metal_bulk`, `refined_plate_stock`, `field_stim_mk0`, `survey_drone_kit`, `contract_handoff_token`, `prototype_armor_shell` (names/display may change; **ids frozen**). +- `scripts/validate_content.py`: schema validation, duplicate `id`, required bucket/tag fields, exact six-id allowlist for prototype. +- Designer note in [E3_M3](../decomposition/modules/E3_M3_ItemizationAndInventorySchema.md) + `content/README.md`: stack rules, slot kinds (bag vs equip stub), v1 scope (no durability mutation). + +**Out of scope** + +- Server loader, inventory store, HTTP, client HUD. + +**Acceptance criteria** + +- [ ] PR gate validates item JSON against schema. +- [ ] Exactly six prototype item ids; duplicate `id` fails CI. +- [ ] Stable id list documented in module doc freeze box. + +--- + +### E3M3-02 — Server item catalog load (fail-fast) + +**Goal:** Disk → host: startup load of `content/items/*.json` with CI-parity validation. + +**In scope** + +- Loader + registry interface under `server/NeonSprawl.Server/Game/Items/` (path TBD in plan). +- Fail-fast on malformed files, duplicate ids, unknown enum values. +- Unit tests (AAA) for loader happy path and failure modes. + +**Out of scope** + +- Per-player inventory, HTTP. + +**Acceptance criteria** + +- [ ] Server refuses boot when item catalog invalid (mirror E2.M1 catalog behavior). +- [ ] Registry resolves `ItemDef` by `id`. + +--- + +### E3M3-03 — Item definition registry + DI + +**Goal:** Injectable `IItemDefinitionRegistry` consumed by inventory and future craft/gather paths. + +**In scope** + +- `ItemDefinitionRegistry` implementation + DI registration. +- Unit tests (AAA): lookup, unknown id, prototype row metadata. + +**Out of scope** + +- HTTP, persistence, stack mutation. + +**Acceptance criteria** + +- [ ] Host resolves registry from DI; unknown `itemId` distinguishable from valid ids in tests. + +--- + +### E3M3-04 — GET world item-definitions + +**Goal:** Versioned read-only catalog for client preview, Bruno, and future codegen — mirror [NEO-36](https://linear.app/neon-sprawl/issue/NEO-36) skill-definitions pattern. + +**In scope** + +- `GET /game/world/item-definitions` + DTOs + API tests (AAA). +- Bruno folder `bruno/neon-sprawl-server/item-definitions/`. +- `server/README.md` section. + +**Out of scope** + +- Per-player inventory mutation. + +**Acceptance criteria** + +- [ ] GET returns all six prototype defs with schema version field. +- [ ] Bruno happy path documented. + +--- + +### E3M3-05 — Player inventory store + stack/slot rules engine + +**Goal:** Server-authoritative `ItemInstance` bags with stack limits and structured deny reasons; persistence (in-memory + Postgres + migration). + +**In scope** + +- `IPlayerInventoryStore`, migration `V00X__player_inventory` (number in plan). +- Inventory operations: add stack, remove stack, slot capacity, `inventory_full` / `invalid_item` / `insufficient_quantity` reason codes. +- Unit + integration tests (AAA); mirror NEO-8/NEO-38 persistence policy. + +**Out of scope** + +- HTTP, Bruno, client HUD. +- Craft/gather automatic grants (callers in E3.M1 / E3.M2). + +**Acceptance criteria** + +- [ ] Add/remove respects `ItemDef` stack max from catalog. +- [ ] Full bag returns stable `reasonCode` without partial silent loss. +- [ ] Postgres + in-memory parity tests. + +--- + +### E3M3-06 — Player inventory HTTP + Bruno + +**Goal:** Versioned **GET** snapshot and **POST** grant/consume (or add/remove) for manual QA and future client. + +**In scope** + +- `GET /game/players/{id}/inventory` and mutating POST (exact path/shape in implementation plan). +- Known-player gate via `IPositionStateStore` (NEO-37 pattern). +- Bruno `bruno/neon-sprawl-server/inventory/`. +- `server/README.md`; API tests (AAA). + +**Out of scope** + +- Godot HUD (optional follow-up). +- Gather node depletion ([E3.M1](../decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md)). + +**Acceptance criteria** + +- [ ] GET returns instances + slots for seeded player. +- [ ] POST add/remove matches engine rules from E3M3-05. +- [ ] Bruno exercises happy path + at least one deny (`inventory_full` or unknown item). + +--- + +### E3M3-07 — `item_created` / transfer-failure telemetry hook sites + +**Goal:** Comment-only hooks on inventory mutation success/deny for future E9.M1 catalog events **`item_created`** and transfer failures. + +**In scope** + +- Hook placement in inventory engine (and POST path if applicable). +- `TODO(E9.M1)` comments; no production logging. +- README + module doc pointer. + +**Out of scope** + +- Telemetry ingest, dashboards. + +**Acceptance criteria** + +- [ ] Hook sites documented in code and `server/README.md`. +- [ ] Matches Epic 3 Slice 1 telemetry vocabulary in [epic_03](../decomposition/epics/epic_03_crafting_economy.md). + +--- + +## After this backlog + +- Decompose **[E3.M1](../decomposition/modules/E3_M1_ResourceNodeAndGatherLoop.md)** Slice 2 (gather yields → inventory) once E3M3-05+ land. +- 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+). + +## Related docs + +- [E3_M3_ItemizationAndInventorySchema.md](../decomposition/modules/E3_M3_ItemizationAndInventorySchema.md) +- [epic_03_crafting_economy.md](../decomposition/epics/epic_03_crafting_economy.md) +- [items.md](../game-design/items.md) +- [E2_M1_SkillDefinitionRegistry.md](../decomposition/modules/E2_M1_SkillDefinitionRegistry.md) (catalog pattern precedent)