---
name: perminder-klair-verify
description: "Drive a controller/admin-UI change end-to-end from a worktree without touching the live station — isolated controller on a spare port + temp STATE_DIR, worktree Next dev server, Playwright against /admin."
license: "MIT"
metadata:
  decimalai-skill-id: "df60b039-9d24-41bb-b48c-f1a551b8d53e"
  decimalai-version-id: "0901622e-8b45-4f71-8978-aa7158919947"
  decimalai-version: "1"
  decimalai-body-sha256: "e7840f2d20ea9f966b091a88b1ec0a05c2ddc9fff9571c3631f7a4fb8d116b0f"
  decimalai-name: "perminder-klair/verify"
  decimalai-format: "1"
  decimalai-invocation: "model"
  decimalai-category: "testing"
  decimalai-source: "https://app.decimal.ai/s/perminder-klair-verify@1/SKILL.md"
---
# Verifying controller + admin-UI changes in isolation

The operator's real station is usually running (docker `sub-wave-*` containers). Never restart or
point tests at it. Boot your own stack from the worktree instead:

## Isolated controller (API surface)

```bash
cd <worktree>/controller
STATE_DIR=$CLAUDE_JOB_DIR/tmp/state PORT=7791 ADMIN_USER=test ADMIN_PASS=test \
  NODE_ENV=development \
  NAVIDROME_URL=http://localhost:9999 NAVIDROME_USER=x NAVIDROME_PASS=x \
  npx tsx src/server.ts
```

- A fresh `STATE_DIR` boots clean (seeds sfx/jingles, writes `settings.json` on first save).
- The fake `NAVIDROME_*` env matters: without it `needsSetup` is true and the admin shell
  redirects every page to `/onboarding`, so UI tests never find their controls.
- Drive `/settings` etc. with `curl -u test:test http://localhost:7791/...`.
- To test load-time migrations: stop the server, hand-edit `settings.json`, restart, GET.
- Kill by port (`fuser -k 7791/tcp`) — a `pkill -f "tsx src/server.ts"` matches the Bash tool's
  own wrapper cmdline and kills your shell (exit 144).

## Worktree web dev server (UI surface)

```bash
cd <worktree>/web
NEXT_PUBLIC_API_URL=http://localhost:7791 npm run dev -- -p 7793
```

Then Playwright (headless chromium, sync API):

- Pre-seed auth before load: `ctx.add_init_script("localStorage.setItem('subwave_admin_auth', '<base64 user:pass>')")`.
- Assert state through the controller API after clicking Save, not through sonner toasts.
- Admin modals portal into `.admin-root`; scope input lookups with `[role="dialog"]`.
