# NEO-123 — Manual QA checklist | 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 | | Plan | `docs/plans/NEO-123-implementation-plan.md` | | Branch | `NEO-123-playable-onboarding-quest-chain-capstone` | ## Preconditions - **Fresh dev player:** stop any running server, then start a new instance so in-memory **`dev-local-1`** quest progress, inventory, encounter progress, NPC HP, and resource-node depletion reset. - **No Bruno/curl** for this checklist — accept uses **Q** / **Shift+Q**; gameplay uses **R**, **Tab** + **1**, and Economy HUD **Craft** buttons only. - NEO-112–NEO-122 quest spine and NEO-75/NEO-111 economy/combat capstones landed on `main`. - **`Economy HUD`** toggle **on** for craft and inventory verification. ## Quest catalog (frozen) | Quest id | Display name | Prerequisites | Objective | |----------|--------------|---------------|-----------| | `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 → hold **`contract_handoff_token`** ×1 | ## Accept key contract | Key | Action | |-----|--------| | **Q** | Accept **`prototype_quest_gather_intro`** | | **Shift+Q** | First catalog-order **`not_started`** quest with all **`prerequisiteQuestIds`** **`completed`** | **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**. ## Resource node anchors (gather) | Node id | Anchor | Yield per **R** | |---------|--------|-----------------| | `prototype_resource_node_alpha` | **(12, −6)** | +1 scrap | | `prototype_subsurface_vein_beta` | **(18, −6)** | +2 scrap | | `prototype_bio_mat_gamma` | **(12, 0)** | +3 scrap | | `prototype_urban_bulk_delta` | **(18, 0)** | +5 scrap | Nodes allow multiple gathers (`maxGathers` **10** each). Quest gather counters credit **scrap quantity granted**, not gather event count. ## Combat archetypes (defeat order flexible) | Archetype | Instance id | Marker | Pulses to defeat | |-----------|-------------|--------|------------------| | Melee | `prototype_npc_melee` | orange west **`(-3, -3)`** | 4 | | Ranged | `prototype_npc_ranged` | purple SE **`(3, 3)`** | 4 | | Elite | `prototype_npc_elite` | gold origin **`(0, 0)`** | 8 | Player casts **`prototype_pulse`** (**25** damage, ~**3 s** cooldown). ## Expected quest HUD progression | Phase | `QuestProgressLabel` (high level) | `QuestAcceptFeedbackLabel` | |-------|-----------------------------------|----------------------------| | Boot | All four **`not started`** | **`Quest accept: — (Q gather / Shift+Q next)`** | | Gather intro | Salvage Run **`active step 1`** → **`completed`** | **`accepted`** on **Q** | | Combat intro | Clear the Pocket **`active`** → **`completed`** | **`accepted`** on **Shift+Q** | | Refine intro | Refine Stock **`active`** → **`completed`** | **`accepted`** on **Shift+Q** | | Operator chain | Operator Chain **`active step 1…4`** → **`completed`** | **`accepted`** on **Shift+Q** | | Idempotency | All four still **`completed`** | **Q** deny / **Shift+Q** no eligible | ## Material math (suggested path) | Phase | Actions | Bag after (approx.) | |-------|---------|---------------------| | Gather intro | **Q**; **R** at **gamma** once (+3 scrap) | 3 scrap | | Combat intro | **Shift+Q**; defeat ×3 NPCs | 13 scrap, 1 token (+10 scrap loot) | | Refine intro | **Shift+Q**; craft **`refine_scrap_standard`** | 8 scrap, 1 plate, 1 token | | Chain step 1 | **Shift+Q**; **R** at **delta** once (+5 scrap) | 13 scrap; counter **5/5** | | Chain step 2 | Craft **`refine_scrap_standard`** | 8 scrap, 2 plates, 1 token | | Chain step 3 | Craft **`make_field_stim_mk0`** | 7 scrap, 0 plates, 1 stim, 1 token | | Chain step 4 | Token already held from combat loot | Operator Chain **`completed`** | Adjust gathers/crafts if bag counts differ; counters and craft denies are authoritative. ## Checklist ### Boot 1. Start server: `cd server/NeonSprawl.Server && dotnet run`. 2. Run Godot main scene (**F5**). Confirm **`QuestProgressLabel`** lists four **`not started`** quests and **`QuestAcceptFeedbackLabel`** shows the idle hint (in **`HudRootScroll`**). **`Economy HUD`** on; economy panel pinned bottom-left. ### Intro: Salvage Run (gather) 3. Press **Q**. Verify **`Intro: Salvage Run: active step 1`** and accept success feedback. 4. Walk to **gamma** **(12, 0)**; press **R** once. Verify counter **`chain_obj_gather`** is **not** present yet; gather intro counter increases (e.g. **`gather_intro_obj_scrap=3`**). 5. Verify **`Intro: Salvage Run: completed`**. ### Intro: Clear the Pocket (combat) 6. Press **Shift+Q**. Verify **`Intro: Clear the Pocket: active`** (combat intro — catalog order picks combat before refine). 7. Defeat all three prototype NPCs (**Tab** + **1**, any order). Verify **`EncounterProgressLabel`** **`completed (3/3)`** and **`EncounterCompleteLabel`** lists **`scrap_metal_bulk ×10`** + **`contract_handoff_token ×1`**. 8. Verify **`Intro: Clear the Pocket: completed`** and **`InventoryLabel`** shows **`contract_handoff_token`** (**1**). ### Intro: Refine Stock (craft) 9. Press **Shift+Q**. Verify **`Intro: Refine Stock: active step 1`**. 10. In Economy HUD, **Craft** **`refine_scrap_standard`** when **≥5** scrap in bag. Verify **`Intro: Refine Stock: completed`**. ### Operator Chain (four steps) 11. Press **Shift+Q**. Verify **`Operator Chain: active step 1`**. 12. **Chain step 1 — gather ×5:** press **R** at resource nodes until step advances (suggested: **delta** once for +5 scrap). Verify **`active step 2`** on **`QuestProgressLabel`**. 13. **Chain step 2 — refine:** craft **`refine_scrap_standard`**. Verify **`active step 3`**. 14. **Chain step 3 — stim:** craft **`make_field_stim_mk0`** (needs **2** plates + **1** scrap). Verify **`active step 4`**. 15. **Chain step 4 — token:** verify **`Operator Chain: completed`** without extra actions (token from step 8). ### Capstone snapshot 16. **Record** final **`QuestProgressLabel`**: all four quests **`completed`**. ### Idempotency (no duplicate quest completion) 17. **Godot restart:** stop Godot (**Shift+F5**); **F5** again **without** stopping the server. Verify all four quests still **`completed`**. 18. Press **Q** on gather intro. Verify **`Quest accept: denied — already_completed`** (or **`already_active`**). 19. Press **Shift+Q**. Verify **`Quest accept: no eligible quest`** (or equivalent deny). Quest HUD **unchanged** from step 16. ### Regression 20. Component quest HUD: [NEO-122 manual QA](NEO-122.md). 21. Encounter loot + token: [NEO-111 manual QA](NEO-111.md). 22. Economy craft panel: [NEO-75 manual QA](NEO-75.md). ## Notes - **Shift+Q catalog order** is intentional for Slice 1 — combat intro before refine intro after gather completes. Full capstone supersedes [NEO-122](NEO-122.md) partial intro path. - Combat defeat order is flexible; only **0/3 → completed (3/3)** is asserted. - Chain terminal step is **`inventory_has_item`** — no token consume in Slice 1. - **`POST /game/__dev/combat-targets-fixture`** is **out of scope** — clears encounter progress unsuitable for idempotency ([server README — dev combat-target fixture](../../server/README.md#dev-combat-target-fixture-brunomanual-qa)). - Epic 7 Slice 1 AC: 3 onboarding + 1 chain complete without duped completion ([epic_07 Definition of Done](../decomposition/epics/epic_07_quest_faction.md#epic-7-definition-of-done)). - **Slice 2 reward verification:** quest completion bundles + economy idempotency — [NEO-132 manual QA](NEO-132.md) (supersedes for reward delivery AC). ## Acceptance - [x] Steps 1–19 completable in one session without Bruno/curl. - [x] All four prototype quests reach **`completed`**; operator chain finishes when **`contract_handoff_token`** held. - [x] Godot restart + duplicate **Q**/**Shift+Q** leave quest statuses unchanged (no duplicate completion). - [x] Epic 7 Slice 1 AC satisfied in Godot.