---
phase: 06.1-gap-closure-d-39-d-46-uat-2026-05-11
status: pending-rerun
last_updated: 2026-05-12
operator: decidel
re_runs_after_findings:
  - D-39
  - D-40
  - D-41
  - D-42
  - D-43
  - D-44
  - D-45
  - D-46
---

# Phase 06.1 — Human UAT (re-run after gap-closure)

> Five manual verifications targeting the 2026-05-11 finding set (D-39..D-46). Test 2 (CLI-08) is THE milestone artifact for the rebuild — capture `06.1-CLI-08-milestone.mp4` if all five pass. The 2026-05-11 video at `.planning/phases/06-client-rebuild-mvp-gate-cli-08-hard-milestone/uat-test-1-2.mp4` is the ground-truth broken-state reference.

<!-- [doc->REQ-CLI-08] [doc->REQ-CLI-06] [doc->REQ-CLI-07] [doc->REQ-AST-01] -->

This script follows the format of `.planning/phases/06-client-rebuild-mvp-gate-cli-08-hard-milestone/06-HUMAN-UAT.md`. Run AFTER all Phase 06.1 plans (06.1-01..06.1-07) merge and the staging CI auto-redeploys. Verify deploy: visit `https://staging.rebno.decidel.com/?invite=$STAGING_INVITE_TOKEN` and confirm the build hash in the page footer matches the latest `main` commit.

---

## Test 1 — Alpha-keyed sprites visible (D-39 closure)

**Why manual:** Background+sprite layering on real GPU with real CSP / blob: img-src wiring is not headless-reproducible at staging-equivalent fidelity. Closes D-39 (solid white box behind sprites).

**Why it failed 2026-05-11:** BMP→PNG bootstrap did not key the source-white pixel to alpha; sprites rendered with a solid white halo per the 2026-05-11 video.

**Instructions:**
1. Open `https://staging.rebno.decidel.com/?invite=$STAGING_INVITE_TOKEN` in Chrome.
2. Log in as `uat_a`. Wait for GameScene (`data-game-ready="true"`).
3. Take a 4× zoom-in screenshot of the local NaviStandD sprite over the mvp-room floor tiles.
4. Inspect the sprite outline: no opaque magenta, no white halo, no solid rectangle behind the figure. Background tiles must be visible AROUND the sprite, including in the gaps between the legs / between the head and torso.
5. Save the screenshot as `.planning/phases/06.1-gap-closure-d-39-d-46-uat-2026-05-11/06.1-test-1-alpha.png`.

**Pass criteria:**
- No solid color box (white or magenta) around the sprite.
- Floor tiles visible in transparent regions of the sprite bbox.
- Aseprite-roundtrip (read-only): open `assets/source/sprites/0000-NaviStandD.png` in Aseprite — file opens, alpha channel present, no white-edge artifacts.

**Fail signals:**
- Solid white box around sprite → D-39 fix did not land or atlas was not regenerated by CI.
- Magenta sentinel visible → bootstrap keyed to wrong sentinel RGB.

---

## Test 2 — Two-player CLI-08 MILESTONE (REQ-CLI-08)

**Why manual:** The "we shipped CLI-08" milestone artifact requires human capture. Playwright (the four `cli-08-*.e2e.test.ts` files from Plan 06.1-03) covers regression; this is the operator deliverable.

**Why it failed 2026-05-11:** Networking + protocol works; visuals (D-39..D-46) blocked closure.

**Instructions:**
1. Operator opens 2 Chrome browser windows (or two physical machines) against `https://staging.rebno.decidel.com/?invite=$STAGING_INVITE_TOKEN`.
2. Sign in as `uat_a` in window 1 and `uat_b` in window 2.
3. Wait for both clients to enter the `mvp-room` GameScene (`data-game-ready="true"` AND `data-room-id="mvp-room"`).
4. Confirm visually in both windows: floor tiles (`0023-Tile1` grid) visible, TSide1 bottom edges visible along the outer floor row, animated `0064-BKA1` background scrolling slowly down-and-right behind/around the room.
5. Start a screen recording covering BOTH browser windows (OBS / Loom / built-in screen recorder).
6. In window 1 (uat_a): walk toward uat_b using WASD (~5 seconds of movement). Confirm: local NaviRun animation cycles smoothly (≥ 3 distinct frames during a 1-second hold), remote sprite (uat_b) animates at the same visual cadence.
7. In window 2 (uat_b): walk toward uat_a.
8. Confirm visually: each window shows BOTH player sprites + nameplates moving smoothly; local nameplate is cyan c_aqua, remote nameplate is white c_white; both nameplates float above sprite head with a 1 px black shadow at offset (1, 1).
9. In window 1 (uat_a): press Enter, type `hello uat_b`, press Enter.
10. Confirm: window 2 shows `uat_a: hello uat_b` in the chat HUD within 2 seconds.
11. In window 2 (uat_b): press Enter, type `hi uat_a`, press Enter.
12. Confirm: window 1 shows `uat_b: hi uat_a`.
13. Stop the recording. Save as `.planning/phases/06.1-gap-closure-d-39-d-46-uat-2026-05-11/06.1-CLI-08-milestone.mp4`.

