# NEO-123 — Implementation plan ## Story reference | Field | Value | |--------|--------| | **Key** | NEO-123 | | **Title** | E7M1-12: Playable onboarding quest chain capstone (Godot) | | **Linear** | https://linear.app/neon-sprawl/issue/NEO-123/e7m1-12-playable-onboarding-quest-chain-capstone-godot | | **Module** | [E7.M1 — QuestStateMachine](../decomposition/modules/E7_M1_QuestStateMachine.md) · Epic 7 Slice 1 · backlog **E7M1-12** | | **Branch** | `NEO-123-playable-onboarding-quest-chain-capstone` | | **Client deps** | [NEO-122](https://linear.app/neon-sprawl/issue/NEO-122) quest progress + accept HUD (**Done**); [NEO-111](https://linear.app/neon-sprawl/issue/NEO-111) encounter clear capstone; [NEO-75](https://linear.app/neon-sprawl/issue/NEO-75) economy loop; [NEO-110](https://linear.app/neon-sprawl/issue/NEO-110) encounter HUD | | **Server deps** | [NEO-112](https://linear.app/neon-sprawl/issue/NEO-112)–[NEO-121](https://linear.app/neon-sprawl/issue/NEO-121) quest spine (**landed on `main`**) | | **Pattern** | Capstone integration — [NEO-111](NEO-111-implementation-plan.md) docs + manual QA primary; minimal gap-fill only if capstone QA fails on `main` | | **Blocked by** | [NEO-122](https://linear.app/neon-sprawl/issue/NEO-122) (**Done**) | | **Server counterpart** | NEO-112–NEO-121 server spine; Bruno-only verification is not prototype-complete per [full-stack epic decomposition](../../.cursor/rules/full-stack-epic-decomposition.md) | ## Kickoff clarifications | Topic | Question | Agent recommendation | Answer | |--------|----------|----------------------|--------| | **Implementation scope** | Docs-only vs client code? | **Docs + manual QA primary**; fix integration gaps only if capstone QA fails on `main` — [NEO-111](NEO-111-implementation-plan.md) precedent. | **Adopted** — docs-primary | | **Capstone intro accept order** | Scripted order for three onboarding intros? | **Shift+Q catalog order:** **Q** gather → **Shift+Q** combat → **Shift+Q** refine → **Shift+Q** operator chain — `prototype_quest_combat_intro` sorts before `prototype_quest_refine_intro` in defs order; matches `quest_hud_controller.gd` `_find_first_eligible_quest_id()`. | **Adopted** — Shift+Q catalog order | | **Idempotency verification** | How to prove no duplicate quest completion on replay? | **Godot stop + F5 restart** (server still running) + retry **Q** / **Shift+Q** on completed quests; HUD statuses unchanged — mirrors [NEO-111](../manual-qa/NEO-111.md). | **Adopted** — Godot restart + duplicate accepts | | **NEO-122 relationship** | Supersede component QA? | **NEO-123 supersedes as Slice 1 capstone**; keep [NEO-122](../manual-qa/NEO-122.md) as component-level regression (NEO-111 / NEO-110 pattern). | **Adopted** (default; no kickoff question) | **Additional defaults (no kickoff question — settled by backlog / precedent):** - **Session baseline:** fresh **server restart** before Godot **F5** — resets in-memory quest progress, inventory, encounter state, and resource-node depletion; zero Bruno/curl in main checklist. - **Economy HUD:** toggle **on** for craft/inventory verification (NEO-75 / NEO-122 precedent). - **Server changes:** none unless capstone QA exposes an authoritative bug (unlikely — covered by server quest tests). ## Goal, scope, and out-of-scope **Goal:** Prove Epic 7 Slice 1 acceptance **in Godot**: complete all four prototype quests (three onboarding intros + one four-step operator chain) without Bruno; satisfies vision **quest loop** gate and [epic_07 Definition of Done](../decomposition/epics/epic_07_quest_faction.md#epic-7-definition-of-done). **In scope (from Linear + [E7M1-12](E7M1-prototype-backlog.md#e7m1-12--playable-onboarding-quest-chain-capstone-godot)):** - **`docs/manual-qa/NEO-123.md`**: numbered **single-session** capstone — fresh server restart; accept intros in **Shift+Q catalog order**; perform gather/craft/combat actions; verify **`prototype_quest_operator_chain`** completes when **`contract_handoff_token`** held; **idempotency** via Godot restart + duplicate accept keys. - **`client/README.md`**: **End-to-end onboarding quest loop** section — integration flow table; cross-links NEO-112–NEO-122 and economy/combat capstones. - **Module alignment** (on story completion): update [E7_M1](../decomposition/modules/E7_M1_QuestStateMachine.md) status, [documentation_and_implementation_alignment.md](../decomposition/modules/documentation_and_implementation_alignment.md) E7.M1 row, [module_dependency_register.md](../decomposition/modules/module_dependency_register.md) E7.M1 note, and [E7M1-prototype-backlog.md](E7M1-prototype-backlog.md) E7M1-12 checkboxes; mark Epic 7 Slice 1 client capstone complete. - **Integration fixes only if capstone QA fails** on current `main` wiring (HUD refresh gap, eligible-accept edge case, chain step stall, idempotency breach, etc.). **Out of scope (from Linear + backlog):** - E7.M2 reward bundles; faction reputation; quest VFX art. - Bruno-only verification as prototype-complete proof. - New server HTTP routes or Godot HUD features beyond NEO-122. - Eligible-quest picker redesign (catalog order is the documented contract for Slice 1). ## Acceptance criteria checklist - [ ] Human completes **`docs/manual-qa/NEO-123.md`** with server + client. - [ ] Epic 7 Slice 1 AC: 3 onboarding + 1 chain complete without duplicate completion on replay (idempotency steps pass). - [ ] Re-read [epic_07 Definition of Done](../decomposition/epics/epic_07_quest_faction.md#epic-7-definition-of-done) for prototype minimums. ## Technical approach ### 1. Capstone manual QA script (`docs/manual-qa/NEO-123.md`) **Preconditions:** Stop any running server; start fresh (`cd server/NeonSprawl.Server && dotnet run`) so in-memory **`dev-local-1`** quest progress, inventory, encounter progress, NPC HP, and resource-node depletion reset. Godot **F5** with **no** prior curl/Bruno seeding. **`Economy HUD`** toggle **on**. **Quest catalog (frozen — `content/quests/prototype_quests.json`):** | Quest id | Display name | Prerequisites | Steps | |----------|--------------|---------------|-------| | `prototype_quest_gather_intro` | Intro: Salvage Run | none | gather **3** `scrap_metal_bulk` | | `prototype_quest_combat_intro` | Intro: Clear the Pocket | none | `encounter_complete` **`prototype_combat_pocket`** | | `prototype_quest_refine_intro` | Intro: Refine Stock | gather intro | craft **`refine_scrap_standard`** ×1 | | `prototype_quest_operator_chain` | Operator Chain | all three intros | gather ×5 → refine ×1 → **`make_field_stim_mk0`** ×1 → **`inventory_has_item`** **`contract_handoff_token`** ×1 | **Accept key contract (NEO-122 / `quest_hud_controller.gd`):** | Key | Action | |-----|--------| | **Q** | Accept **`prototype_quest_gather_intro`** | | **Shift+Q** | First catalog-order **`not_started`** quest with all **`prerequisiteQuestIds`** **`completed`** | **HTTP defs catalog order (ordinal `id`):** combat → gather → operator chain → refine. After gather intro completes, **Shift+Q** accepts **combat** (not refine). After combat completes, **Shift+Q** accepts **refine**. After all three intros complete, **Shift+Q** accepts **operator chain**. **Expected quest HUD progression (`QuestProgressLabel`):** | Phase | Action | Expected HUD lines (high level) | |-------|--------|--------------------------------| | Boot | Godot **F5** | All four quests **`not started`** | | Gather intro | **Q** → gather **3** scrap (**R** at nodes) | Salvage Run **`active`** → counter → **`completed`** | | Combat intro | **Shift+Q** → defeat ×3 NPCs (**Tab** + **1**) | Clear the Pocket **`active`** → **`completed`**; encounter **`completed (3/3)`**; loot includes **`contract_handoff_token`** | | Refine intro | **Shift+Q** → craft **`refine_scrap_standard`** | Refine Stock **`active`** → **`completed`** | | Operator chain | **Shift+Q** → chain steps | Operator Chain **`active step 1…4`** → **`completed`** when token held | | Idempotency | Godot restart + **Q** / **Shift+Q** | All four remain **`completed`**; accept deny / no eligible quest | **Material / action notes for script author:** - Combat loot grants **`scrap_metal_bulk` ×10** + **`contract_handoff_token` ×1** (NEO-111) — satisfies chain terminal **`inventory_has_item`** once combat intro completes (token persists for chain step 4). - Chain step 1 requires **5** successful gathers **while chain step 1 is active** (objective counter; prior bag scrap does not substitute). Use [NEO-75](../manual-qa/NEO-75.md) anchor table (**alpha** +1, **beta** +2, **gamma** +3, **delta** +5). - Chain step 3 **`make_field_stim_mk0`** needs **2** `refined_plate_stock` + **1** scrap — plan extra **`refine_scrap_standard`** crafts after combat loot if bag is short on plates. - Defeat order for combat pocket is **flexible** (NEO-111); script asserts **0/3 → completed (3/3)** only. **Main checklist spine (to expand in `docs/manual-qa/NEO-123.md`):** 1. Start server + Godot **F5**; confirm four quests **`not started`**. 2. **Q** accept gather intro; gather until **`Intro: Salvage Run: completed`**. 3. **Shift+Q** accept combat intro; defeat three prototype NPCs; confirm encounter + combat intro **`completed`** and bag contains **`contract_handoff_token`**. 4. **Shift+Q** accept refine intro; craft **`refine_scrap_standard`**; confirm refine intro **`completed`**. 5. **Shift+Q** accept operator chain; complete steps 1–4 (gather ×5, refine, stim craft, token check); confirm **`Operator Chain: completed`**. 6. **Record** final quest HUD snapshot (all four **`completed`**). 7. **Idempotency — Godot restart:** stop Godot; **F5** again **without** stopping server. Quest HUD still shows all four **`completed`**. 8. **Idempotency — duplicate accepts:** **Q** on gather → **`denied — already_completed`**; **Shift+Q** → **`no eligible quest`** (or deny on ineligible pick); HUD unchanged from step 6. 9. Regression pointers: [NEO-122](../manual-qa/NEO-122.md) component HUD, [NEO-111](../manual-qa/NEO-111.md) encounter loot, [NEO-75](../manual-qa/NEO-75.md) economy craft. ### 2. Client README (`client/README.md`) Add **End-to-end onboarding quest loop (NEO-123)** section after [Quest progress + accept HUD (NEO-122)](../../client/README.md#quest-progress--accept-hud-neo-122), mirroring NEO-111 / NEO-75 capstone sections: - One-line Epic 7 Slice 1 capstone goal. - Flow table: fresh restart → **Q** gather → **Shift+Q** combat → **Shift+Q** refine → **Shift+Q** chain → four-step chain objectives → idempotency. - Cross-links: NEO-112 catalog, NEO-118 wiring, NEO-119/120 HTTP, NEO-122 HUD, NEO-75 economy, NEO-111 combat token. - Pointer to **`docs/manual-qa/NEO-123.md`**. ### 3. Module / backlog alignment (on land) When capstone QA passes: - [E7M1-prototype-backlog.md](E7M1-prototype-backlog.md) — E7M1-12 AC checkboxes. - [E7_M1_QuestStateMachine.md](../decomposition/modules/E7_M1_QuestStateMachine.md) — module status **Ready**; Slice 1 client capstone note. - [documentation_and_implementation_alignment.md](../decomposition/modules/documentation_and_implementation_alignment.md) — E7.M1 row: NEO-123 landed; Epic 7 Slice 1 client capstone complete. - [module_dependency_register.md](../decomposition/modules/module_dependency_register.md) — E7.M1 **Ready** when all stories landed. ### 4. Integration fixes (conditional) Run capstone QA on `main` (or branch with NEO-122 merged). If any step fails: | Symptom | Likely fix surface | |---------|-------------------| | Quest HUD stale after gather/craft/defeat | `main.gd` refresh hook or `quest_hud_controller.gd` | | Chain step counter stuck | Server wiring (unlikely) — file issue; client displays GET only | | Token step not completing | Verify encounter loot + quest GET refresh on encounter **`completed`** (NEO-110 belt-and-suspenders) | | Shift+Q picks unexpected quest | Document vs fix picker — **out of scope** unless script order is impossible | Document any fix in this plan’s **Implementation reconciliation** section and add regression note to manual QA. ## Files to add | Path | Purpose | |------|---------| | `docs/plans/NEO-123-implementation-plan.md` | This plan. | | `docs/manual-qa/NEO-123.md` | Single-session four-quest capstone checklist with idempotency + regression steps. | ## Files to modify | Path | Rationale | |------|-----------| | `client/README.md` | **End-to-end onboarding quest loop (NEO-123)** section with flow table and cross-links. | | `docs/manual-qa/NEO-122.md` | Cross-link to NEO-123 capstone; note intro accept order defers to capstone script. | | `docs/plans/E7M1-prototype-backlog.md` | E7M1-12 AC checkboxes when capstone lands. | | `docs/decomposition/modules/E7_M1_QuestStateMachine.md` | Module status **Ready** + capstone landed note on completion. | | `docs/decomposition/modules/documentation_and_implementation_alignment.md` | E7.M1 row: NEO-123 landed; Slice 1 complete. | | `docs/decomposition/modules/module_dependency_register.md` | E7.M1 **Ready** when capstone lands. | **Conditional (only if capstone QA fails):** `client/scripts/main.gd`, `client/scripts/quest_hud_controller.gd`, or related refresh wiring — minimal gap-fill; document paths in reconciliation. ## Tests | Test file | What it covers | |-----------|----------------| | *(none planned)* | **Docs-primary scope** — server quest spine covered by **`QuestProgressApiTests`**, **`QuestAcceptApiTests`**, **`QuestObjectiveWiringTests`**, and content CI; client covered by NEO-122 GdUnit suites. Capstone proof is **`docs/manual-qa/NEO-123.md`** human QA. | If integration fixes land, add or extend GdUnit only when the fix introduces new client parse/refresh behavior worth locking (follow [testing-expectations.md](../../.cursor/rules/testing-expectations.md) AAA layout). ## Open questions / risks | Item | Agent recommendation | Status | |------|----------------------|--------| | **NEO-122 manual QA step 6 (Shift+Q → refine)** | Capstone adopts **catalog order** (combat before refine); update NEO-122 cross-link note, not NEO-122 checklist retroactively unless user asks. | **adopted** | | **Resource node depletion mid-session** | Script uses four anchors from NEO-75; fresh server gives enough total yield for intro + chain gathers. | **adopted** | | **Chain step 4 before combat loot** | Script orders combat intro before chain accept; token in bag before chain step 4. | **adopted** | | **Docs-only fails capstone** | Escalate to minimal client refresh fix in same story; record in reconciliation. | **deferred** |