feat: add production assurance dashboard flow

This commit is contained in:
thanhnv
2026-07-28 21:49:15 +07:00
parent ee5d1f7af5
commit cce3cbfd42
39 changed files with 1873 additions and 91 deletions
@@ -100,14 +100,14 @@ function H6Summary({ node, goal, runReport, projectReport, loading, error }: {
return <div className="mt-4 rounded-xl border border-amber-300/30 bg-amber-300/10 p-3 text-xs leading-5 text-amber-100">Run telemetry could not be loaded here. <Link to={reportLink} className="font-semibold underline decoration-amber-300/50 underline-offset-4 hover:text-white focus:outline-none focus:ring-2 focus:ring-cyan-300">Open the full H6 report</Link> to inspect the source status.</div>;
}
const tokenTotal = runReport.summary.tokens.provider_total || runReport.summary.tokens.total;
const tokenTotal = runReport.summary.tokens.provider_total ?? runReport.summary.tokens.total;
const actualCost = runReport.summary.cost_usd.provider_actual;
const displayedCost = actualCost || runReport.summary.cost_usd.estimated;
const displayedCost = actualCost ?? runReport.summary.cost_usd.estimated;
const provider = runReport.details.by_provider.slice(0, 2).map((row) => row.key).join(', ') || 'Not attributed';
const metrics = [
['Max runtime', formatDuration(runReport.summary.latency_ms.max)],
['Tokens', tokenTotal.toLocaleString()],
[actualCost ? 'Actual cost' : 'Estimated cost', formatCost(displayedCost)],
['Tokens', tokenTotal === null ? 'Unavailable' : tokenTotal.toLocaleString()],
[actualCost !== null ? 'Actual cost' : displayedCost !== null ? 'Estimated cost' : 'Cost', displayedCost === null ? 'Unavailable' : formatCost(displayedCost)],
['Retries', runReport.summary.retries.toLocaleString()],
['Provider calls', runReport.summary.provider_calls.toLocaleString()],
['Freshness', runReport.freshness.status],
@@ -21,6 +21,7 @@ const PAGE_COPY: Record<string, { title: string; eyebrow: string }> = {
export function Header() {
const { data } = useQuery({ queryKey: ['health'], queryFn: health });
const { data: session } = useQuery({ queryKey: ['session'], queryFn: api.session, staleTime: 60_000 });
const { data: project } = useQuery({ queryKey: ['project-profile'], queryFn: api.project, staleTime: 60_000 });
const { pathname } = useLocation();
const stale = data ? !data.ok : true;
const page = PAGE_COPY[pathname] ?? PAGE_COPY['/'];
@@ -32,6 +33,10 @@ export function Header() {
<h1 className="mt-0.5 text-lg font-semibold tracking-tight text-slate-900">{page.title}</h1>
</div>
<div className="flex items-center gap-2.5 text-xs">
<div className="hidden rounded-xl border border-slate-200 bg-white px-3 py-1.5 md:block">
<div className="max-w-48 truncate font-semibold text-slate-800">{project?.project_id ?? 'Discovering project…'}</div>
<div className="text-[10px] font-bold uppercase tracking-wide text-slate-400">{project?.edition ?? 'unknown'} edition · maturity {project?.maturity.level ? `L${project.maturity.level}` : 'not assessed'}</div>
</div>
<div className="hidden rounded-xl border border-slate-200 bg-slate-50 px-3 py-2 text-slate-500 sm:block">
<span className="font-medium text-slate-700">{data?.runs ?? '—'}</span> governed runs
</div>
@@ -0,0 +1,42 @@
import type { HarnessGateStatus, HarnessTraceGraph } from '../../lib/api';
const TONE: Record<HarnessGateStatus, string> = {
queued: 'border-slate-200 bg-slate-100 text-slate-400',
running: 'border-blue-300 bg-blue-50 text-blue-700',
pass: 'border-emerald-300 bg-emerald-50 text-emerald-700',
warning: 'border-amber-300 bg-amber-50 text-amber-700',
blocked: 'border-rose-300 bg-rose-50 text-rose-700',
error: 'border-rose-300 bg-rose-50 text-rose-700',
skipped: 'border-slate-200 bg-slate-100 text-slate-400',
};
const MARK: Record<HarnessGateStatus, string> = {
queued: '○',
running: '●',
pass: '✓',
warning: '!',
blocked: '×',
error: '×',
skipped: '–',
};
export function AssuranceRail({ graph }: { graph: HarnessTraceGraph }) {
return (
<div className="overflow-x-auto pb-1">
<div className="flex min-w-[760px] items-center">
{graph.nodes.map((node, index) => (
<div key={node.id} className="flex min-w-0 flex-1 items-center">
<div className={`min-w-0 flex-1 rounded-xl border p-3 ${TONE[node.status]}`}>
<div className="flex items-center justify-between gap-2">
<span className="text-[10px] font-black uppercase tracking-[0.12em]">{node.title.split(' · ')[0]}</span>
<span className={`flex h-5 w-5 items-center justify-center rounded-full border border-current text-[10px] ${node.status === 'running' ? 'animate-pulse' : ''}`}>{MARK[node.status]}</span>
</div>
<div className="mt-2 truncate text-xs font-semibold">{node.title.split(' · ')[1]}</div>
</div>
{index < graph.nodes.length - 1 && <div className={`h-px w-3 shrink-0 ${node.status === 'pass' ? 'bg-emerald-300' : 'bg-slate-200'}`} />}
</div>
))}
</div>
</div>
);
}
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { api, type HarnessGateNode, type HarnessGateStatus, type HarnessTraceGraph } from '../../lib/api';
import { api, runReportExportUrl, type HarnessGateNode, type HarnessGateStatus, type HarnessTraceGraph } from '../../lib/api';
import { Card, StatusBadge } from '../ui/Card';
const NODE_TONE: Record<HarnessGateStatus, string> = {
@@ -82,7 +82,11 @@ export function TraceExplorer({ traceId, onClose }: { traceId: string; onClose?:
return (
<Card
title="Harness trace explorer"
right={onClose && <button type="button" onClick={onClose} className="rounded-lg border border-slate-200 px-3 py-1.5 text-xs font-medium text-slate-600 transition-colors hover:bg-slate-50">Close</button>}
right={<div className="flex items-center gap-2">
<a href={`/reports/h6?run=${encodeURIComponent(traceId)}`} className="rounded-lg border border-indigo-200 bg-indigo-50 px-3 py-1.5 text-xs font-semibold text-indigo-700 transition hover:bg-indigo-100">Open H6</a>
<a href={runReportExportUrl(traceId, 'html')} className="rounded-lg bg-slate-900 px-3 py-1.5 text-xs font-semibold text-white transition hover:bg-slate-700">Export evidence</a>
{onClose && <button type="button" onClick={onClose} className="rounded-lg border border-slate-200 px-3 py-1.5 text-xs font-medium text-slate-600 transition-colors hover:bg-slate-50">Close</button>}
</div>}
className="overflow-hidden"
>
<div className="mb-5 flex flex-wrap items-end justify-between gap-3">
@@ -59,8 +59,8 @@ export interface H6Breakdown {
runs: number;
failures: number;
latency_avg_ms: number;
tokens: number;
cost_usd: number;
tokens: number | null;
cost_usd: number | null;
}
export interface H6Report {
@@ -87,10 +87,18 @@ export interface H6Report {
failure_rate_pct: number;
retries: number;
latency_ms: { average: number; p50: number; p95: number; p99: number; max: number };
tokens: { input: number; output: number; total: number; provider_total: number };
cost_usd: { provider_actual: number; estimated: number };
tokens: { input: number | null; output: number | null; total: number | null; provider_total: number | null };
cost_usd: { provider_actual: number | null; estimated: number | null };
provider_calls: number;
alerts: number;
coverage: {
runtime_records: number;
token_records: number;
cost_records: number;
token_pct: number;
cost_pct: number;
quality: { complete: number; partial: number; insufficient: number; unknown: number };
};
};
thresholds: Record<string, number | string | boolean>;
findings: H6ReportFinding[];
@@ -141,11 +149,22 @@ export interface EvidencePackDetail extends EvidencePackSummary {
export interface Overview extends Freshness {
totals: {
runs: number; total_cost: number; avg_latency_ms: number; failures: number;
token_coverage_pct: number; cost_coverage_pct: number;
hallucination_signals: number; provider_tokens: number; provider_cost: number;
fallback_routes: number; tool_denies: number; action_blocks: number;
};
harness_signals: Record<string, Record<string, number | string>>;
audit_chain: { records: number; head: string | null; last_decision: string | null };
latest_assurance: {
trace_id: string;
certified: boolean;
certification_strength: string | null;
telemetry_quality: string;
duration_ms: number | null;
tool_calls: number;
failures: number;
graph: HarnessTraceGraph;
} | null;
}
export interface SettingsActor {
@@ -581,8 +600,25 @@ export function h6ReportExportUrl(query: H6ReportQuery, format: 'json' | 'html')
return `${base}/reports/h6/export?${params.toString()}`;
}
export function runReportExportUrl(traceId: string, format: 'json' | 'html'): string {
const base = import.meta.env.VITE_API_BASE_URL ?? '/api/v1';
return `${base}/reports/run/${encodeURIComponent(traceId)}/export?format=${format}`;
}
export interface ProjectProfile {
project_id: string;
app_root: string;
edition: string;
edition_status: string;
maturity: { level: number | null; status: string; evidence: string | null };
enforcement_mode: string;
integration_mode: string;
clients: string[];
}
export const api = {
session: () => get<SettingsActor>('session'),
project: () => get<ProjectProfile>('project'),
overview: () => get<Overview>('overview'),
runs: (limit = 50) => get<Freshness & { count: number; runs: HarnessRunRecord[] }>(`runs?limit=${limit}`),
traceGraph: (traceId: string) => get<HarnessTraceGraph>(`runs/${encodeURIComponent(traceId)}/graph`),
@@ -31,7 +31,7 @@ function MetricCard({ label, value, sub, accent = false }: { label: string; valu
return <div className={`relative overflow-hidden rounded-2xl border p-4 ${accent ? 'border-indigo-200 bg-indigo-50/70' : 'border-slate-200 bg-white'}`}>
{accent && <span className="absolute -right-5 -top-5 h-16 w-16 rounded-full bg-indigo-200/50 blur-xl" />}
<div className="relative text-[10px] font-bold uppercase tracking-[0.12em] text-slate-500">{label}</div>
<div className="relative mt-2 text-2xl font-semibold tracking-tight text-slate-900">{value}</div>
<div className={`relative mt-2 font-semibold tracking-tight text-slate-900 ${value.length > 9 ? 'text-base' : 'text-2xl'}`}>{value}</div>
{sub && <div className="relative mt-1 text-xs text-slate-500">{sub}</div>}
</div>;
}
@@ -42,7 +42,7 @@ function BreakdownTable({ rows, subject }: { rows: H6Breakdown[]; subject: strin
<th className="py-2.5 pr-3">{subject}</th><th>runs</th><th>failures</th><th>avg latency</th><th>tokens</th><th>cost</th>
</tr></thead>
<tbody>{rows.map((row) => <tr key={row.key} className="border-b border-slate-100 transition-colors hover:bg-slate-50/80">
<td className="max-w-[300px] py-3 pr-3 font-medium text-slate-800">{row.key}</td><td>{integer(row.runs)}</td><td>{integer(row.failures)}</td><td>{integer(row.latency_avg_ms)} ms</td><td>{integer(row.tokens)}</td><td>{money(row.cost_usd)}</td>
<td className="max-w-[300px] py-3 pr-3 font-medium text-slate-800">{row.key}</td><td>{integer(row.runs)}</td><td>{integer(row.failures)}</td><td>{integer(row.latency_avg_ms)} ms</td><td>{row.tokens === null ? 'Unavailable' : integer(row.tokens)}</td><td>{row.cost_usd === null ? 'Unavailable' : money(row.cost_usd)}</td>
</tr>)}{rows.length === 0 && <tr><td colSpan={6} className="py-8 text-center text-slate-500">No matching {subject.toLowerCase()} records.</td></tr>}</tbody>
</table></div>;
}
@@ -108,9 +108,22 @@ export function H6ReportPage() {
<MetricCard label="Failures" value={integer(report.data.summary.failed)} sub={`${report.data.summary.failure_rate_pct}% rate`} />
<MetricCard label="Degraded" value={integer(report.data.summary.degraded)} />
<MetricCard label="P95 latency" value={`${integer(report.data.summary.latency_ms.p95)}ms`} sub={`P50 ${integer(report.data.summary.latency_ms.p50)}ms`} />
<MetricCard label="Provider tokens" value={integer(report.data.summary.tokens.provider_total)} sub={`${report.data.summary.provider_calls} calls`} accent />
<MetricCard label="Actual cost" value={money(report.data.summary.cost_usd.provider_actual)} sub="provider reported" />
<MetricCard label="Estimated cost" value={money(report.data.summary.cost_usd.estimated)} sub="runtime fallback" />
<MetricCard
label="Provider tokens"
value={report.data.summary.coverage.token_records > 0 ? integer(report.data.summary.tokens.provider_total ?? report.data.summary.tokens.total ?? 0) : 'Unavailable'}
sub={`${report.data.summary.coverage.token_pct}% run coverage`}
accent
/>
<MetricCard
label="Actual cost"
value={report.data.summary.cost_usd.provider_actual !== null ? money(report.data.summary.cost_usd.provider_actual) : 'Unavailable'}
sub={`${report.data.summary.provider_calls} provider calls`}
/>
<MetricCard
label="Cost coverage"
value={`${report.data.summary.coverage.cost_pct}%`}
sub={`${report.data.summary.coverage.cost_records}/${report.data.summary.coverage.runtime_records} runs`}
/>
<MetricCard label="Alerts" value={integer(report.data.summary.alerts)} sub={`${report.data.summary.retries} retries`} />
</section>
@@ -127,6 +140,10 @@ export function H6ReportPage() {
<div className="grid gap-5 xl:grid-cols-[0.8fr_1.2fr]">
<Card title={`Data quality · ${report.data.data_quality.status}`}>
<div className="mb-4 grid grid-cols-2 gap-3">
<div className="rounded-xl border border-slate-200 bg-slate-50 p-3"><div className="text-[10px] font-bold uppercase tracking-wider text-slate-400">Token coverage</div><div className="mt-1 text-xl font-semibold text-slate-900">{report.data.summary.coverage.token_pct}%</div></div>
<div className="rounded-xl border border-slate-200 bg-slate-50 p-3"><div className="text-[10px] font-bold uppercase tracking-wider text-slate-400">Cost coverage</div><div className="mt-1 text-xl font-semibold text-slate-900">{report.data.summary.coverage.cost_pct}%</div></div>
</div>
{report.data.data_quality.warnings.length > 0 ? <ul className="space-y-2 text-sm leading-5 text-slate-600">{report.data.data_quality.warnings.map((warning) => <li key={warning} className="flex gap-2"><span className="mt-1 h-2 w-2 shrink-0 rounded-full bg-amber-400" />{warning}</li>)}</ul> : <div className="text-sm text-emerald-700">All required sources are present and no estimation warning was detected.</div>}
</Card>
<Card title="Independent export" right={<span className="text-xs font-normal normal-case tracking-normal text-slate-400">Generated on demand · no hard-coded score</span>}>
@@ -1,6 +1,8 @@
import { useQuery } from '@tanstack/react-query';
import { api } from '../lib/api';
import { Card, StatTile, StatusBadge } from '../components/ui/Card';
import { AssuranceRail } from '../components/trace/AssuranceRail';
import { Link } from 'react-router-dom';
function SignalMark({ tone }: { tone: 'indigo' | 'emerald' | 'amber' }) {
const color = { indigo: 'bg-indigo-500', emerald: 'bg-emerald-500', amber: 'bg-amber-500' }[tone];
@@ -39,10 +41,41 @@ export function Overview() {
</div>
</section>
{data.latest_assurance && (
<section className="rounded-2xl border border-slate-200 bg-white p-5 shadow-[0_15px_35px_rgba(15,23,42,0.05)] sm:p-6">
<div className="mb-4 flex flex-col justify-between gap-3 sm:flex-row sm:items-end">
<div>
<div className="text-[10px] font-black uppercase tracking-[0.18em] text-indigo-600">Latest assurance receipt</div>
<div className="mt-1 flex flex-wrap items-center gap-2">
<h3 className="text-lg font-semibold text-slate-900">{data.latest_assurance.certified ? 'Certified governed run' : 'Run requires review'}</h3>
<StatusBadge value={data.latest_assurance.certified ? 'certified' : 'attention'} />
<StatusBadge value={`H6 ${data.latest_assurance.telemetry_quality}`} />
</div>
<p className="mt-1 max-w-2xl truncate font-mono text-[11px] text-slate-400">{data.latest_assurance.trace_id}</p>
</div>
<div className="flex flex-wrap gap-2">
<Link to={`/reports/h6?run=${encodeURIComponent(data.latest_assurance.trace_id)}`} className="rounded-xl border border-indigo-200 bg-indigo-50 px-3 py-2 text-xs font-semibold text-indigo-700 transition hover:bg-indigo-100">Inspect H6</Link>
<Link to={`/runs?trace=${encodeURIComponent(data.latest_assurance.trace_id)}`} className="rounded-xl bg-slate-900 px-3 py-2 text-xs font-semibold text-white transition hover:bg-slate-700">Open live trace</Link>
</div>
</div>
<AssuranceRail graph={data.latest_assurance.graph} />
<div className="mt-4 flex flex-wrap gap-x-5 gap-y-2 border-t border-slate-100 pt-4 text-xs text-slate-500">
<span><strong className="text-slate-800">{data.latest_assurance.graph.progress}/7</strong> gates observed</span>
<span><strong className="text-slate-800">{data.latest_assurance.tool_calls}</strong> tools</span>
<span><strong className="text-slate-800">{data.latest_assurance.failures}</strong> failures</span>
<span><strong className="text-slate-800">{data.latest_assurance.duration_ms == null ? '—' : `${Math.round(data.latest_assurance.duration_ms / 1000)}s`}</strong> duration</span>
</div>
</section>
)}
<div className="grid grid-cols-2 gap-3 md:grid-cols-4 xl:grid-cols-8">
<StatTile label="Runs" value={totals.runs} />
<StatTile label="Failures" value={totals.failures} />
<StatTile label="Model cost" value={`$${totals.total_cost.toFixed(4)}`} sub={`${totals.provider_tokens.toLocaleString()} tokens`} />
<StatTile
label="Model cost"
value={totals.cost_coverage_pct > 0 ? `$${totals.total_cost.toFixed(4)}` : 'Unavailable'}
sub={`${totals.cost_coverage_pct}% cost coverage`}
/>
<StatTile label="Latency" value={`${totals.avg_latency_ms}ms`} sub="average" />
<StatTile label="Fallbacks" value={totals.fallback_routes} />
<StatTile label="Tool denies" value={totals.tool_denies} />
@@ -30,7 +30,7 @@ export function Runs() {
<td><StatusBadge value={run.status ?? '—'} /></td>
<td>{run.latency_ms ?? '—'} ms</td>
<td>{run.total_tokens ?? '—'}</td>
<td>${Number(run.cost_estimate ?? 0).toFixed(5)}</td>
<td>{run.cost_estimate == null ? <span className="font-medium text-amber-600">Unavailable</span> : `$${Number(run.cost_estimate).toFixed(5)}`}</td>
<td className="py-2 text-right">
{run.trace_id ? (
<button