# Phase 06.5 — Client fast-path E2E UAT

[doc->REQ-DEP-04] [doc->REQ-CLI-08]

Operator UAT checklist for the Phase 06.5 client-only fast-path deploy
infrastructure. **Plan 06.5-05 executes this checklist end-to-end.** Pre-
authoring here keeps Plan 05 focused on running the drill rather than
writing the checklist mid-drill.

Target: every numbered drill produces a green or red signoff in under
15 minutes.

---

## 1. Prerequisites

- [ ] Phase 06.5 Plans 01-04 are merged to `main` and deployed to staging.
- [ ] `flyctl auth whoami` returns the operator's identity (no `auth login`
  flow needed mid-drill).
- [ ] Staging URL: `https://staging.rebno.decidel.com` — operator can resolve
  it in their browser.
- [ ] Two Chrome browser windows or profiles are open and ready for the
  two-player CLI-08 fidelity drill (Section 5).
- [ ] Operator has read `docs/deploy/ROLLBACK.md` (Section 4 of this UAT
  walks it).
- [ ] Operator has a stopwatch / timestamps captured per drill.

---

## 2. Cold-start fallback drill (REQ-DEP-01)

**Goal:** Prove the server stays up when the volume is empty — the bundled
`/app/public` fallback path serves the page until the first fast-path
release lands.

> **WARNING — staging only:** Step 1 deletes everything under
> `/data/client-assets/`. Do NOT run this drill on production. If staging
> is currently the gold copy of UAT state, snapshot the volume first.

1. Empty the volume:
   ```bash
   flyctl ssh console -a rebno-staging -C "rm -rf /data/client-assets || true"
   ```
2. Restart the machine to force a fresh boot under the empty-volume
   condition:
   ```bash
   flyctl machine restart -a rebno-staging
   ```
3. Probe the root URL — must return 200 and serve bundled `index.html`:
   ```bash
   curl -fsS https://staging.rebno.decidel.com/ >/dev/null && echo OK_cold_start
   ```
4. Confirm the server logged the bundled-fallback source:
   ```bash
   flyctl logs -a rebno-staging | grep -E 'static_assets_source_bundled|static_assets_source_env'
   ```
   Expected: at least one `static_assets_source_bundled` line. (If you
   see `static_assets_source_env` instead, the env-pointed dir was
   re-populated between steps 1 and 2; restart and try again.)
5. **Outcome:** Server stays up, bundled fallback serves the page, no
   crashloop. Tick the box.

- [x] **2-PASS** RE 2026-05-16T23:06:12Z

---

## 3. Fast-path deploy drill (REQ-DEP-04)

**Goal:** Prove a client-only commit deploys via the fast path (no Docker
image push) in under 5 minutes, and the symlink swap + GC behave correctly.

1. Push a **client-only** commit. A one-line CSS tweak under
   `apps/client/src/` is the canonical test change. Example:
   ```bash
   # In a feature branch:
   echo "/* uat-06.5 fast-path probe */" >> apps/client/src/index.css
   git commit -am "test(06.5): fast-path probe — operator UAT $(date -u +%FT%TZ)"
   git push
   # Open a PR + merge to main (or push directly to a deploy-eligible branch).
   ```
2. Watch the GitHub Actions run for the deploy workflow:
   - [ ] The fast-path job runs.
   - [ ] The full-image (Docker push) job is **SKIPPED** (path-filter
     decision).
   - [ ] Workflow run completes in **under 5 minutes** wall-clock
     (capture: `___ minutes`).
3. Verify the symlink swapped:
   ```bash
   flyctl ssh console -a rebno-staging -C "readlink /data/client-assets/current"
   ```
   Expected: `/data/client-assets/releases/<new-sha>` where `<new-sha>`
   matches the merge commit on `main`.
4. Verify GC ran (≤ 5 release dirs remain):
   ```bash
   flyctl ssh console -a rebno-staging -C "ls /data/client-assets/releases/ | wc -l"
   ```
   Expected: a number ≤ 5.
5. Three-check probe (from your laptop, NOT on the machine):
   ```bash
   URL=https://staging.rebno.decidel.com
   curl -fsS "${URL}/" >/dev/null && echo OK_root
   curl -fsS "${URL}/health" >/dev/null && echo OK_health
   HASHED=$(flyctl ssh console -a rebno-staging -C \
     "node -e 'console.log(require(\"/data/client-assets/current/.vite/manifest.json\")[\"index.html\"].file)'")
   curl -fsS "${URL}/${HASHED}" >/dev/null && echo OK_hashed
   ```
   Expected: three `OK_*` lines.
6. Hard-refresh the staging URL in Chrome (Ctrl+Shift+R or Cmd+Shift+R).
   The CSS tweak from step 1 must be visible (inspect the `<style>` or
   `<link>` for the comment).

- [x] **3-PASS** RE 2026-05-16T23:29:24Z fast-path 57s (run 25975772140, after workflow probe fix 0c0e055)

---

## 4. Rollback drill (REQ-DEP-04)

**Goal:** Walk `docs/deploy/ROLLBACK.md` end-to-end on a live machine and
prove the documented procedure completes in under 60 seconds wall-clock
between the `mv -T` invocation and a green 3-check probe.

1. Open `docs/deploy/ROLLBACK.md` in a separate window.
2. Follow the **Preflight** section to identify the previous-good SHA.
3. Start the stopwatch. Issue the **Atomic rollback** command.
4. Run the **Verify rollback** three probes. Stop the stopwatch when all
   three `OK_*` lines appear.
