# OpenSpec Change: enterprise-gaming-crafting - **Change ID**: enterprise-gaming-crafting - **Package**: `@suaveplan/crafting` - **Category**: gaming/narrative - **Target path**: `gaming/narrative/crafting` - **Status**: PROPOSED - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/crafting.md` --- ## Summary Deliver `@suaveplan/crafting` on the genesis branch from scratch at enterprise quality. The package provides recipe-based crafting with stations, material requirements, quality tiers, and crafting queues. A `RecipeRegistry` holds typed `RecipeDefinition` objects; `CraftingStation` manages a per-station craft queue with concurrent slot limits and duration timers; `QualityCalculator` computes output quality from input material quality and skill level. Genesis adds Zod recipe schemas, structured errors, OTel craft counter, injectable clock, and 100% coverage. --- ## Current-state audit (genesis) Package does not exist on genesis yet — fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | `CraftingError`; `CRAFT.*` codes | | `@suaveplan/types` (`workspace:^`) | `Clock`, `IdGenerator` | | `@suaveplan/events` (`workspace:^`) | `craft:started`, `craft:complete`, `craft:failed` events | | `zod` (`catalog:forms`) | `RecipeDefinition` schema | | `@opentelemetry/api` (`catalog:observability`) | Craft completion counter | --- ## Public API surface ```ts type QualityTier = 'poor' | 'normal' | 'fine' | 'superior' | 'masterwork' interface Ingredient { itemId: string quantity: number qualityMin?: QualityTier } interface RecipeDefinition { id: string name: string stationType: string ingredients: Ingredient[] outputItemId: string outputQuantity: number craftTime: number // seconds skillRequired?: number // 0–100 outputQualityBase?: QualityTier } function createRecipeRegistry(): RecipeRegistry interface RecipeRegistry { register(recipe: RecipeDefinition): void get(id: string): RecipeDefinition | undefined listByStation(stationType: string): RecipeDefinition[] } function createCraftingStation(options: StationOptions): CraftingStation interface StationOptions { type: string maxSlots?: number // concurrent crafts, default 1 clock?: Clock registry: RecipeRegistry } interface CraftingStation { canCraft(recipeId: string, inventory: Map): boolean startCraft(recipeId: string, inventory: Map, skill?: number): CraftJob tick(dt: number): CompletedCraft[] getQueue(): CraftJob[] cancelJob(jobId: string): void } interface CraftJob { jobId: string recipeId: string startedAt: number duration: number skill: number } interface CompletedCraft { jobId: string recipeId: string outputItemId: string quantity: number quality: QualityTier } ``` ### Error codes ```ts type CraftErrorCode = | 'CRAFT_RECIPE_NOT_FOUND' | 'CRAFT_MISSING_INGREDIENTS' | 'CRAFT_STATION_FULL' | 'CRAFT_SKILL_TOO_LOW' | 'CRAFT_JOB_NOT_FOUND' ``` --- ## New additions for genesis 1. **Quality calculator** — output quality = base + skill bonus; `masterwork` requires skill ≥ 90. 2. **Concurrent slot queue** — `maxSlots` allows parallel crafting at upgraded stations. 3. **Ingredient quality minimum** — recipe can require `qualityMin`; fails if inventory item below tier. --- ## File layout ```text gaming/narrative/crafting/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts constants/index.ts types/common.ts types/common.md core/ recipe-registry/ recipe-registry.ts recipe-registry.md recipe-registry.test.ts index.ts crafting-station/ crafting-station.ts crafting-station.md crafting-station.types.ts crafting-station.test.ts index.ts utils/ quality-calculator.ts quality-calculator.md quality-calculator.test.ts tests/ integration.test.ts ``` --- ## Impact **Downstream**: `@suaveplan/react-crafting` displays station queue and recipe list. Prerequisites: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`.