neon-sprawl/docs/manual-qa/NEO-123.md

145 lines
8.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 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-112NEO-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 119 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.