- rewrite drawStatusChart to a Canvas pie (no per-slice labels), center shows total requests
- status card: title + total caption + tall pie area (110px) + color legend row below (swatch + code + count), each item has title tooltip with ok/err
- store status swatch palette and reuse across pie/legend for color consistency
- deployed (bak .bak.20260811m), server active
Redo the KPI row properly: five identical cards each with title row, large metric value, subtitle, and an 86px canvas chart. Replaces the previous gray-box canvas placeholders (which dropped the numbers — a regression).
- Active requests: line sparkline (real-time refresh) + live count
- Total requests: 7-day vertical bar chart + current total
- Tokens: stacked bar of per-model token share + big total
- Avg latency: line sparkline (real-time refresh) + avg ms
- Status codes: stacked bar by code + chip subtitle (code/reqs/percent)
All charts drawn with plain Canvas 2D (sparkline/dailyBars helpers), no third-party lib. DPR-aware for crispness. Deployed (bak .bak.20260811l), server active.
- move status distribution out of the full-width standalone card into the top KPI row as a 5th small block (aligned with the four KPI boxes)
- swap stroke-dasharray circles for SVG path arcs inside a rotated <g>: keeps each slice crisp and prevents the thick stroke clipping against the viewBox edge
- compact 108px donut + wrap-able status chip legend (hover title shows code/reqs/percent)
- drop redundant dashStatus subtitle; simplify title
- deployed to /usr/local/bin/llmsproxy (bak .bak.20260811j), server active
- paintStatusTable: replace plain table with SVG ring (conic slices per status code, center total, clickable legend with title=value/reqs/percent/ok/err)
- paintModelTable: percentage now = model share of total requests (was relative-to-max, so the top model always showed 100%/97%); bar stays max-relative
- plan.md: record P4-9 (visualization) and P4-10 (claude 400 'extra usage' = Anthropic account quota, not fingerprint; qijiar+openai serves claude fine, no adapter disguise needed)
- deployed to /usr/local/bin/llmsproxy (bak .bak.20260811i), server active
- scheduler: BuildChain sorts tiers ascending so tier 1 (highest priority) is tried first; previously descending inverted the chain (P10-1..P10-5)
- stats/api: handleStatsAPI limit→20000; CSV reads full audit via new Stats.AuditRecords (includes *.old rotation); key_names mapped by keyID() masked key; non-admin filter and keys-csv use masked keys
- server: ring buffer NewStats(10000)
- ui: dash-row card scroll area moved to table container (fix overflow below card); key view toggle (re-click same key returns to global) + kpi-exit affordance; rec-exit span
- chat: chain-failure record now surfaces first failed tier; AUTO comment sync