feat(governance): 新增監控合約降噪矩陣
All checks were successful
CD Pipeline / tests (push) Successful in 1m29s
Code Review / ai-code-review (push) Successful in 16s
CD Pipeline / build-and-deploy (push) Successful in 4m45s
CD Pipeline / post-deploy-checks (push) Successful in 1m31s

This commit is contained in:
Your Name
2026-06-05 12:44:47 +08:00
parent 0980ae3e49
commit 4944d77093
17 changed files with 1733 additions and 64 deletions

View File

@@ -39,6 +39,7 @@ import {
type BackupDrTargetInventorySnapshot,
type BackupNotificationPolicySnapshot,
type GiteaWorkflowRunnerHealthSnapshot,
type ObservabilityContractMatrixSnapshot,
type OffsiteEscrowReadinessStatusSnapshot,
type RuntimeSurfaceInventorySnapshot,
} from '@/lib/api-client'
@@ -303,6 +304,7 @@ export function AutomationInventoryTab() {
const [offsiteEscrow, setOffsiteEscrow] = useState<OffsiteEscrowReadinessStatusSnapshot | null>(null)
const [runtimeSurface, setRuntimeSurface] = useState<RuntimeSurfaceInventorySnapshot | null>(null)
const [giteaHealth, setGiteaHealth] = useState<GiteaWorkflowRunnerHealthSnapshot | null>(null)
const [observabilityMatrix, setObservabilityMatrix] = useState<ObservabilityContractMatrixSnapshot | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(false)
@@ -317,6 +319,7 @@ export function AutomationInventoryTab() {
apiClient.getOffsiteEscrowReadinessStatus(),
apiClient.getRuntimeSurfaceInventory(),
apiClient.getGiteaWorkflowRunnerHealth(),
apiClient.getObservabilityContractMatrix(),
] as const
Promise.allSettled(requests)
@@ -330,6 +333,7 @@ export function AutomationInventoryTab() {
offsiteEscrowResult,
runtimeSurfaceResult,
giteaHealthResult,
observabilityMatrixResult,
] = results
setSnapshot(inventoryResult.status === 'fulfilled' ? inventoryResult.value : null)
@@ -340,6 +344,7 @@ export function AutomationInventoryTab() {
setOffsiteEscrow(offsiteEscrowResult.status === 'fulfilled' ? offsiteEscrowResult.value : null)
setRuntimeSurface(runtimeSurfaceResult.status === 'fulfilled' ? runtimeSurfaceResult.value : null)
setGiteaHealth(giteaHealthResult.status === 'fulfilled' ? giteaHealthResult.value : null)
setObservabilityMatrix(observabilityMatrixResult.status === 'fulfilled' ? observabilityMatrixResult.value : null)
setError([
inventoryResult,
backlogResult,
@@ -348,6 +353,7 @@ export function AutomationInventoryTab() {
policyResult,
offsiteEscrowResult,
giteaHealthResult,
observabilityMatrixResult,
].some(result => result.status === 'rejected'))
})
.catch(() => setError(true))
@@ -461,6 +467,28 @@ export function AutomationInventoryTab() {
})
}, [giteaHealth])
const visibleObservabilitySurfaces = useMemo(() => {
if (!observabilityMatrix) return []
const priority = { action_required: 0, blocked: 1, verified: 2 } as Record<string, number>
return [...observabilityMatrix.observability_surfaces].sort((a, b) => {
const left = priority[a.status] ?? 3
const right = priority[b.status] ?? 3
if (left !== right) return left - right
return a.surface_id.localeCompare(b.surface_id)
})
}, [observabilityMatrix])
const visibleNoiseOpportunities = useMemo(() => {
if (!observabilityMatrix) return []
const priority = { approval_required: 0, ready_for_proposal: 1, preserved: 2, deferred: 3 } as Record<string, number>
return [...observabilityMatrix.noise_reduction_opportunities].sort((a, b) => {
const left = priority[a.status] ?? 3
const right = priority[b.status] ?? 3
if (left !== right) return left - right
return a.opportunity_id.localeCompare(b.opportunity_id)
})
}, [observabilityMatrix])
if (loading) {
return (
<div style={{ padding: 20, display: 'grid', gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 12 }} className="automation-inventory-kpi-grid">
@@ -474,7 +502,7 @@ export function AutomationInventoryTab() {
)
}
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth) {
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix) {
return (
<div style={{ padding: 20 }}>
<GlassCard variant="subtle" padding="lg">
@@ -527,6 +555,10 @@ export function AutomationInventoryTab() {
const runtimeBoundComponents = runtimeSurface?.rollups.source_components_with_runtime_binding ?? 0
const giteaRunnerActions = giteaHealth.rollups.workflow_ids_requiring_runner_attestation.length
const giteaQuietPolicies = giteaHealth.rollups.notification_contracts_quiet_success_count
const observabilityActions = observabilityMatrix.rollups.surface_ids_requiring_action.length
const observabilityProposalCount = observabilityMatrix.rollups.noise_reduction_opportunities_total
const observabilityClassificationGaps = observabilityMatrix.rollups.classification_gap_ids.length
const observabilityApprovalRequired = observabilityMatrix.rollups.approval_required_opportunity_ids.length
const backlogProgressPercent = backlog.progress_summary.overall_percent
const explicitApprovalItemCount = backlog.item_approval_boundary_rollup.items_requiring_explicit_approval.length
const taskBoundaryCount = snapshot.task_approval_boundary_rollup.total_tasks
@@ -643,6 +675,14 @@ export function AutomationInventoryTab() {
}
}
const observabilityValueLabel = (value: string) => {
try {
return t(`observability.values.${value}` as never)
} catch {
return value
}
}
return (
<div className="automation-inventory-tab-root" style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 16, minWidth: 0 }}>
<GlassCard variant="subtle" padding="md">
@@ -1450,6 +1490,169 @@ export function AutomationInventoryTab() {
</div>
</GlassCard>
<GlassCard variant="subtle" padding="md">
<div style={{ display: 'flex', flexDirection: 'column', gap: 13, minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 }}>
<BellRing size={14} style={{ color: '#d97757' }} />
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
{t('observability.title')}
</span>
</div>
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f' }}>
{t('observability.source', {
generated: formatDateTime(observabilityMatrix.generated_at),
current: observabilityMatrix.program_status.current_task_id,
next: observabilityMatrix.program_status.next_task_id,
})}
</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, minmax(0, 1fr))', gap: 12 }} className="automation-inventory-observability-kpi-grid">
<MetricCard label={t('observability.metrics.surfaces')} value={observabilityMatrix.rollups.total_surfaces} icon={<Database size={16} />} />
<MetricCard label={t('observability.metrics.actions')} value={observabilityActions} tone={observabilityActions > 0 ? 'warn' : 'ok'} icon={<AlertTriangle size={16} />} />
<MetricCard label={t('observability.metrics.proposals')} value={observabilityProposalCount} tone="warn" icon={<BellOff size={16} />} />
<MetricCard label={t('observability.metrics.classificationGaps')} value={observabilityClassificationGaps} tone="warn" icon={<Target size={16} />} />
<MetricCard label={t('observability.metrics.approvalRequired')} value={observabilityApprovalRequired} tone={observabilityApprovalRequired > 0 ? 'warn' : 'ok'} icon={<ShieldCheck size={16} />} />
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 10 }} className="automation-inventory-observability-map-grid">
<SummaryTile
label={t('observability.map.coverage')}
value={`${observabilityMatrix.rollups.total_surfaces}`}
detail={t('observability.map.coverageDetail')}
tone="ok"
icon={<Layers3 size={16} />}
/>
<SummaryTile
label={t('observability.map.noise')}
value={`${observabilityProposalCount}`}
detail={t('observability.map.noiseDetail')}
tone="warn"
icon={<BellOff size={16} />}
/>
<SummaryTile
label={t('observability.map.classification')}
value={`${observabilityApprovalRequired}`}
detail={t('observability.map.classificationDetail')}
tone="warn"
icon={<Target size={16} />}
/>
<SummaryTile
label={t('observability.map.safeBoundary')}
value="0"
detail={t('observability.map.safeBoundaryDetail')}
tone="ok"
icon={<ShieldCheck size={16} />}
/>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1.35fr) minmax(0, 0.65fr)', gap: 12 }} className="automation-inventory-observability-grid">
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 10 }} className="automation-inventory-observability-surface-grid">
{visibleObservabilitySurfaces.map(surface => (
<div key={surface.surface_id} style={{ padding: 11, border: '0.5px solid #e0ddd4', borderRadius: 7, background: '#fff', minWidth: 0 }}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, minWidth: 0 }}>
<span style={{
fontFamily: 'Syne, sans-serif',
fontSize: 12,
fontWeight: 700,
color: '#141413',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}>
{surface.display_name}
</span>
<Chip value={observabilityValueLabel(surface.status)} muted={surface.status === 'verified'} />
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, minWidth: 0 }}>
<Chip value={observabilityValueLabel(surface.kind)} />
<Chip value={`${t('observability.labels.evidence')}: ${observabilityValueLabel(surface.evidence_status)}`} muted={surface.evidence_status === 'committed_manifest' || surface.evidence_status === 'production_readback_recorded'} />
<Chip value={`${t('observability.labels.noise')}: ${observabilityValueLabel(surface.noise_policy_status)}`} muted />
</div>
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{surface.coverage_contract}
</div>
{surface.current_contract ? (
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{surface.current_contract}
</div>
) : null}
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#141413', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{surface.next_action}
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, minWidth: 0 }}>
<Chip value={surface.evidence_refs[0] ?? t('backupEvidence.noEvidence')} muted />
</div>
</div>
</div>
))}
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
<div style={{ padding: 12, border: '0.5px solid #e0ddd4', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
{t('observability.noiseTitle')}
</span>
{visibleNoiseOpportunities.slice(0, 5).map(opportunity => (
<div key={opportunity.opportunity_id} style={{ display: 'flex', flexDirection: 'column', gap: 6, minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 11, fontWeight: 700, color: '#141413', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
{opportunity.display_name}
</span>
<Chip value={observabilityValueLabel(opportunity.status)} muted />
</div>
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{opportunity.impact}
</div>
</div>
))}
</div>
<div style={{ padding: 12, border: '0.5px solid #e0ddd4', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
{t('observability.classificationTitle')}
</span>
{observabilityMatrix.classification_gaps.map(gap => (
<div key={gap.gap_id} style={{ display: 'flex', flexDirection: 'column', gap: 6, minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8 }}>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 11, fontWeight: 700, color: '#141413', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
{gap.display_name}
</span>
<Chip value={observabilityValueLabel(gap.status)} />
</div>
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{gap.summary}
</div>
</div>
))}
</div>
<div style={{ padding: 12, border: '0.5px solid #e0ddd4', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
{t('observability.contractTitle')}
</span>
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
{observabilityMatrix.operator_contract.alertmanager_route_policy}
</div>
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
{observabilityMatrix.operator_contract.noise_reduction_policy}
</div>
<div style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
{observabilityMatrix.operator_contract.notification_policy}
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, minWidth: 0 }}>
{observabilityMatrix.operator_contract.must_not_interpret_as.slice(0, 6).map(item => (
<Chip key={item} value={item} />
))}
</div>
</div>
</div>
</div>
</div>
</GlassCard>
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1.2fr) minmax(0, 0.8fr)', gap: 12 }} className="automation-inventory-bottom-grid">
<GlassCard variant="subtle" padding="md">
<div style={{ display: 'flex', flexDirection: 'column', gap: 13, minWidth: 0 }}>
@@ -1564,6 +1767,10 @@ export function AutomationInventoryTab() {
.automation-inventory-gitea-map-grid,
.automation-inventory-gitea-grid,
.automation-inventory-gitea-workflow-grid,
.automation-inventory-observability-kpi-grid,
.automation-inventory-observability-map-grid,
.automation-inventory-observability-grid,
.automation-inventory-observability-surface-grid,
.automation-inventory-bottom-grid,
.automation-inventory-task-grid {
grid-template-columns: 1fr !important;

View File

@@ -272,6 +272,11 @@ export const apiClient = {
return handleResponse<GiteaWorkflowRunnerHealthSnapshot>(res)
},
async getObservabilityContractMatrix() {
const res = await fetch(`${API_BASE_URL}/agents/observability-contract-matrix`)
return handleResponse<ObservabilityContractMatrixSnapshot>(res)
},
async getBackupDrTargetInventory() {
const res = await fetch(`${API_BASE_URL}/agents/backup-dr-target-inventory`)
return handleResponse<BackupDrTargetInventorySnapshot>(res)
@@ -946,6 +951,80 @@ export interface GiteaWorkflowRunnerHealthSnapshot {
approval_boundaries: Record<string, false>
}
export interface ObservabilityContractMatrixSnapshot {
schema_version: 'observability_contract_matrix_v1'
generated_at: string
program_status: {
overall_completion_percent: number
current_priority: 'P0' | 'P1' | 'P2' | 'P3'
current_task_id: string
next_task_id: string
read_only_mode: true
}
source_refs: string[]
rollups: {
total_surfaces: number
by_kind: Record<string, number>
by_status: Record<string, number>
by_evidence_status: Record<string, number>
by_noise_policy_status: Record<string, number>
surface_ids_requiring_action: string[]
surface_ids_with_proposal_only_noise_policy: string[]
noise_reduction_opportunities_total: number
approval_required_opportunity_ids: string[]
classification_gap_ids: string[]
read_only_denials_total: number
}
observability_surfaces: Array<{
surface_id: string
display_name: string
kind: string
status: 'verified' | 'action_required' | 'blocked'
risk_level: 'low' | 'medium' | 'high' | 'critical'
evidence_status: string
noise_policy_status: string
coverage_contract: string
current_contract?: string
evidence_refs: string[]
next_action: string
}>
noise_reduction_opportunities: Array<{
opportunity_id: string
display_name: string
status: string
proposal_only: true
impact: string
target_surface_ids?: string[]
evidence_refs: string[]
next_action: string
}>
classification_gaps: Array<{
gap_id: string
display_name: string
status: string
severity: 'low' | 'medium' | 'high' | 'critical'
summary: string
evidence_refs: string[]
next_action: string
}>
latest_observations: Array<{
observation_id: string
status: string
summary: string
evidence_refs: string[]
}>
operator_contract: {
display_mode: 'read_only_observability_contract_matrix'
must_not_interpret_as: string[]
secret_display_policy: string
alertmanager_route_policy: string
noise_reduction_policy: string
notification_policy: string
}
operation_boundaries: Record<string, boolean>
approval_boundaries: Record<string, false>
}
export interface BackupDrTargetInventorySnapshot {
schema_version: 'backup_dr_target_inventory_v1'
generated_at: string