← back to Wallco Ai
data/yolo-overnight/status-browser-perf-20260525-0405.md
73 lines
# status-browser perf probe — 2026-05-25 04:05 PT
## Target
- **Requested URL**: `http://127.0.0.1:9877/admin/status-browser?status=published&category=drunk-animals`
- **Actual URL probed**: `http://127.0.0.1:9905/admin/status-browser?status=published&category=drunk-animals`
- **Port drift**: 127.0.0.1:9877 is now held by `paint-visualizer-agent` (binds 127.0.0.1 after the Tailscale-conflict fix in commit `4fcbef909`). wallco-ai now listens on **0.0.0.0:9905** (see pm2 logs: `wallco.ai production server → http://0.0.0.0:9905`). Probed 9905 since that is where the route actually lives. **The task brief's port is stale and should be updated** in any cron / dashboard that pings it.
## Method
- Playwright Chromium headless, `--no-sandbox`, fresh context per run.
- 3 cold runs (each new browser/context — no warm cache).
- Metrics via `performance.getEntriesByType('navigation')[0]` + a selector race for `.card / [data-design-id] / img[src*="/design/"] / …`.
- Run 3 captured a Playwright trace (`/tmp/status-browser-trace.zip`).
## Headline numbers
| Metric | Run 1 | Run 2 | Run 3 | Threshold (3000 ms) |
|---|---|---|---|---|
| HTTP TTFB (navigation) | **8 ms** | **260 ms** | **5 ms** | ✅ under |
| DOMContentLoaded | **113 ms** | **331 ms** | **77 ms** | ✅ under |
| Time-to-first-card | **399 ms** | **1095 ms** | **898 ms** | ✅ under |
| Cards rendered | 200 | 200 | 200 | — |
| Selector that hit first | `.card` | `.card` | `.card` | — |
| Network requests | 5 | 8 | 20 | — |
**Verdict: no metric exceeds 3 s on any of the three runs. No profiling escalation required.**
The Run 2 spike (260 ms TTFB / 1.1 s first-card) is consistent with the second probe hitting the server while the prior run's connection pool / file cache was being warmed — Run 3 is back to normal even though it captures more image traffic.
## Observations worth flagging (not blockers)
1. **Query string is ignored.** The page is requested with `?status=published&category=drunk-animals`, but the front-end always fires `/api/status-browser?status=all&sort=newest&limit=200&offset=0` to populate the grid. The filter params on the URL never reach the API call.
- Effect: 200 cards always render regardless of filter; the user has to re-pick from the in-page controls. Worth a quick fix in `public/admin/status-browser.html` so deep links work.
2. **Five extra `/api/status-browser?status=X&limit=1` round-trips** fire on every load — one each for `all`, `published`, `unpublished`, `removed`, `etsy`. They appear to populate tab counters. Each is a real Postgres `COUNT(*)` (per server.js:8364) and they account for the bulk of network time:
- status=all: 670–700 ms
- status=removed: 467–499 ms
- status=etsy: 365–387 ms
- status=unpublished: 261–275 ms
- status=published: 157–165 ms
- Plus the actual list query: 372–703 ms
- **Recommendation**: collapse into one `/api/status-browser/counts` endpoint that returns all five tab counts in a single query (`SELECT count(*) FILTER (WHERE …) AS published, …`). That would cut ~1.5 s of compounded TTFB on the API fan-out and make page load roughly twice as fast even though we're currently under budget.
3. **Image waterfall is fine.** First-card was measured against DOM attach, but image bodies (`/designs/img/by-id/<n>`) come in at 40–380 ms each and don't block the card render. No image bigger than ~400 ms.
4. **Server-side query cost is the dominant cost** — the document itself ships in 6–11 ms (cached HTML). All time is in the API fan-out, not the static asset, not Playwright.
## Slowest network sections (Run 3, the trace-captured run)
| # | URL | Type | Dur | TTFB |
|---|---|---|---|---|
| 1 | `/api/status-browser?status=all&sort=newest&limit=200&offset=0` | fetch | 677 ms | 623 ms |
| 2 | `/api/status-browser?status=all&limit=1` | fetch | 675 ms | 672 ms |
| 3 | `/api/status-browser?status=removed&limit=1` | fetch | 467 ms | 464 ms |
| 4 | `/designs/img/by-id/39138` | image | 382 ms | 172 ms |
| 5 | `/designs/img/by-id/39280` | image | 379 ms | 310 ms |
| … | (rest: images 40–380 ms, two more count queries 261/365 ms) | | | |
`/api/status-browser` server-side latency dominates — server.js:8345 issues two psql shell-outs (`countRaw` + `raw`), and the page repeats it 6× per load. That's the fix surface if/when this falls under budget.
## Artifacts
- Trace: `/tmp/status-browser-trace.zip` (open with `playwright show-trace`)
- Raw results: `/tmp/status-browser-results.json`
- Probe script: `/tmp/status-browser-perf.js`
## Next actions (optional, none blocking)
- [ ] Fix front-end so `?status=` and `?category=` query params actually drive the API call.
- [ ] Replace 5× count queries with one batched `counts` endpoint.
- [ ] Update any cron / monitor / link that still points at port 9877 for `/admin/status-browser` — that port is now `paint-visualizer-agent`, not wallco-ai.