docs(slice-0.4): record First Loot verification results

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Bastian Wagner
2026-08-20 10:04:26 +02:00
parent 21b377f70c
commit 1a7a766f2b

View File

@@ -3913,7 +3913,37 @@ git commit -m "docs(slice-0.4): record First Loot verification results"
| all tests pass | Task 13 Step 1 |
| backend and frontend builds succeed | Task 13 Step 1 |
---
## Verification Results
Verified 2026-08-20 against a live PostgreSQL instance (Docker container `awesome_babbage`) with dev servers run on alternate ports (API 3901, web 4901) to avoid colliding with a sibling worktree's own dev servers already occupying 3000/4200.
**Step 1 — automated checks:** all four green.
- API: 23 test suites, 119 tests, 0 failures.
- Web: 13 test suites, 104 tests, 0 failures.
- `npm run build:api`: succeeds.
- `npm run build:web`: succeeds (pre-existing `combat-page.component.scss` budget warning only — 9.14 kB vs. the 4 kB advisory threshold, well under the 12 kB error threshold; not a new regression, tracked since Task 11).
**Step 2 — migration/seed round-trip:** `db:revert``db:migrate``db:seed``db:seed` all succeeded. Post-cycle counts: `item_definitions` = 12, `loot_table_entries` = 5 — unchanged by the second seed run.
**Step 3 — Aschenratte victory (browser, Playwright-driven Chromium against the real dev servers):**
- No-drop victory: +8 XP, +4 Silber, "Keine besondere Beute gefunden." with no error styling.
- Drop victory: +8 XP, +5 Silber, item card showing icon, "Abgenutztes Kurzschwert", "GEWÖHNLICH" (the 8% starter-equipment branch of the ash-rat table, hit before the 60% Aschenfell branch in this run — both are real, data-driven rolls from the same table).
- TopBar silver/XP increased by exactly the granted amounts after each victory.
**Step 4 — Straßenräuber victory:**
- +16 XP and silver rolls of 12, 13, and 10 across three wins — all within the documented 915 range.
- One win dropped two items in a single combat (Räuberhaube + Plündererhandschuhe), directly demonstrating independent per-entry rolls (spec §17).
- A later win dropped Räuberklinge alone; icon, name, and "GEWÖHNLICH" rendered correctly.
- `character_items` verified via SQL: `bandit-blade`, `bandit-hood`, `raider-gloves`, `worn-short-sword`, and `ash-pelt` (from prior sessions) all persisted as real rows, quantity 1 each — not cosmetic (spec §27).
**Step 5 — refresh does not reroll:** navigated to `/combat/<won-combat-id>` as a fresh page load (equivalent to F5 — no client cache reused). Rendered XP (+16), silver (+10), and item (Räuberklinge) were byte-identical to the original grant. `SELECT count(*) FROM combat_rewards WHERE combat_id = '<id>'` = exactly `1`.
**Step 6 — repeated reward request cannot farm:** `POST /api/combats/<id>/actions` on the already-WON combat returned `409 COMBAT_ALREADY_FINISHED`. The subsequent `GET` returned the identical persisted reward. Confirmed via SQL that `combat_rewards` count and the character's `experience`/`silver` totals were unchanged from Step 5.
**Step 7 — return to hunt:** "Zur Jagd" returns to `/hunt` and redisplays the same encounter list, including the just-consumed encounter. Re-attacking that consumed encounter is rejected server-side with `HUNT_ENCOUNTER_ALREADY_CONSUMED` ("Diese Begegnung wurde bereits genutzt.") — no duplicate combat, no duplicate reward. "Neu suchen" / "Jagd beginnen" successfully starts a fresh hunt with new encounters.
**Environment notes for future runs:** the worktree's `.env` (untracked, copied from the main checkout) needs its own `PORT` and the web app needs `ng serve --proxy-config <temp-file-pointing-at-that-port>` whenever a sibling worktree's dev servers are already running on 3000/4200. `psql` is not on PATH — use `docker exec awesome_babbage psql -U ashen -d ashen_realms`.