**Pass criteria:**
- Both clients see each other's sprite + nameplate.
- Bidirectional chat works in real time.
- Floor + TSide1 + animated background all render.
- Movement feels smooth (no choppiness; verified subjective + by Test 3/4 below).
- Video file exists and is committed (or linked).
- Operator types "approved — CLI-08 shipped" in the resume signal.

**Fail signals:**
- Either client sees only blue rectangles → 06.1-02 atlas regen did not deploy.
- No floor tiles → D-40 not closed (re-check Plan 06.1-04 verify-bail flip landed).
- Chat HUD missing after movement → re-entry regression (Phase 6 D-25 reopened).

---

## Test 3 — Anim rate consistency (D-41/D-42 closure)

**Why manual:** Local-vs-remote animation cadence symmetry is a subjective visual call beyond what a frame-count assertion captures.

**Why it failed 2026-05-11:** D-41 (local stuck) + D-42 (remote too fast) both rooted in the sim-tick callsite contract being lost between Phase 6 plans 06-16 and 06-17.

**Instructions:**
1. Continue from Test 2 (both clients still logged in to mvp-room).
2. In window 1 (uat_a): hold KeyD for exactly 2 seconds. Visually count the run-cycle frame transitions on the LOCAL sprite (should see ~15 frame advances across the 6-frame cycle = ~2.5 full cycles, i.e. the visible run animation completes 2-3 loops).
3. In window 2 (uat_b): observe uat_a's REMOTE sprite during the same 2-second window. The remote sprite must animate at the same visual cadence — NOT faster, NOT slower.
4. Repeat with uat_b holding KeyA and uat_a observing.

**Pass criteria:**
- Local + remote run animations cycle at visually identical rate (within human-eye tolerance).
- Neither is "stuck" (frame visibly advances on every keypress).
- Neither animates faster than ~10 fps visual (5 fps in the canonical 0.5 frames/tick × 30 Hz model = 15 fps real-time, fast-but-not-jarring).

**Fail signals:**
- Local sprite stuck → D-41 not closed (PlayerRenderer.onSimulationTickLocal not firing).
- Remote sprite at 60Hz blur → D-42 not closed (caller still on Phaser render frame).
- Remote slower than local → asymmetric sim-tick wiring; check PlayerRenderer.onSimulationTickRemote callsite.

---

## Test 4 — Camera follow smoothness + nameplate legibility + Fixedsys font load (D-45/D-46 closure)

**Why manual:** Subjective camera-feel + font legibility + nameplate position calls.

**Why it failed 2026-05-11:** D-45 (nametag too large/wrong color) + D-46 (camera does not follow) both visible in `uat-test-1-2.mp4`.

**Instructions:**
1. Continue from Test 2/3 (both clients still in mvp-room).
2. In window 1 (uat_a): walk continuously in a circle for ~10 seconds (W → D → S → A → W).
3. Observe: camera tracks the local sprite — the sprite stays in roughly the center of the viewport (within the D6.1-14 32×32 deadzone). No "leaving the screen" sensation.
4. Observe: as the camera scrolls, the animated `0064-BKA1` background continues to scroll under/past the room edges — no "void" at the room boundary; world feels infinite.
5. Open Chrome DevTools (F12) → Network tab → reload page → confirm `Fixedsys` (or whatever the chosen Fixedsys-Excelsior WOFF2 is named under `apps/client/public/assets/fonts/`) loads with HTTP 200, MIME `font/woff2`.
6. Visually inspect both nameplates: cyan (local) and white (remote), small pixel font (~10 px), positioned 16 px above sprite head, 1 px black drop-shadow at offset (1, 1).

**Pass criteria:**
- Camera holds local sprite within the central deadzone area for the full 10-second loop.
- Background tiles past the room edge — no black void.
- Fixedsys WOFF2 loads cleanly (no fallback to system monospace).
- Local nameplate cyan c_aqua, remote nameplate white c_white.
- Nameplate has a visible drop shadow on light tiles.

