# Sprint 01 — Production Stability **Depends on:** S00 (critical security fixes) **Duration:** ~6h **Goal:** Restore dev deployment, add test gates, fix broken UI states and inaccurate system data. --- ## S01.1 — Fix dev deploy runner label - **Files:** `.gitea/workflows/deploy-dev.yml:15` - **Estimate:** 0.5h - **Done means:** `runs-on: nas` instead of `runs-on: ubuntu-latest`. CI deploy to dev succeeds. - **Verify by:** Push a trivial change to `dev` → workflow runs on `nas` runner → deploy succeeds → `curl http://nas:4001/api/health` returns 200 - **Risk:** None — this is the same runner used by `deploy.yml` and `deploy-claude-dev-dev.yml`. - [x] S01.1 — Fix dev deploy runner label ## S01.2 — Add test gate to dev deploy - **Files:** `.gitea/workflows/deploy-dev.yml` - **Estimate:** 2h - **Done means:** `deploy-dev.yml` has backend-tests and frontend-tests jobs that must pass before the deploy job runs (via `needs`). Same test pattern as `deploy.yml`. - **Verify by:** 1. Push code with failing test → tests fail → deploy job skipped 2. Push code with passing tests → tests pass → deploy proceeds 3. Workflow summary in Gitea UI shows test→deploy dependency clearly - **Risk:** Adds 2-3 minutes to dev deploy cycle. Acceptable trade-off for safety. - [x] S01.2 — Add test gate to dev deploy ## S01.3 — Add error handling to Docker.svelte - **Files:** `dashboard/frontend/src/routes/Docker.svelte:12-15` - **Estimate:** 1h - **Done means:** API errors in `load()` are caught. UI shows error state with message and retry button instead of blank page or crash. Same pattern applied to `action()` and `showLogs()`. - **Verify by:** 1. Stop docker-socket-proxy → navigate to Docker page → see error message "Docker API unavailable" + retry button 2. Start docker-socket-proxy → click retry → containers load 3. During normal operation → no regression (page works as before) - **Risk:** Low. Add `let error = $state("")` and an `{#if error}` block in the template. Keep existing `loading` state. - [x] S01.3 — Add error handling to Docker.svelte ## S01.4 — Fix cpu_percent always returning 0 - **Files:** `dashboard/backend/routers/system.py:53` - **Estimate:** 0.5h - **Done means:** First call to `/api/system/stats` returns accurate CPU percentage (non-zero under load). - **Verify by:** 1. Restart dashboard backend 2. Run `stress --cpu 1` on the NAS 3. Call `/api/system/stats` → `cpu_percent` > 0 4. Stop stress → next call shows lower value - **Risk:** `psutil.cpu_percent(interval=0.1)` blocks the request for 100ms. This is acceptable for a system stats endpoint. Alternative: call `cpu_percent()` once at startup (in lifespan) to prime the counter, then use `interval=0` in the endpoint. - [x] S01.4 — Fix cpu_percent always returning 0 ## S01.5 — Verify production docker-socket-proxy - **Files:** `dashboard/docker-compose.yml` - **Estimate:** 2h - **Done means:** Production docker-socket-proxy container is running and healthy. Docker API calls from dashboard succeed without timeouts. - **Verify by:** 1. `ssh nas "cd /volume1/docker/nas-dashboard && docker compose ps"` → docker-socket-proxy shows "Up" and "healthy" 2. Navigate to Docker page in production dashboard → containers load within 5 seconds 3. Monitor `/api/docker/containers` response time → < 2 seconds - **Risk:** If docker-socket-proxy needs to be created from scratch, ensure the compose file defines it correctly. - [ ] S01.5 — Verify production docker-socket-proxy --- ## Exit criteria - [ ] Push to `dev` → CI deploys successfully on `nas` runner - [ ] Failing test blocks dev deploy - [ ] Docker page shows error state when API unavailable (not blank/crash) - [ ] `/api/system/stats` reports non-zero CPU under load - [ ] Production Docker page loads containers within 5 seconds - [ ] All backend tests pass - [ ] All frontend tests pass