8.8 KiB
NEO-68 — Implementation plan
Story reference
| Field | Value |
|---|---|
| Key | NEO-68 |
| Title | E3.M2: GET world recipe-definitions + Bruno |
| Linear | https://linear.app/neon-sprawl/issue/NEO-68/e3m2-get-world-recipe-definitions-bruno |
| Module | E3.M2 — RefinementAndRecipeExecution · Epic 3 Slice 3 · backlog E3M2-04 |
| Branch | NEO-68-get-world-recipe-definitions-bruno |
| Precursor | NEO-67 — IRecipeDefinitionRegistry + DI (Done on main) |
| Pattern | NEO-53 — GET /game/world/item-definitions |
| Client counterpart | NEO-74 — E3S5-03 craft UI + recipe list (blocked by this issue; server-only in this story) |
| Blocks | NEO-74, NEO-73 (Linear relations) |
Kickoff clarifications
| Topic | Question | Agent recommendation | Answer |
|---|---|---|---|
| JSON row fields | Expose required six + I/O only vs optional nullables? | Required six + inputs/outputs only — prototype rows omit requiredSkillLevel / stationTag; mirror NEO-53 “loaded fields only”. |
User: required six + I/O only. |
| Response envelope | Array property name? | recipes (with schemaVersion 1) — parallel to NEO-36 skills / NEO-53 items; matches content vocabulary. |
Adopted — no objection; follows precedent. |
| Route path | /game/world/… vs /game/content/…? |
GET /game/world/recipe-definitions — E3M2 backlog + parallel to item/skill defs. |
Adopted — backlog. |
| Manual QA doc | Add docs/manual-qa/NEO-68.md? |
Yes — player-visible HTTP; NEO-53 pattern. | User: yes. |
Goal, scope, and out-of-scope
Goal: Expose a stable, read-only JSON endpoint that returns all eight loaded prototype recipe definitions for Bruno, manual QA, client preview (NEO-74), and tooling — backed by IRecipeDefinitionRegistry without duplicating catalog truth.
In scope (from Linear + E3M2-04):
GET /game/world/recipe-definitionswith versioned envelope (schemaVersion1,recipesarray).- Row fields:
id,displayName,recipeKind,requiredSkillId,inputs,outputs(I/O rows:itemId,quantity; camelCase JSON). - Recipes ordered by
idordinal, matchingGetDefinitionsInIdOrder(). - Bruno folder
bruno/neon-sprawl-server/recipe-definitions/. docs/manual-qa/NEO-68.md.server/README.mdsection.- API integration tests (AAA).
Out of scope (from Linear + backlog):
- Per-player craft history or cooldown state.
- Optional schema fields (
requiredSkillLevel,stationTag) until content ships them. - Craft execution (NEO-69).
- Godot client (NEO-74).
Acceptance criteria checklist
- GET returns all eight prototype recipes with
schemaVersion1 and input/output summary fields needed for QA. - Bruno happy path documented and runnable against dev server.
- Automated API tests (AAA) assert eight ids, id order, and spot-check metadata + I/O rows.
Technical approach
-
Route:
GET /game/world/recipe-definitions— parameterless read; injectIRecipeDefinitionRegistryonly (notRecipeDefinitionCatalog). -
Response shape: Top-level
schemaVersion(RecipeDefinitionsListResponse.CurrentSchemaVersion= 1) plusrecipesarray. Each row maps fromRecipeDefRow:id,displayName,recipeKind,requiredSkillId,inputs,outputs. Do not emit optional null fields on this contract. -
I/O projection: Map
RecipeIoRow→ JSON withitemId,quantity(same keys as content schema). -
Ordering: Build list from
registry.GetDefinitionsInIdOrder()(already ordinal by id). Tests assert exact id sequence (frozen eight from E3.M2 snapshot):make_armor_quick,make_contract_token,make_field_stim_batch,make_field_stim_mk0,make_prototype_armor,make_survey_drone_kit,refine_scrap_efficient,refine_scrap_standard. -
Implementation: New
RecipeDefinitionsWorldApi+RecipeDefinitionsListDtos.csinGame/Crafting/(mirrorItemDefinitionsWorldApi). Wireapp.MapRecipeDefinitionsWorldApi()fromProgram.csnext toMapItemDefinitionsWorldApi(). -
Bruno:
bruno/neon-sprawl-server/recipe-definitions/withGet recipe definitions.bru+folder.bru. Tests: 200, JSON,schemaVersion1,recipes.length === 8, ascending id order, exact frozen-eight registry sequence (mirror NEO-53 item-definitions Bruno), spot-checkrefine_scrap_standard(recipeKindprocess, inputs/outputs) andmake_field_stim_mk0(recipeKindmake, multi-input). -
Docs:
docs/manual-qa/NEO-68.md(mirror NEO-53). Updateserver/README.mdrecipe section with GET + curl. Update E3_M2 Related implementation slices and documentation_and_implementation_alignment.md E3.M2 row when landed.
Files to add
| Path | Purpose |
|---|---|
server/NeonSprawl.Server/Game/Crafting/RecipeDefinitionsWorldApi.cs |
Map* extension registering GET route; maps registry → JSON. |
server/NeonSprawl.Server/Game/Crafting/RecipeDefinitionsListDtos.cs |
Versioned response + row + I/O DTOs for JSON serialization. |
server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionsWorldApiTests.cs |
HTTP integration: 200, schema v1, eight ids in order, spot-check rows + I/O. |
bruno/neon-sprawl-server/recipe-definitions/Get recipe definitions.bru |
Manual / Bruno verification against dev server. |
bruno/neon-sprawl-server/recipe-definitions/folder.bru |
Bruno folder metadata (match item-definitions). |
docs/manual-qa/NEO-68.md |
Checklist: start server, curl GET, confirm eight ids + spot-check I/O. |
docs/plans/NEO-68-implementation-plan.md |
This plan. |
Files to modify
| Path | Rationale |
|---|---|
server/NeonSprawl.Server/Program.cs |
Register MapRecipeDefinitionsWorldApi() alongside other game world definition APIs. |
server/README.md |
Document GET /game/world/recipe-definitions, curl example, links to plan/manual QA/Bruno. |
docs/decomposition/modules/E3_M2_RefinementAndRecipeExecution.md |
Related implementation slices — HTTP read model bullet (NEO-68). |
docs/decomposition/modules/documentation_and_implementation_alignment.md |
E3.M2 row — note NEO-68 HTTP projection when landed. |
Tests
| Test file | What it covers |
|---|---|
server/NeonSprawl.Server.Tests/Game/Crafting/RecipeDefinitionsWorldApiTests.cs |
Integration: GET /game/world/recipe-definitions via InMemoryWebApplicationFactory; ReadFromJsonAsync; assert schemaVersion 1; recipes count 8; ordered id list equals FrozenEightInIdOrder (shared constant referenced by manual QA / Bruno); spot-check refine_scrap_standard and make_field_stim_mk0. AAA per csharp-style. |
Bruno scripts complement automated tests for manual dev-server verification.
Open questions / risks
| Question / risk | Agent recommendation | Status |
|---|---|---|
| Linear blockedBy NEO-67 | Branch from main where NEO-67 is merged (confirmed at kickoff). |
adopted |
| Optional fields later | When content adds requiredSkillLevel / stationTag, bump schemaVersion or extend v1 with documented null semantics in a follow-up issue. |
deferred |
| Client not in this story | Cross-link NEO-74 in plan; Bruno + manual QA are not prototype-complete per full-stack epic decomposition. | adopted |
Decisions (kickoff)
- Required six + I/O only — no optional null fields on v1 contract (user confirmed).
recipesarray key — consistent with entity naming in sibling world-definition endpoints.docs/manual-qa/NEO-68.mdincluded (user confirmed).- Registry-only injection — HTTP layer depends on
IRecipeDefinitionRegistry, notRecipeDefinitionCatalog.