mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-31 04:07:52 +00:00
Adds the v0.36.0.0 admin SPA Calibration tab. Per the design review,
the approved variant-B (Linear calm clarity) layout: single-column flow,
generous whitespace, ONE big sparkline as hero, then patterns, then
domain bars, then abandoned threads.
D23 server-rendered SVG architecture:
src/core/calibration/svg-renderer.ts — pure functions. data → SVG
string. No DOM, no React, no chart library dep. Inlines the admin
design tokens (#0a0a0f bg, #3b82f6 accent, etc.) so the SVG is
visually consistent with the rest of the admin SPA.
Four chart renderers:
- renderBrierTrend({ series }) — sparkline w/ baseline reference
at 0.25 (always-50% baseline)
- renderDomainBars({ bars }) — horizontal accuracy bars per domain
- renderAbandonedThreadsCard(threads) — D30/TD4 'revisit now' link
per row, points at /admin/calibration/revisit/<takeId>
- renderPatternStatementsCard(statements) — D29/TD3 clickable
drill-down links per row, point at /admin/calibration/pattern/<i>
XSS posture: all caller-controlled strings pass through escapeXml().
Numeric inputs are .toFixed()-coerced. Admin SPA renders via
dangerouslySetInnerHTML inside a TrustedSVG wrapper component;
endpoint is gated by requireAdmin middleware.
/admin/api/calibration/profile — returns the active profile row as JSON.
/admin/api/calibration/charts/:type — returns image/svg+xml markup
for type ∈ {brier-trend, domain-bars, pattern-statements,
abandoned-threads}. Cache-Control: private, max-age=60.
brier-trend currently renders a single-point series from the active
profile (the time-series view across calibration_profiles.generated_at
history is a v0.37 follow-up once we have multiple snapshots).
abandoned-threads pulls the top 5 abandoned rows via the same SQL the
doctor check uses.
CalibrationPage React component (admin/src/pages/Calibration.tsx):
Fetches profile + 4 charts. Loading / error / cold-brain states all
handled. Layout includes the audit annotations (partial-grade badge,
voice-gate-fell-back-to-template badge) per the approved mockup.
TrustedSVG wrapper isolates the dangerouslySetInnerHTML to the SVG
surface only.
App.tsx nav: added 'calibration' page route + sidebar nav item, hash
routing extended to support #calibration.
TD2 contrast bump:
admin/src/index.css --text-muted: #555 → #777. Old value was contrast
4.0 on the #0a0a0f bg — below WCAG AA 4.5 for body text. New value is
~5.5, passes AA. Improvement is global across Dashboard, Agents,
RequestLog, and the new Calibration tab — single-line CSS change with
~10x the impact.
admin/dist/ rebuilt via `bun run build` (vite). 36 modules transformed.
Tests: 19 cases in test/svg-renderer.test.ts.
escapeXml (1): canonical entities.
renderBrierTrend (6): empty state, polyline for 2+ points, clamp
beyond yMax, design tokens inlined, XSS safety on date strings,
text-anchor end on right label.
renderDomainBars (4): empty state, label/accuracy/n rendering,
out-of-range accuracy clamp, XSS safety on labels.
renderAbandonedThreadsCard (4): empty state, row rendering with
revisit link, claim truncation at 70 chars, custom revisitHref override.
renderPatternStatementsCard (4): empty state, anchor count matches
statement count, XSS safety, custom drillHref override.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
17 lines
673 B
HTML
17 lines
673 B
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>GBrain Admin</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
|
<script type="module" crossorigin src="/admin/assets/index-CWq369vO.js"></script>
|
|
<link rel="stylesheet" crossorigin href="/admin/assets/index-GxkWX7v3.css">
|
|
</head>
|
|
<body>
|
|
<div id="root"></div>
|
|
</body>
|
|
</html>
|