NEO-111: add capstone manual QA script and README loop section.

Single-session Godot checklist with flexible defeat order, inventory
verification, and Godot-restart idempotency; cross-link from NEO-110.
pull/150/head
VinPropane 2026-05-31 20:02:14 -04:00
parent 385cabe883
commit e900ba992b
3 changed files with 114 additions and 1 deletions

View File

@ -225,6 +225,29 @@ Full capstone checklist: [`docs/manual-qa/NEO-86.md`](../docs/manual-qa/NEO-86.m
Full checklist: [`docs/manual-qa/NEO-110.md`](../docs/manual-qa/NEO-110.md).
## End-to-end encounter clear loop (NEO-111)
Epic 5 Slice 3 capstone — defeat all three prototype NPCs, receive loot + quest token **once**, verify inventory **in Godot** without Bruno.
**Flow:** fresh server restart → boot encounter HUD **0/3** → defeat ×3 (any order) → progress **1/3 → 2/3 → completed** → loot label + inventory → Godot restart idempotency.
| Step | Input / trigger | HUD / server outcome |
|------|-----------------|----------------------|
| Boot | Godot **F5** + fresh server | **`EncounterProgressLabel`** **`not started (0/3)`**; **`Loot: —`**; empty bag |
| Engage | **Tab** + **1** on first NPC | Encounter activates on first damaging hit (NEO-106); progress **`1/3`** after defeat |
| Second defeat | Lock + cast second NPC | **`2/3`**; loot still **`—`** |
| Third defeat | Lock + cast third NPC | **`completed (3/3)`**; **`EncounterCompleteLabel`** lists grants; **`InventoryLabel`** auto-refreshes |
| Idempotency | Stop Godot + **F5** (server still running) | Encounter still **`completed`**; inventory counts unchanged |
| Re-cast defeated | **Tab** + **1** on defeated NPC | **`ability_cast_denied: target_defeated`**; no duplicate loot or gig XP |
**Cross-links:** [NEO-106](../docs/plans/NEO-106-implementation-plan.md) combat wiring · [NEO-108](../docs/plans/NEO-108-implementation-plan.md) encounter-progress GET · [NEO-110](../docs/manual-qa/NEO-110.md) HUD components · [NEO-98](../docs/manual-qa/NEO-98.md) NPC combat · [NEO-86](../docs/manual-qa/NEO-86.md) gig XP per defeat.
**Scripts:** `encounter_progress_client.gd`, `inventory_client.gd`, `ability_cast_client.gd`, `combat_targets_client.gd` — wired from `main.gd`.
**Preconditions:** **Server restart** before capstone run resets NPC HP, encounter progress, inventory, and gig XP.
Full capstone checklist: [`docs/manual-qa/NEO-111.md`](../docs/manual-qa/NEO-111.md).
## Inventory snapshot HUD (NEO-72)
- **`GET /game/players/{id}/inventory`** — server-authoritative bag (**24** slots) + equipment stub (**1** slot); see [server README — Player inventory](../server/README.md#player-inventory-neo-54-store-neo-55-http).

View File

@ -49,7 +49,7 @@ Player casts **`prototype_pulse`** (**25** damage, ~**3 s** cooldown).
- Defeat order may differ from table — server tracks order-independent subset; count is **`defeatedTargetIds.size()`**.
- Capstone baseline prefers **server restart** over mid-session fixture POST.
- Full three-NPC loop + idempotency capstone: [NEO-111](NEO-111.md) (when landed).
- Full three-NPC loop + idempotency capstone: [NEO-111 manual QA](NEO-111.md).
- Component combat regression: [NEO-98 manual QA](NEO-98.md).
## Acceptance

View File

@ -0,0 +1,90 @@
# NEO-111 — Manual QA checklist
| Field | Value |
|-------|-------|
| Key | NEO-111 |
| Title | E5M3-12: Playable encounter clear capstone (Godot) |
| Linear | https://linear.app/neon-sprawl/issue/NEO-111/e5m3-12-playable-encounter-clear-capstone-godot |
| Plan | `docs/plans/NEO-111-implementation-plan.md` |
| Branch | `NEO-111-playable-encounter-clear-capstone` |
## Preconditions
- **Fresh dev player:** stop any running server, then start a new instance so in-memory **`dev-local-1`** NPC HP, encounter progress, inventory, and gig XP reset.
- **No Bruno/curl** for this checklist — defeat chain uses Godot **Tab** + **1** only.
- NEO-110 encounter HUD, NEO-106 combat wiring, and NEO-108 encounter-progress GET landed on `main`.
- **`Economy HUD`** toggle **on** for inventory verification.
## Archetype reference (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). Defeat all three in **any order** — server tracks an order-independent subset.
## Expected encounter HUD progression
| After | `EncounterProgressLabel` | `EncounterCompleteLabel` |
|-------|--------------------------|---------------------------|
| Boot (no engagement) | `prototype_combat_pocket: not started (0/3)` | `Loot: —` |
| 1st NPC defeated | `prototype_combat_pocket: 1/3` | `Loot: —` |
| 2nd NPC defeated | `prototype_combat_pocket: 2/3` | `Loot: —` |
| 3rd NPC defeated | `prototype_combat_pocket: completed (3/3)` | `scrap_metal_bulk ×10` and `contract_handoff_token ×1` (display names when item defs loaded) |
| After Godot restart (idempotency) | still **`completed (3/3)`** | unchanged grant lines |
## Expected inventory after completion
On a fresh server restart the bag starts empty. After the third defeat, **`InventoryLabel`** should show at least:
| Item id | Quantity |
|---------|----------|
| `scrap_metal_bulk` | **10** |
| `contract_handoff_token` | **1** |
Record these quantities before idempotency steps.
## Expected gig XP after three defeats
**`GigXpLabel`** should show **`breach: L1 · 75 xp`** (NEO-44: **25** gig XP per defeat × **3**). No further gig XP increase during idempotency steps.
## Checklist
### Boot + encounter clear
1. Start server: `cd server/NeonSprawl.Server && dotnet run`.
2. Run Godot main scene (**F5**). Confirm boot lines: **`Encounter: … not started (0/3)`** and **`Loot: —`** on **`EncounterProgressLabel`** / **`EncounterCompleteLabel`** (combat HUD block, below **`PlayerCombatHpLabel`**).
3. Defeat **first** prototype NPC (any archetype): walk to marker, **Tab** lock, press **1** until **`Cast: … — defeated!`**. Verify **`EncounterProgressLabel`** shows **`1/3`** (may lag one GET behind cast — wait ~1 s).
4. Defeat **second** prototype NPC (either remaining archetype): lock, cast until defeated. Verify **`2/3`**.
5. Defeat **third** prototype NPC: lock, cast until defeated (**8** pulses for Elite). Verify **`completed (3/3)`** and **`EncounterCompleteLabel`** lists **`scrap_metal_bulk ×10`** and **`contract_handoff_token ×1`** (or raw ids if defs still loading).
6. Open **`Economy HUD`** body: **`InventoryLabel`** shows **`scrap_metal_bulk`** (**10**) and **`contract_handoff_token`** (**1**) without pressing **I** (auto-refresh on completion GET).
7. Verify **`GigXpLabel`** shows **`breach: L1 · 75 xp`**.
### Idempotency
8. **Record** inventory quantities for **`scrap_metal_bulk`** and **`contract_handoff_token`** from step 6.
9. **Godot restart (re-login):** stop Godot run (**Shift+F5** or stop button); **F5** again **without** stopping the server. After boot hydrate, verify **`EncounterProgressLabel`** still **`completed (3/3)`** and **`EncounterCompleteLabel`** grant lines unchanged.
10. Verify **`InventoryLabel`** quantities **match step 8** — no duplicate loot.
11. Lock a **defeated** NPC (**Tab** at its marker); press **1**. Verify **`CastFeedbackLabel`** shows **`ability_cast_denied: target_defeated`**; encounter HUD and inventory **unchanged** from steps 910.
12. Verify **`GigXpLabel`** still **`breach: L1 · 75 xp`** — no extra gig XP from idempotency casts.
### Regression
13. **`CastFeedbackLabel`** still shows readable deny reasons (NEO-28 / NEO-98).
14. Component encounter HUD detail: [NEO-110 manual QA](NEO-110.md). Component NPC combat: [NEO-98 manual QA](NEO-98.md).
## Notes
- Defeat order may differ from the archetype table — only **0/3 → 3/3** progression is asserted.
- Capstone baseline prefers **server restart** over mid-session fixture POST.
- **`POST /game/__dev/combat-targets-fixture`** is **out of scope** for idempotency — it clears encounter progress/completion alongside NPC HP reset ([server README — dev combat-target fixture](../../server/README.md#dev-combat-target-fixture-brunomanual-qa)).
- Slice 3 Epic AC: completing **`prototype_combat_pocket`** grants expected items + quest token **once** ([epic_05 Slice 3](../../decomposition/epics/epic_05_pve_combat.md#epic-5-slice-3)).
## Acceptance
- [ ] Steps 114 completable in one session without Bruno/curl.
- [ ] Progress label shows **1/3**, **2/3**, then **completed (3/3)** after three defeats (any order).
- [ ] Loot label and inventory show **`scrap_metal_bulk` ×10** + **`contract_handoff_token` ×1**; quantities unchanged after Godot restart + defeated-NPC casts.
- [ ] Epic 5 Slice 3 AC satisfied in Godot.