3.2 KiB
3.2 KiB
NEO-29 — Manual QA checklist
| Field | Value |
|---|---|
| Key | NEO-29 |
| Title | E1M4-01: HotbarLoadout v1 contract + baseline persistence path |
| Linear | https://linear.app/neon-sprawl/issue/NEO-29/e1m4-01-hotbarloadout-v1-contract-baseline-persistence-path |
| Plan | docs/plans/NEO-29-implementation-plan.md |
| Branch | NEO-29-hotbarloadout-v1-contract-baseline-persistence-path |
1) Setup sanity
- Start server:
cd server/NeonSprawl.Server && dotnet run. - Confirm health endpoint responds:
curl -s http://localhost:5253/health. - Confirm baseline loadout for dev player is reachable:
curl -s http://localhost:5253/game/players/dev-local-1/hotbar-loadout.
2) Happy path (bind and re-read)
- Bind slot 0 + slot 3 in one request:
curl -s -X POST http://localhost:5253/game/players/dev-local-1/hotbar-loadout -H "Content-Type: application/json" -d '{"schemaVersion":1,"slots":[{"slotIndex":0,"abilityId":"prototype_pulse"},{"slotIndex":3,"abilityId":"prototype_burst"}]}' - Verify response contains
updated=trueandloadout.slots[0].abilityId == "prototype_pulse"andloadout.slots[3].abilityId == "prototype_burst". - Run GET again and verify the same two bindings are still present.
3) Reconnect / persistence behavior
- If Postgres is configured (
ConnectionStrings__NeonSprawlset), stop and restart the server, then GET loadout and verify slot 0/3 bindings survived restart. - If Postgres is not configured (in-memory fallback), verify loadout behavior in the same process is stable and document that restart reset is expected for this mode.
4) Deny paths and reason codes
- Send out-of-bounds slot (
slotIndex: 8) and confirm response hasupdated=falsewithreasonCode == "slot_out_of_bounds". - Send unknown ability id (
abilityId: "not_real") and confirm response hasupdated=falsewithreasonCode == "unknown_ability". - Send duplicate slot index entries in one POST and confirm response has
updated=falsewithreasonCode == "duplicate_slot".
5) Client hydration sanity
- Run
client/scenes/main.tscnin Godot after slot bindings exist on server. - Confirm no startup warnings from
HotbarLoadoutClientand verifyHotbarStatenode exists under the scene root with 8-slot mirror populated from server response.
6) Client-driven update sanity (no curl)
- With
main.tscnrunning, open the remote SceneTree and selectHotbarLoadoutClientunder the scene root. - Execute
request_bind_slot(2, "prototype_guard")on that node (Editor script console or remote call). - Confirm no client warning log from
HotbarLoadoutClientand verifyHotbarState.slots_snapshot()now contains"prototype_guard"at index2. - Restart the client scene and verify hydration still reflects slot
2from server (proves client fetch + apply path, not just local mutation).
7) Client deny-path signal sanity
- With
main.tscnrunning, executerequest_bind_slot(2, "not_real")onHotbarLoadoutClient. - Confirm the client logs/handles a deny response (server
updated=false,reasonCode="unknown_ability"), andHotbarStateremains unchanged from the last valid loadout.