feat(governance): 新增報表真相與告警有效性審查
All checks were successful
CD Pipeline / tests (push) Successful in 1m34s
Code Review / ai-code-review (push) Successful in 15s
CD Pipeline / build-and-deploy (push) Successful in 6m2s
CD Pipeline / post-deploy-checks (push) Successful in 2m38s

This commit is contained in:
Your Name
2026-06-12 10:28:19 +08:00
parent bc4735a645
commit 7fef2dc832
20 changed files with 1178 additions and 21 deletions

View File

@@ -45,6 +45,7 @@ import {
type AiAgentPostWriteVerifierPackageSnapshot,
type AiAgentProactiveOperationsContractSnapshot,
type AiAgentRedisDryRunGateSnapshot,
type AiAgentReportTruthActionabilityReviewSnapshot,
type AiAgentRuntimeVerifierEvidenceReviewSnapshot,
type AiAgentRuntimeWriteGateReviewSnapshot,
type AiAgentTelegramReceiptApprovalPackageSnapshot,
@@ -335,6 +336,7 @@ export function AutomationInventoryTab() {
const [runtimeWriteGateReview, setRuntimeWriteGateReview] = useState<AiAgentRuntimeWriteGateReviewSnapshot | null>(null)
const [postWriteVerifierPackage, setPostWriteVerifierPackage] = useState<AiAgentPostWriteVerifierPackageSnapshot | null>(null)
const [runtimeVerifierEvidenceReview, setRuntimeVerifierEvidenceReview] = useState<AiAgentRuntimeVerifierEvidenceReviewSnapshot | null>(null)
const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState<AiAgentReportTruthActionabilityReviewSnapshot | null>(null)
const [ownerDryRunPackage, setOwnerDryRunPackage] = useState<AiAgentOwnerApprovedFixtureDryRunSnapshot | null>(null)
const [hostStatefulInventory, setHostStatefulInventory] = useState<AiAgentHostStatefulVersionInventorySnapshot | null>(null)
const [serviceHealthGapMatrix, setServiceHealthGapMatrix] = useState<ServiceHealthGapMatrixSnapshot | null>(null)
@@ -366,6 +368,7 @@ export function AutomationInventoryTab() {
apiClient.getAiAgentRuntimeWriteGateReview(),
apiClient.getAiAgentPostWriteVerifierPackage(),
apiClient.getAiAgentRuntimeVerifierEvidenceReview(),
apiClient.getAiAgentReportTruthActionabilityReview(),
apiClient.getAiAgentOwnerApprovedFixtureDryRun(),
apiClient.getAiAgentHostStatefulVersionInventory(),
apiClient.getServiceHealthGapMatrix(),
@@ -396,6 +399,7 @@ export function AutomationInventoryTab() {
runtimeWriteGateReviewResult,
postWriteVerifierPackageResult,
runtimeVerifierEvidenceReviewResult,
reportTruthActionabilityReviewResult,
ownerDryRunPackageResult,
hostStatefulInventoryResult,
serviceHealthGapMatrixResult,
@@ -423,6 +427,7 @@ export function AutomationInventoryTab() {
setRuntimeWriteGateReview(runtimeWriteGateReviewResult.status === 'fulfilled' ? runtimeWriteGateReviewResult.value : null)
setPostWriteVerifierPackage(postWriteVerifierPackageResult.status === 'fulfilled' ? postWriteVerifierPackageResult.value : null)
setRuntimeVerifierEvidenceReview(runtimeVerifierEvidenceReviewResult.status === 'fulfilled' ? runtimeVerifierEvidenceReviewResult.value : null)
setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null)
setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null)
setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null)
setServiceHealthGapMatrix(serviceHealthGapMatrixResult.status === 'fulfilled' ? serviceHealthGapMatrixResult.value : null)
@@ -448,6 +453,7 @@ export function AutomationInventoryTab() {
runtimeWriteGateReviewResult,
postWriteVerifierPackageResult,
runtimeVerifierEvidenceReviewResult,
reportTruthActionabilityReviewResult,
ownerDryRunPackageResult,
hostStatefulInventoryResult,
serviceHealthGapMatrixResult,
@@ -834,6 +840,46 @@ export function AutomationInventoryTab() {
})
}, [runtimeVerifierEvidenceReview])
const visibleReportTruthFindings = useMemo(() => {
if (!reportTruthActionabilityReview) return []
const priority = { critical: 0, high: 1, medium: 2, low: 3 } as Record<string, number>
return [...reportTruthActionabilityReview.zero_signal_findings]
.sort((a, b) => {
const left = priority[a.severity] ?? 4
const right = priority[b.severity] ?? 4
if (left !== right) return left - right
return a.finding_id.localeCompare(b.finding_id)
})
}, [reportTruthActionabilityReview])
const visibleTelegramRouteFindings = useMemo(() => {
if (!reportTruthActionabilityReview) return []
const priority = {
direct_send_path_present: 0,
legacy_chat_env_referenced: 1,
multiple_bot_tokens_present: 2,
} as Record<string, number>
return [...reportTruthActionabilityReview.telegram_route_findings]
.sort((a, b) => {
const left = priority[a.current_state] ?? 3
const right = priority[b.current_state] ?? 3
if (left !== right) return left - right
return a.route_id.localeCompare(b.route_id)
})
}, [reportTruthActionabilityReview])
const visibleReportTruthActions = useMemo(() => {
if (!reportTruthActionabilityReview) return []
const priority = { approval_required: 0, ready_for_owner: 1, blocked_by_runtime_gate: 2 } as Record<string, number>
return [...reportTruthActionabilityReview.operator_actions]
.sort((a, b) => {
const left = priority[a.status] ?? 3
const right = priority[b.status] ?? 3
if (left !== right) return left - right
return a.action_id.localeCompare(b.action_id)
})
}, [reportTruthActionabilityReview])
const visibleOwnerDryRunGates = useMemo(() => {
if (!ownerDryRunPackage) return []
const priority = { approval_required: 0, approved_for_fixture_only: 1, fixture_only: 2, ready: 3 } as Record<string, number>
@@ -1013,7 +1059,7 @@ export function AutomationInventoryTab() {
)
}
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
return (
<div style={{ padding: 20 }}>
<GlassCard variant="subtle" padding="lg">
@@ -1152,6 +1198,16 @@ export function AutomationInventoryTab() {
const runtimeVerifierApprovals = runtimeVerifierEvidenceReview.rollups.approval_required_action_ids.length
const runtimeVerifierBlockedActions = runtimeVerifierEvidenceReview.rollups.blocked_runtime_action_count
const runtimeVerifierLiveTotal = runtimeVerifierEvidenceReview.rollups.live_verifier_execution_count
const reportTruthOverall = reportTruthActionabilityReview.program_status.overall_completion_percent
const reportTruthFindings = reportTruthActionabilityReview.rollups.zero_signal_finding_count
const reportTruthCritical = reportTruthActionabilityReview.rollups.critical_finding_count
const reportTruthCadences = reportTruthActionabilityReview.rollups.cadence_contract_count
const reportTruthMissingCadence = reportTruthActionabilityReview.rollups.missing_cadence_contract_count
const reportTruthRouteFindings = reportTruthActionabilityReview.rollups.telegram_route_finding_count
const reportTruthLegacyRoutes = reportTruthActionabilityReview.rollups.legacy_or_direct_route_count
const reportTruthActions = reportTruthActionabilityReview.rollups.operator_action_count
const reportTruthApprovals = reportTruthActionabilityReview.rollups.approval_required_action_ids.length
const reportTruthBlockedActions = reportTruthActionabilityReview.rollups.blocked_runtime_action_count
const ownerDryRunOverall = ownerDryRunPackage.program_status.overall_completion_percent
const ownerDryRunFixtures = ownerDryRunPackage.rollups.fixture_set_count
const ownerDryRunGates = ownerDryRunPackage.rollups.dry_run_gate_count
@@ -1737,6 +1793,125 @@ export function AutomationInventoryTab() {
</div>
</div>
<div style={{ padding: 12, border: '0.5px solid #d8c6a6', borderRadius: 7, background: '#fffdf7', display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, 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('reportTruthActionabilityReview.title')}
</span>
</div>
<Chip
value={t('reportTruthActionabilityReview.source', {
generated: formatDateTime(reportTruthActionabilityReview.generated_at),
current: reportTruthActionabilityReview.program_status.current_task_id,
next: reportTruthActionabilityReview.program_status.next_task_id,
})}
muted
/>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(128px, 1fr))', gap: 10 }} className="automation-inventory-live-read-kpi-grid">
<MetricCard label={t('reportTruthActionabilityReview.metrics.overall')} value={`${reportTruthOverall}%`} tone="warn" icon={<Gauge size={16} />} />
<MetricCard label={t('reportTruthActionabilityReview.metrics.findings')} value={reportTruthFindings} tone="danger" icon={<AlertTriangle size={16} />} />
<MetricCard label={t('reportTruthActionabilityReview.metrics.critical')} value={reportTruthCritical} tone="danger" icon={<ShieldAlert size={16} />} />
<MetricCard label={t('reportTruthActionabilityReview.metrics.cadences')} value={reportTruthCadences} tone="warn" icon={<FileText size={16} />} />
<MetricCard label={t('reportTruthActionabilityReview.metrics.missingCadence')} value={reportTruthMissingCadence} tone="danger" icon={<Lock size={16} />} />
<MetricCard label={t('reportTruthActionabilityReview.metrics.telegramRoutes')} value={reportTruthRouteFindings} tone="danger" icon={<BellOff size={16} />} />
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 0.85fr) minmax(0, 1.15fr)', gap: 12 }} className="automation-inventory-live-read-grid">
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
<div style={{ padding: 11, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
<SmallLabel>{t('reportTruthActionabilityReview.truthTitle')}</SmallLabel>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
{reportTruthActionabilityReview.report_truth.truth_note}
</span>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
<Chip value={t('reportTruthActionabilityReview.flags.allZero', { value: String(reportTruthActionabilityReview.report_truth.all_zero_weekly_report_is_actionable_anomaly) })} />
<Chip value={t('reportTruthActionabilityReview.flags.freshness', { value: String(reportTruthActionabilityReview.report_truth.freshness_gate_implemented) })} muted />
<Chip value={t('reportTruthActionabilityReview.flags.confidence', { value: String(reportTruthActionabilityReview.report_truth.source_confidence_gate_implemented) })} muted />
<Chip value={t('reportTruthActionabilityReview.flags.actionability', { value: String(reportTruthActionabilityReview.report_truth.actionability_score_implemented) })} muted />
</div>
</div>
<div style={{ padding: 11, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
<SmallLabel>{t('reportTruthActionabilityReview.telegramTitle')}</SmallLabel>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
{reportTruthActionabilityReview.telegram_routing_consolidation.routing_note}
</span>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
<Chip value={t('reportTruthActionabilityReview.labels.canonicalRoom', { room: reportTruthActionabilityReview.telegram_routing_consolidation.canonical_room_name })} />
<Chip value={reportTruthActionabilityReview.telegram_routing_consolidation.canonical_room_env} muted />
<Chip value={t('reportTruthActionabilityReview.flags.otherRoutes', { value: String(reportTruthActionabilityReview.telegram_routing_consolidation.other_bot_or_group_alerts_allowed) })} muted />
<Chip value={t('reportTruthActionabilityReview.flags.routeChange', { value: String(reportTruthActionabilityReview.telegram_routing_consolidation.route_change_allowed) })} muted />
</div>
</div>
<div style={{ padding: 11, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
<SmallLabel>{t('reportTruthActionabilityReview.policyTitle')}</SmallLabel>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 8 }}>
<SummaryTile label={t('reportTruthActionabilityReview.metrics.legacyRoutes')} value={`${reportTruthLegacyRoutes}`} detail={t('reportTruthActionabilityReview.labels.legacyRoutesDetail')} tone="danger" icon={<BellOff size={16} />} />
<SummaryTile label={t('reportTruthActionabilityReview.metrics.approval')} value={`${reportTruthApprovals}`} detail={t('reportTruthActionabilityReview.metrics.blocked', { count: reportTruthBlockedActions })} tone="warn" icon={<Lock size={16} />} />
</div>
</div>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
{visibleReportTruthFindings.map(finding => (
<div key={finding.finding_id} style={{ padding: 10, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 7, 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', lineHeight: 1.35, overflowWrap: 'anywhere' }}>
{finding.display_name}
</span>
<Chip value={finding.severity} muted={finding.severity !== 'critical'} />
</div>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{finding.operator_meaning}
</span>
<Chip value={finding.blocked_runtime_action} muted />
</div>
))}
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
{visibleTelegramRouteFindings.map(routeFinding => (
<div key={routeFinding.route_id} style={{ padding: 10, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 7, 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', lineHeight: 1.35, overflowWrap: 'anywhere' }}>
{routeFinding.display_name}
</span>
<Chip value={routeFinding.current_state} />
</div>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{routeFinding.risk}
</span>
<Chip value={routeFinding.target_state} muted />
</div>
))}
</div>
</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(190px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
{visibleReportTruthActions.map(action => (
<div key={action.action_id} style={{ padding: 10, border: '0.5px solid #eee9dd', borderRadius: 7, background: '#faf9f3', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'center', minWidth: 0 }}>
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 700, color: '#141413', overflowWrap: 'anywhere' }}>
{action.display_name}
</span>
<Chip value={redisDryRunValueLabel('statuses', action.status)} muted={action.status !== 'approval_required'} />
</div>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#87867f', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{action.operator_instruction}
</span>
<Chip value={action.blocked_runtime_action} muted />
</div>
))}
</div>
</div>
<div style={{ padding: 12, border: '0.5px solid #d8c6a6', borderRadius: 7, background: '#fffdf7', display: 'flex', flexDirection: 'column', gap: 12, minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 7, minWidth: 0 }}>

View File

@@ -317,6 +317,11 @@ export const apiClient = {
return handleResponse<AiAgentRuntimeVerifierEvidenceReviewSnapshot>(res)
},
async getAiAgentReportTruthActionabilityReview() {
const res = await fetch(`${API_BASE_URL}/agents/agent-report-truth-actionability-review`)
return handleResponse<AiAgentReportTruthActionabilityReviewSnapshot>(res)
},
async getAiAgentOwnerApprovedFixtureDryRun() {
const res = await fetch(`${API_BASE_URL}/agents/agent-owner-approved-fixture-dry-run`)
return handleResponse<AiAgentOwnerApprovedFixtureDryRunSnapshot>(res)
@@ -1843,6 +1848,106 @@ export interface AiAgentRuntimeVerifierEvidenceReviewSnapshot {
}
}
export interface AiAgentReportTruthActionabilityReviewSnapshot {
schema_version: 'ai_agent_report_truth_actionability_review_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
runtime_authority: 'report_truth_actionability_review_only_no_report_send_or_runtime_fix'
status_note: string
}
source_refs: string[]
report_truth: {
report_truth_packet_ready: true
all_zero_weekly_report_is_actionable_anomaly: true
daily_report_contract_present: boolean
weekly_report_contract_present: boolean
monthly_report_contract_present: false
freshness_gate_implemented: false
source_confidence_gate_implemented: false
actionability_score_implemented: false
ai_agent_runtime_control_allowed: false
telegram_report_send_allowed: false
cronjob_change_allowed: false
truth_note: string
}
zero_signal_findings: Array<{
finding_id: string
display_name: string
severity: string
source: string
evidence: string
operator_meaning: string
required_fix: string
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
blocked_runtime_action: string
}>
report_cadence_contracts: Array<{
cadence_id: string
display_name: string
status: string
source: string
required_truth: string
next_action: string
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
}>
alert_actionability_lanes: Array<{
lane_id: string
display_name: string
routing_policy: string
ai_agent_role: string
notification_policy: string
}>
telegram_routing_consolidation: {
canonical_room_name: 'AwoooI SRE 戰情室'
canonical_room_env: 'SRE_GROUP_CHAT_ID'
product_alerts_must_route_to_canonical_room: true
other_bot_or_group_alerts_allowed: false
direct_telegram_api_send_allowed: false
secret_value_read_allowed: false
route_change_allowed: false
routing_note: string
}
telegram_route_findings: Array<{
route_id: string
display_name: string
source: string
current_state: string
target_state: string
risk: string
required_fix: string
blocked_runtime_action: string
}>
operator_actions: Array<{
action_id: string
display_name: string
action_type: string
status: string
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
operator_instruction: string
blocked_runtime_action: string
}>
approval_boundaries: Record<string, false>
rollups: {
zero_signal_finding_count: number
critical_finding_count: number
high_finding_count: number
cadence_contract_count: number
missing_cadence_contract_count: number
actionability_lane_count: number
telegram_route_finding_count: number
legacy_or_direct_route_count: number
operator_action_count: number
approval_required_action_ids: string[]
blocked_runtime_action_count: number
all_zero_weekly_report_confidence: 'low_trust_actionable_anomaly'
}
}
export interface AiAgentOwnerApprovedFixtureDryRunSnapshot {
schema_version: 'ai_agent_owner_approved_fixture_dry_run_v1'
generated_at: string