feat(governance): surface verification coverage
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user