feat(governance): surface verification coverage
All checks were successful
Code Review / ai-code-review (push) Successful in 10s
CD Pipeline / tests (push) Successful in 1m9s
CD Pipeline / build-and-deploy (push) Successful in 3m49s
CD Pipeline / post-deploy-checks (push) Successful in 1m17s

This commit is contained in:
Your Name
2026-05-14 20:28:53 +08:00
parent bc1a11e373
commit 485c58d085
5 changed files with 447 additions and 6 deletions

View File

@@ -46,6 +46,7 @@ interface SloApiResponse {
adr100?: {
overall_status?: string
overall_compliance?: number | null
verification_coverage?: Adr100VerificationCoverage
metrics?: Array<{
name: SloMetric['name']
value: number | null
@@ -61,6 +62,30 @@ interface SloApiResponse {
computed_at?: string
}
interface Adr100VerificationCoverage {
status: 'ok' | 'warning' | 'violated' | 'skipped_low_volume' | 'no_data' | 'error'
reason?: string | null
window?: string
total_auto: number
successful_auto: number
verified_auto: number
verified_success: number
verified_non_success: number
unverified_auto: number
coverage_rate?: number | null
verification_success_rate?: number | null
last_auto_at?: string | null
last_verified_auto_at?: string | null
latest_auto_age_seconds?: number | null
last_verified_auto_age_seconds?: number | null
recent_unverified?: Array<{
id: string
incident_id: string
success: boolean
created_at?: string | null
}>
}
interface SummaryApiResponse {
data?: ViolationDataPoint[]
event_types?: string[]
@@ -79,6 +104,25 @@ function mapStatus(s: string): SloMetric['status'] {
return 'critical'
}
function coverageTone(status?: Adr100VerificationCoverage['status']): string {
if (status === 'ok') return '#22C55E'
if (status === 'warning') return '#F59E0B'
if (!status || status === 'skipped_low_volume' || status === 'no_data') return '#87867f'
return '#FF3300'
}
function coverageReasonKey(reason?: string | null): string {
if (reason === 'no_auto_repair_executions_24h') return reason
if (reason === 'verification_backlog_present') return reason
if (reason === 'non_success_verification_present') return reason
if (reason === 'postgresql_query_error') return reason
return 'none'
}
function formatPercent(value?: number | null): string {
return value == null ? '--' : `${(value * 100).toFixed(1)}%`
}
function buildMetrics(api: SloApiResponse): SloMetric[] {
const adr100Metrics = api.adr100?.metrics
if (adr100Metrics?.length) {
@@ -133,6 +177,68 @@ function buildMetrics(api: SloApiResponse): SloMetric[] {
})
}
function VerificationCoveragePanel({ coverage }: { coverage?: Adr100VerificationCoverage }) {
const t = useTranslations('governance.slo.coverage')
const color = coverageTone(coverage?.status)
const rows = [
{ label: t('totalAuto'), value: String(coverage?.total_auto ?? '--') },
{ label: t('verifiedAuto'), value: String(coverage?.verified_auto ?? '--') },
{ label: t('unverifiedAuto'), value: String(coverage?.unverified_auto ?? '--') },
{ label: t('coverageRate'), value: formatPercent(coverage?.coverage_rate) },
]
return (
<GlassCard variant="subtle" padding="md">
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
<div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12 }}>
<div style={{ minWidth: 0 }}>
<div style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
{t('title')}
</div>
<div style={{ marginTop: 4, fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45 }}>
{t('subtitle', { window: coverage?.window ?? '24h' })}
</div>
</div>
<div style={{
flexShrink: 0,
display: 'inline-flex',
alignItems: 'center',
minHeight: 26,
padding: '4px 8px',
borderRadius: 6,
border: `0.5px solid ${color}40`,
background: `${color}12`,
fontFamily: "'DM Mono', monospace",
fontSize: 10,
color,
}}>
{t(`state.${coverage?.status ?? 'no_data'}`)}
</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, minmax(120px, 1fr))', gap: 10 }} className="slo-coverage-grid">
{rows.map(row => (
<div key={row.label} style={{ minWidth: 0 }}>
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 9, color: '#87867f', marginBottom: 3 }}>
{row.label}
</div>
<div style={{ fontFamily: 'Syne, sans-serif', fontSize: 18, fontWeight: 700, color: '#141413', letterSpacing: 0 }}>
{row.value}
</div>
</div>
))}
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: '8px 14px', fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45 }}>
<span>{t('reasonLabel')} {t(`reason.${coverageReasonKey(coverage?.reason)}`)}</span>
<span>{t('successRate')} {formatPercent(coverage?.verification_success_rate)}</span>
<span>{t('lastVerified')} {coverage?.last_verified_auto_at ?? '--'}</span>
</div>
</div>
</GlassCard>
)
}
// =============================================================================
// Component
// =============================================================================
@@ -173,6 +279,7 @@ export function SloTab() {
const metrics = sloData ? buildMetrics(sloData) : []
const compliance = sloData?.adr100?.overall_compliance ?? sloData?.overall_compliance ?? null
const verificationCoverage = sloData?.adr100?.verification_coverage
const chartData: ViolationDataPoint[] = summaryData?.data ?? []
const eventTypes: string[] = summaryData?.event_types ?? []
@@ -235,6 +342,8 @@ export function SloTab() {
}
</div>
{!sloLoading && <VerificationCoveragePanel coverage={verificationCoverage} />}
{/* Violation timeline chart */}
<SloViolationChart
data={chartData}
@@ -248,6 +357,7 @@ export function SloTab() {
.slo-kpi-grid > * { flex: 1; min-width: 200px; }
@media (max-width: 640px) {
.slo-kpi-grid > * { flex: 0 0 100%; min-width: 0; }
.slo-coverage-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
}
`}</style>
</div>