**Fail signals:**
- Sprite walks off-screen → D-46 not closed (camera startFollow not re-bound to local sprite).
- Black void beyond room edge → D6.1-16 unbounded camera + bkdraw not wired (Plan 06.1-05 / 06.1-06 not landed).
- Generic monospace font in nameplate → WOFF2 not loaded (CSP or path issue).
- Same color on both nameplates → D6.1-11 color rule not implemented.

---

## Test 5 — Walkable-edge block + background scroll/visible past room edge (D6.1-28/29 closure)

**Why manual:** "Player blocked at edge" + "background visible past edge" are visual / haptic checks.

**Why it failed 2026-05-11:** Not exercised — D-40 (no tiles) made the test impossible to run. Re-run now that tiles render.

**Instructions:**
1. Continue from Test 4 (both clients in mvp-room).
2. In window 1 (uat_a): walk to the bottom edge of the floor region (the southernmost row of `0023-Tile1` sprites). Continue holding KeyS.
3. Observe: local sprite stops at the floor edge; cannot walk off into non-floor space. The NaviMask feet bbox (18×7 px) sits flush against the floor's south edge.
4. Observe: while blocked at the edge, the animated `0064-BKA1` background continues to scroll behind/around — the world "outside" the floor is visible and lively, not a black void.
5. Walk in each of the other three cardinal directions to the corresponding floor edges; confirm the block applies at all four edges.
6. Walk diagonally into a corner (e.g. SE) and confirm wall-slide: the sprite slides along the free axis when one axis is blocked (per D6.1-28 per-axis sub-pixel collision).

**Pass criteria:**
- Sprite blocks at all four floor edges with NaviMask feet bbox at the boundary.
- Background scrolls past the room edge — infinite-feel.
- Diagonal-into-corner produces a wall-slide along the unblocked axis.

**Fail signals:**
- Sprite walks past floor edge → walkable-region mask not derived OR per-axis collision not wired (Plan 06.1-05).
- Black void past edge → D6.1-16 unbounded + bkdraw not landed (Plan 06.1-06).
- Diagonal-into-corner produces a hard stop (no slide) → D6.1-28 per-axis sub-pixel loop not landed.

---

## Sign-Off (after re-run)

| Test | Requirement | Status | Notes |
|------|-------------|--------|-------|
| 1 — Alpha-keyed sprites | REQ-AST-01, REQ-CLI-06 | ⬜ pending | run after 06.1-01 deploys |
| 2 — CLI-08 milestone | REQ-CLI-08 | ⬜ pending | run after 06.1-01..06.1-06 deploy |
| 3 — Anim rate consistency | REQ-CLI-04 | ⬜ pending | requires 06.1-04 PlayerRenderer fix |
| 4 — Camera + nameplate + font | REQ-CLI-05, REQ-CLI-06 | ⬜ pending | requires 06.1-04 + 06.1-05 |
| 5 — Walkable-edge + background | REQ-CLI-07 | ⬜ pending | requires 06.1-05 + 06.1-06 |

**Operator approval pending.** Update this section after the re-run.

**Resume signal:** Operator types one of:
- `approved — CLI-08 shipped` → close Phase 06.1, archive `06.1-CLI-08-milestone.mp4`, advance to Phase 7.
- `not approved — <D-XX, D-YY>` → spawn `/gsd-plan-phase 6 --gaps` for a third cycle.

---

## Re-Run Procedure Summary

1. Wait for CI to redeploy after Phase 06.1 plans merge to `main` (deploy-staging.yml auto-fires).
2. Verify the deployed build hash matches `main` HEAD.
3. Run Tests 1–5 in order (Test 2 is the milestone capture; Tests 3/4/5 piggyback on the same two-client session).
4. Run Plan 06.1-03's four Playwright e2e files (`pnpm --filter @rebno/client test:e2e -- cli-08-camera cli-08-tiles cli-08-nameplate cli-08-anim`) — all must exit 0 (GREEN gate alongside human UAT).
5. Commit the `06.1-CLI-08-milestone.mp4` + `06.1-test-1-alpha.png` artifacts to this phase directory.
6. Update the Sign-Off table above and append the operator's verdict line.

---

*Phase 06.1 UAT re-run script. Authored 2026-05-12 by Plan 06.1-03 executor. Operator must run after all Phase 06.1 plans land.*