5. Capture the wall-clock duration: `___ seconds`. Target: under 60.
6. Roll forward to the original deploy by deploying a no-op client commit
   (a CSS comment toggle works), to leave the staging volume in a clean
   state for subsequent drills.

- [x] **4-PASS** RE 2026-05-16T23:31:00Z rollback wall-clock 0.835s (swap 0.468s + 3-check 0.367s)

---

## 5. Two-player CLI-08 fidelity check (REQ-CLI-08)

**Goal:** Operator proxy for the Playwright CLI-08 smoke that the fast
path **does NOT run** — manually confirm the milestone behavior survives
a fast-path deploy.

1. Open two Chrome windows side-by-side (or two browser profiles to
   isolate cookies).
2. In window A, log in as `UAT-A`; in window B, log in as `UAT-B`. Both
   join the staging room.
3. Each player walks around the room for ~10 seconds. Each player sends
   3 chat messages.
4. **Each player sees the other's** chat messages **and** movement.
5. **Outcome:** CLI-08 milestone behavior unchanged after the fast-path
   deploy.

- [x] **5-PASS** RE 2026-05-16T23:33:58Z (two-player CLI-08 fidelity confirmed against fast-path-deployed 4c24630 bundle)

---

## 6. Phase 06.4 carry-over regression check

**Goal:** Confirm the full-image deploy path still honors the
06.4 deploy-script knobs added in commit `c01038f` (`workflow_dispatch`
inputs `skip_verification` / `skip_phase_4_carryover` / `skip_smoke`,
commit-message escape hatches `[skip-staging-verify]`,
`[skip-phase-4-carryover]`, `[skip-staging-smoke]`).

1. Push a **server-touching** change (e.g., a comment-only tweak under
   `apps/server/src/`) with the commit message tagged `[skip-staging-smoke]`:
   ```bash
   git commit -am "chore(06.5-uat): full-path regression probe [skip-staging-smoke]"
   git push
   ```
2. In the GitHub Actions run, confirm:
   - [ ] The full-image Docker push job ran (server code changed).
   - [ ] The staging smoke step shows a skip notice referencing
     `[skip-staging-smoke]` in its output.
   - [ ] Other 06.4 carry-over inputs are still respected (no errors
     about unknown inputs in the workflow YAML).

- [x] **6-PASS** RE 2026-05-16T23:50Z
  - 5A (mixed-diff routing + skip-staging-smoke commit-msg flag): https://github.com/SaberMage/rebno/actions/runs/25976038704
  - 5C (workflow_dispatch + skip_verification + skip_smoke): https://github.com/SaberMage/rebno/actions/runs/25976148153
  - 5B's distinct dimension (server-only commit + [skip-staging-smoke]) consolidated under 5A (identical SKIP_STAGING_SMOKE env path).

---

## 7. Signoff

| Section | Result | Operator initials | Date |
|---------|--------|-------------------|------|
| 2 — Cold-start fallback (REQ-DEP-01) | ☑ green | RE | 2026-05-16 |
| 3 — Fast-path deploy (REQ-DEP-04)     | ☑ green (after gap closure 0c0e055) | RE | 2026-05-16 |
| 4 — Rollback drill (REQ-DEP-04)       | ☑ green | RE | 2026-05-16 |
| 5 — Two-player CLI-08 fidelity        | ☑ green | RE | 2026-05-16 |
| 6 — 06.4 regression check             | ☑ green | RE | 2026-05-16 |

**UAT signoff:** RE 2026-05-16 — phase passes. One gap (Plan 04 workflow probe under STAGING_MODE) closed inline via `fix(06.5-04): pass STAGING_INVITE_TOKEN Bearer on fast-path / probe` (commit `0c0e055`) and revalidated by run 25975772140 (Drill 3 retest).

---

## Operator notes (free-form)

> Use this section during the drill to capture timings, surprises, and
> any environmental quirks. These notes flow into Plan 05's SUMMARY.

```
2026-05-16 UAT (RE):

- Windows-host TTY: `flyctl ssh console -C "..."` errors with "The handle is invalid" on
  Windows under both bash and PowerShell. Worked around by using
  `flyctl machine exec <machine-id> -a rebno-staging "sh -c '<cmd>'"` for every
  non-interactive ssh call (Drill 1 wipe, Drill 3 atomic symlink swap, hashed-asset
  manifest read). Linux CI runners are unaffected.
- Drill 1 `/` probe: staging-invite gate (STAGING_MODE=1) returns 401 for `curl -fsS /`
  without a Bearer header. Used Authorization: Bearer <STAGING_INVITE_TOKEN> for the
  / probe. `/assets/*` and `/health` are middleware-exempt and need no header.
- Drill 2 surfaced a Plan 04 workflow defect: the "Post-swap 3-check probe" step
  in `.github/workflows/deploy-staging.yml` called `curl $URL/` without Bearer,
  so the step failed HTTP 401 even though the semantic deploy succeeded. Patched
  inline (commit 0c0e055) — added STAGING_INVITE_TOKEN secret to the step env and
  `-H "Authorization: Bearer ..."` on the / probe. Retest run 25975772140 green.
- Drill 4 was operator-driven (two browser windows). All other drills were
  agent-driven via flyctl + gh CLIs.
- 5B's distinct dimension (server-only commit w/ [skip-staging-smoke]) was
  consolidated under 5A — the SKIP_STAGING_SMOKE env propagation and the full-path
  routing branch are identical regardless of whether the commit is mixed or server-only.
- Follow-up TODO (operator-suggested): split Playwright smoke into a 3rd workflow
  job so deploy completion is observable without smoke-step coupling. Out of
  Phase 06.5 scope; defer to future workflow-polish phase.
```
