# E3.M2 — RefinementAndRecipeExecution ## Summary | Field | Value | |--------|--------| | **Module ID** | E3.M2 | | **Epic** | [Epic 3 — Crafting Economy](../epics/epic_03_crafting_economy.md) | | **Stage target** | Prototype | | **Status** | In Progress — Slice 3 backlog [E3M2-prototype-backlog](../../plans/E3M2-prototype-backlog.md): E3M2-01 [NEO-65](https://linear.app/neon-sprawl/issue/NEO-65) landed; E3M2-02–E3M2-07 open (see [dependency register](module_dependency_register.md)) | ## Implementation snapshot **Prep (NEO-42):** Server ships **`RefineActivitySkillXpGrant.GrantOnSuccessfulCraftOrRefine`** + **`RefineSkillXpConstants`** under `server/NeonSprawl.Server/Game/Skills/` — delegates to **`SkillProgressionGrantOperations.TryApplyGrant`** with **`refine`** + **`activity`** (prototype **10** XP), same persistence and **`allowedXpSourceKinds`** rules as **`POST …/skill-progression`**. **No** `CraftRequest` / **`CraftResult`** route yet; when this module adds authoritative craft/refine success, call that helper once on success ([NEO-42 implementation plan](../../plans/NEO-42-implementation-plan.md); [server README — Craft / refine hook (NEO-42)](../../../server/README.md#craft--refine-hook--skill-xp-neo-42)). **E3M2-01 (NEO-65):** Frozen eight-recipe catalog in [`content/recipes/prototype_recipes.json`](../../../content/recipes/prototype_recipes.json); [`recipe-def.schema.json`](../../../content/schemas/recipe-def.schema.json) + [`recipe-io-row.schema.json`](../../../content/schemas/recipe-io-row.schema.json); PR gate + [`validate_content.py`](../../../scripts/validate_content.py) Slice 3 gates ([NEO-65 plan](../../plans/NEO-65-implementation-plan.md)). **No** server loader yet — E3M2-02 (NEO-66) owns fail-fast boot load. ## Purpose Implements the processing and crafting pipeline: raw-to-refined flows and recipe execution with server-authoritative inventory mutations. Bridges gathered materials ([E3.M1](E3_M1_ResourceNodeAndGatherLoop.md)) and item definitions ([E3.M3](E3_M3_ItemizationAndInventorySchema.md)) into usable outputs for combat, quests, and economy loops. ## Responsibilities - Validate `CraftRequest` against `RecipeDef`, costs, and player inventory state. - Produce `CraftResult` (success/failure, outputs, failures with reason codes). - Support prototype recipe set (e.g. 8–12 starter recipes per epic slice minimums). ## Key contracts | Contract | Role | |----------|------| | `RecipeDef` | Inputs, outputs, skill gates, station requirements (as scoped for prototype). | | `CraftRequest` | Actor, recipe, quantities, optional targeting for UI/server sync. | | `CraftResult` | Deterministic outcome for inventory and telemetry. | ## Module dependencies - **E3.M1** — [ResourceNodeAndGatherLoop](E3_M1_ResourceNodeAndGatherLoop.md): refined materials from gather outputs into crafting inputs. - **E3.M3** — [ItemizationAndInventorySchema](E3_M3_ItemizationAndInventorySchema.md): `ItemDef`, `ItemInstance`, inventory slots for costs and outputs. ## Dependents (by design) - **E7.M1** — [QuestStateMachine](E7_M1_QuestStateMachine.md): quest steps may require crafted items or craft completion. - **E6.M4** — [RewardParityEnforcer](E6_M4_RewardParityEnforcer.md): PvP ↔ PvE/crafting equivalents involving craft outputs. - **Epic 2 integration** — Callers award crafting XP via [E2.M2](E2_M2_XpAwardAndLevelEngine.md) at activity sites. ## Designer note: prototype recipe shape Each **`RecipeDef`** row under `content/recipes/*.json` declares: - **`recipeKind`** — **`process`** (refine / intermediate) or **`make`** (finished good). - **`requiredSkillId`** — prototype uses **`refine`** for all eight rows (no separate Make skill in the skill trio). - **`inputs`** / **`outputs`** — arrays of `{ itemId, quantity }` referencing only frozen [E3.M3](../decomposition/modules/E3_M3_ItemizationAndInventorySchema.md) item ids. - **`requiredSkillLevel`** — **omitted** in Slice 3 (no level gates until a deliberate content pass). **Prototype v1:** no station tags, craft failure RNG, or quality rolls — deterministic success when inputs and bag/equipment capacity allow. ## Prototype Slice 3 freeze (E3M2-01) The **first shipped eight-recipe spine** under `content/recipes/*.json` is **frozen** for downstream references (craft HTTP, Bruno spine, quest objectives) until a deliberate migration or follow-up issue expands the roster. | `RecipeDef.id` | `recipeKind` | Primary inputs → output | Demo role | |----------------|--------------|-------------------------|-----------| | **`refine_scrap_standard`** | `process` | 5× **`scrap_metal_bulk`** → 1× **`refined_plate_stock`** | Default refine after gather | | **`refine_scrap_efficient`** | `process` | 10× **`scrap_metal_bulk`** → 2× **`refined_plate_stock`** | Branching refine efficiency | | **`make_field_stim_mk0`** | `make` | 2× **`refined_plate_stock`** + 1× **`scrap_metal_bulk`** → 1× **`field_stim_mk0`** | Primary gather→refine→combat consumable | | **`make_field_stim_batch`** | `make` | 5× **`refined_plate_stock`** + 3× **`scrap_metal_bulk`** → 3× **`field_stim_mk0`** | Batch make variant | | **`make_prototype_armor`** | `make` | 8× **`refined_plate_stock`** + 5× **`scrap_metal_bulk`** → 1× **`prototype_armor_shell`** | Equip-stub output | | **`make_armor_quick`** | `make` | 4× **`refined_plate_stock`** + 3× **`scrap_metal_bulk`** → 1× **`prototype_armor_shell`** | Alternate armor path (branching) | | **`make_survey_drone_kit`** | `make` | 3× **`refined_plate_stock`** + 2× **`scrap_metal_bulk`** → 1× **`survey_drone_kit`** | Utility output | | **`make_contract_token`** | `make` | 2× **`refined_plate_stock`** + 1× **`scrap_metal_bulk`** → 1× **`contract_handoff_token`** | Quest token output | **Rules:** Do **not** rename these `id` values—change **`displayName`** only, or add a new `id` in a follow-up issue. CI ([`scripts/validate_content.py`](../../../scripts/validate_content.py)) enforces **exactly** these eight ids, at least one **`process`** and one **`make`** row, **`requiredSkillId: refine`** on every row, input/output **`itemId`** cross-check against the frozen item catalog, and duplicate-`id` rejection across all recipe JSON files. Implementation: [NEO-65 plan](../../plans/NEO-65-implementation-plan.md). ## Related implementation slices 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). **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 - Duplication or negative stacks: server-authoritative craft and inventory; integrity signals via E9.M4 when live. - Quest/economy parity: lint reward bundles against E6.M4 and E3.M5 policies in later phases. ## Source anchors - Master plan: [`neon_sprawl_vision.plan.md`](../../../neon_sprawl_vision.plan.md) — Core Epic Map, Epic 3. - [Module dependency register](module_dependency_register.md)