75 lines
2.8 KiB
Markdown
75 lines
2.8 KiB
Markdown
# Manual QA — NEO-44 (combat defeat → gig XP, not skill XP)
|
|
|
|
Reference: [implementation plan](../plans/NEO-44-implementation-plan.md), [NEO-82 plan](../plans/NEO-82-implementation-plan.md) (cast defeat spine), [progression.md](../game-design/progression.md).
|
|
|
|
## Preconditions
|
|
|
|
- Run `NeonSprawl.Server` from `server/NeonSprawl.Server` (`dotnet run`; default `http://localhost:5253`).
|
|
- Player **`dev-local-1`** (default seed).
|
|
- For a clean gig XP baseline on in-memory mode, restart the server before the defeat spine.
|
|
|
|
```bash
|
|
BASE=http://localhost:5253
|
|
ID=dev-local-1
|
|
```
|
|
|
|
## Automated coverage
|
|
|
|
- `GigProgressionSnapshotApiTests`, `CombatDefeatGigXpGrantTests`, `AbilityCastApiTests.PostAbilityCast_ShouldGrantGigXpOnceOnDefeat_WithoutChangingSkillProgression`
|
|
- Bruno: `bruno/neon-sprawl-server/gig-progression/`
|
|
|
|
## 1. Fresh gig snapshot
|
|
|
|
```bash
|
|
curl -sS "${BASE}/game/players/${ID}/gig-progression"
|
|
```
|
|
|
|
Expect **`schemaVersion` 1**, **`mainGigId` `"breach"`**, one gig row with **`xp` 0** and **`level` 1** (fresh in-memory server).
|
|
|
|
## 2. Baseline skill snapshot (control)
|
|
|
|
```bash
|
|
curl -sS "${BASE}/game/players/${ID}/skill-progression" | jq '.skills[] | select(.id=="salvage" or .id=="refine")'
|
|
```
|
|
|
|
Note **`salvage`** and **`refine`** **`xp`** values — combat defeat must not change them.
|
|
|
|
## 3. Defeat `prototype_target_alpha` (four pulses)
|
|
|
|
Move in range, bind pulse, lock alpha, cast four times with ~3.2s between casts (or run Bruno **`Get gig progression after defeat spine.bru`**).
|
|
|
|
Minimal curl sequence (slot 0):
|
|
|
|
```bash
|
|
curl -sS -X POST "${BASE}/game/players/${ID}/hotbar-loadout" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"schemaVersion":1,"slots":[{"slotIndex":0,"abilityId":"prototype_pulse"}]}'
|
|
|
|
curl -sS -X POST "${BASE}/game/players/${ID}/target/select" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"schemaVersion":1,"targetId":"prototype_target_alpha"}'
|
|
|
|
# Repeat cast (respect 3s pulse cooldown between each):
|
|
curl -sS -X POST "${BASE}/game/players/${ID}/ability-cast" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"schemaVersion":1,"slotIndex":0,"abilityId":"prototype_pulse","targetId":"prototype_target_alpha"}'
|
|
```
|
|
|
|
Fourth accept should show **`targetDefeated": true`**. Fifth cast should deny **`target_defeated`**.
|
|
|
|
## 4. Verify gig XP granted once
|
|
|
|
```bash
|
|
curl -sS "${BASE}/game/players/${ID}/gig-progression"
|
|
```
|
|
|
|
Expect **`breach`** row **`xp`** increased by **25** from the pre-spine baseline (Postgres retains prior totals across the full Bruno collection).
|
|
|
|
## 5. Verify skill XP unchanged
|
|
|
|
Re-run step 2 — **`salvage`** and **`refine`** **`xp`** must match the pre-defeat baseline.
|
|
|
|
## Invariant
|
|
|
|
Combat encounters grant **gig XP on main gig only** ([progression.md](../game-design/progression.md)). Mission/scripted skill payouts use **`mission_reward`** via E2.M2 ([NEO-43](./NEO-43.md)) — not the combat defeat path.
|