feat(governance): 新增 12-Agent War Room 讀回
Some checks failed
CD Pipeline / tests (push) Failing after 7s
CD Pipeline / build-and-deploy (push) Has been skipped
CD Pipeline / post-deploy-checks (push) Has been skipped
Code Review / ai-code-review (push) Successful in 22s

This commit is contained in:
Your Name
2026-06-14 14:03:15 +08:00
parent e76c424431
commit 5de4b3f36b
13 changed files with 1574 additions and 4 deletions

View File

@@ -39,6 +39,7 @@ import { StatusOrb } from '@/components/ui/status-orb'
import { AgentActivityConstellation } from '@/components/governance/agent-activity-constellation'
import {
apiClient,
type AiAgent12AgentWarRoomSnapshot,
type AiAgentCandidateOperationDryRunEvidenceSnapshot,
type AiAgentCriticReviewerResultCaptureSnapshot,
type AiAgentDeploymentLayoutSnapshot,
@@ -457,6 +458,7 @@ export function AutomationInventoryTab() {
const [observabilityMatrix, setObservabilityMatrix] = useState<ObservabilityContractMatrixSnapshot | null>(null)
const [providerRouteMatrix, setProviderRouteMatrix] = useState<AiProviderRouteMatrixSnapshot | null>(null)
const [deploymentLayout, setDeploymentLayout] = useState<AiAgentDeploymentLayoutSnapshot | null>(null)
const [warRoom, setWarRoom] = useState<AiAgent12AgentWarRoomSnapshot | null>(null)
const [proactiveOperations, setProactiveOperations] = useState<AiAgentProactiveOperationsContractSnapshot | null>(null)
const [interactionLearningProof, setInteractionLearningProof] = useState<AiAgentInteractionLearningProofSnapshot | null>(null)
const [liveReadModelGate, setLiveReadModelGate] = useState<AiAgentLiveReadModelGateSnapshot | null>(null)
@@ -535,6 +537,7 @@ export function AutomationInventoryTab() {
apiClient.getObservabilityContractMatrix(),
apiClient.getAiProviderRouteMatrix(),
apiClient.getAiAgentDeploymentLayout(),
apiClient.getAiAgent12AgentWarRoom(),
apiClient.getAiAgentProactiveOperationsContract(),
apiClient.getAiAgentInteractionLearningProof(),
apiClient.getAiAgentLiveReadModelGate(),
@@ -612,6 +615,7 @@ export function AutomationInventoryTab() {
observabilityMatrixResult,
providerRouteMatrixResult,
deploymentLayoutResult,
warRoomResult,
proactiveOperationsResult,
interactionLearningProofResult,
liveReadModelGateResult,
@@ -686,6 +690,7 @@ export function AutomationInventoryTab() {
setObservabilityMatrix(observabilityMatrixResult.status === 'fulfilled' ? observabilityMatrixResult.value : null)
setProviderRouteMatrix(providerRouteMatrixResult.status === 'fulfilled' ? providerRouteMatrixResult.value : null)
setDeploymentLayout(deploymentLayoutResult.status === 'fulfilled' ? deploymentLayoutResult.value : null)
setWarRoom(warRoomResult.status === 'fulfilled' ? warRoomResult.value : null)
setProactiveOperations(proactiveOperationsResult.status === 'fulfilled' ? proactiveOperationsResult.value : null)
setInteractionLearningProof(interactionLearningProofResult.status === 'fulfilled' ? interactionLearningProofResult.value : null)
setLiveReadModelGate(liveReadModelGateResult.status === 'fulfilled' ? liveReadModelGateResult.value : null)
@@ -758,6 +763,7 @@ export function AutomationInventoryTab() {
observabilityMatrixResult,
providerRouteMatrixResult,
deploymentLayoutResult,
warRoomResult,
proactiveOperationsResult,
interactionLearningProofResult,
liveReadModelGateResult,
@@ -883,6 +889,19 @@ export function AutomationInventoryTab() {
.slice(0, 12)
}, [deploymentLayout])
const visibleWarRoomRoles = useMemo(() => {
if (!warRoom) return []
const riskPriority = { critical: 0, high: 1, medium: 2, low: 3 } as Record<string, number>
return [...warRoom.agent_roles]
.sort((a, b) => {
const riskLeft = riskPriority[a.risk_tier] ?? 4
const riskRight = riskPriority[b.risk_tier] ?? 4
if (riskLeft !== riskRight) return riskLeft - riskRight
return a.agent_id.localeCompare(b.agent_id)
})
.slice(0, 12)
}, [warRoom])
const visibleDelegableCapabilities = useMemo(() => {
if (!proactiveOperations) return []
const riskPriority = { critical: 0, high: 1, medium: 2, low: 3 } as Record<string, number>
@@ -2056,7 +2075,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 || !reportAutomationReview || !reportStatusBoard || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !matchedPlaybookLearningGap || !criticReviewerResultCapture || !ownerApprovedResultCaptureDryRun || !ownerApprovedResultCaptureReadback || !runtimeReadbackApprovalPackage || !runtimeReadbackImplementationReview || !reportLiveDeliveryApprovalPackage || !runtimeReadbackFixtureApproval || !runtimeReadbackPromotionGate || !ownerApprovedFixturePromotionGate || !canonicalRuntimeReadbackOwnerAcceptance || !failureReceiptNoSendReplay || !reviewerQueueNoWriteReadback || !resultCaptureNoWriteReadback || !resultCapturePromotionApprovalGate || !ownerApprovedResultCapturePromotionDryRun || !resultCaptureWriteGateReview || !resultCaptureWriterImplementationReview || !resultCaptureWriterDryRunFixture || !resultCaptureWriterDryRunReadback || !resultCaptureOwnerPromotionReview || !resultCaptureOwnerApprovedExecutionRehearsal || !resultCaptureOwnerAcceptanceMaintenanceGate || !resultCaptureOwnerAcceptanceReadbackPreflightHold || !resultCaptureOwnerApprovedPreflightReleasePackage || !resultCaptureOwnerApprovedReleaseReadinessReadback || !resultCaptureOwnerReleaseApprovalGate || !resultCapturePostReleaseVerifierRollbackGate || !resultCaptureFinalReleaseCandidateReadback || !resultCaptureReleaseAuthorizationHold || !resultCaptureReleaseAuthorizationReadbackGate || !resultCaptureReleaseVerifierPreflightGate || !resultCaptureReleaseVerifierOwnerReviewPacket || !resultCaptureReleaseDecisionHold || !resultCaptureReleaseDecisionReadback || !resultCaptureReleaseDecisionNextHandoff || !resultCaptureReleaseDecisionInputPrep || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !warRoom || !proactiveOperations || !interactionLearningProof || !liveReadModelGate || !redisDryRunGate || !learningWritebackPackage || !telegramReceiptPackage || !ownerApprovedLearningDryRun || !runtimeWriteGateReview || !postWriteVerifierPackage || !runtimeVerifierEvidenceReview || !reportAutomationReview || !reportStatusBoard || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !matchedPlaybookLearningGap || !criticReviewerResultCapture || !ownerApprovedResultCaptureDryRun || !ownerApprovedResultCaptureReadback || !runtimeReadbackApprovalPackage || !runtimeReadbackImplementationReview || !reportLiveDeliveryApprovalPackage || !runtimeReadbackFixtureApproval || !runtimeReadbackPromotionGate || !ownerApprovedFixturePromotionGate || !canonicalRuntimeReadbackOwnerAcceptance || !failureReceiptNoSendReplay || !reviewerQueueNoWriteReadback || !resultCaptureNoWriteReadback || !resultCapturePromotionApprovalGate || !ownerApprovedResultCapturePromotionDryRun || !resultCaptureWriteGateReview || !resultCaptureWriterImplementationReview || !resultCaptureWriterDryRunFixture || !resultCaptureWriterDryRunReadback || !resultCaptureOwnerPromotionReview || !resultCaptureOwnerApprovedExecutionRehearsal || !resultCaptureOwnerAcceptanceMaintenanceGate || !resultCaptureOwnerAcceptanceReadbackPreflightHold || !resultCaptureOwnerApprovedPreflightReleasePackage || !resultCaptureOwnerApprovedReleaseReadinessReadback || !resultCaptureOwnerReleaseApprovalGate || !resultCapturePostReleaseVerifierRollbackGate || !resultCaptureFinalReleaseCandidateReadback || !resultCaptureReleaseAuthorizationHold || !resultCaptureReleaseAuthorizationReadbackGate || !resultCaptureReleaseVerifierPreflightGate || !resultCaptureReleaseVerifierOwnerReviewPacket || !resultCaptureReleaseDecisionHold || !resultCaptureReleaseDecisionReadback || !resultCaptureReleaseDecisionNextHandoff || !resultCaptureReleaseDecisionInputPrep || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
return (
<div style={{ padding: 20 }}>
<GlassCard variant="subtle" padding="lg">
@@ -3519,6 +3538,34 @@ export function AutomationInventoryTab() {
serviceHealthNotificationPolicy.display_redaction_contract.conversation_transcript_display_allowed === false
&& serviceHealthNotificationPolicy.display_redaction_contract.redaction_required === true
)
const warRoomOverall = warRoom.program_status.overall_completion_percent
const warRoomCompletedReviews = warRoom.rollups.read_only_review_completed_count
const warRoomRoleCount = warRoom.rollups.agent_role_count
const warRoomBatchCount = warRoom.rollups.subagent_batch_count
const warRoomBatchLimit = warRoom.rollups.subagent_batch_limit
const warRoomWorkUnits = warRoom.rollups.total_work_units
const warRoomApprovals = warRoom.rollups.approval_required_total
const warRoomBlockers = warRoom.rollups.blocker_total
const warRoomMarketCandidates = warRoom.rollups.market_refresh_candidate_count
const warRoomReportCadences = (
warRoom.rollups.daily_report_required_count
+ warRoom.rollups.weekly_report_required_count
+ warRoom.rollups.monthly_report_required_count
)
const warRoomLiveWrites = (
warRoom.rollups.live_write_count
+ warRoom.rollups.telegram_send_count
+ warRoom.rollups.bot_api_call_count
+ warRoom.rollups.production_write_count
+ warRoom.rollups.paid_api_call_count
+ warRoom.rollups.sdk_install_count
+ warRoom.rollups.secret_read_count
+ warRoom.rollups.destructive_operation_count
)
const warRoomRedactionLocked = (
warRoom.display_redaction_contract.conversation_transcript_display_allowed === false
&& warRoom.display_redaction_contract.redaction_required === true
)
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
@@ -3788,6 +3835,123 @@ export function AutomationInventoryTab() {
]}
/>
<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: 8, minWidth: 0 }}>
<Layers3 size={15} style={{ color: '#d97757' }} />
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 14, fontWeight: 700, color: '#141413' }}>
{t('warRoom.title')}
</span>
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, justifyContent: 'flex-end' }}>
<Chip
value={t('warRoom.source', {
generated: formatDateTime(warRoom.generated_at),
current: warRoom.program_status.current_task_id,
next: warRoom.program_status.next_task_id,
})}
muted
/>
<Chip value={t('warRoom.runtime', { value: warRoom.program_status.runtime_authority })} muted />
</div>
</div>
<p style={{ margin: 0, fontFamily: "'DM Mono', monospace", fontSize: 11, lineHeight: 1.55, color: '#5c5a55', overflowWrap: 'anywhere' }}>
{warRoom.program_status.status_note}
</p>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(128px, 1fr))', gap: 10 }} className="automation-inventory-live-read-kpi-grid">
<MetricCard label={t('warRoom.metrics.overall')} value={`${warRoomOverall}%`} tone="warn" icon={<Gauge size={16} />} />
<MetricCard label={t('warRoom.metrics.reviews')} value={`${warRoomCompletedReviews}/${warRoomRoleCount}`} tone="ok" icon={<ShieldCheck size={16} />} />
<MetricCard label={t('warRoom.metrics.batches')} value={`${warRoomBatchCount}×${warRoomBatchLimit}`} tone="neutral" icon={<Layers3 size={16} />} />
<MetricCard label={t('warRoom.metrics.workUnits')} value={warRoomWorkUnits} tone="neutral" icon={<FileText size={16} />} />
<MetricCard label={t('warRoom.metrics.approvals')} value={warRoomApprovals} tone="warn" icon={<ShieldAlert size={16} />} />
<MetricCard label={t('warRoom.metrics.blockers')} value={warRoomBlockers} tone="danger" icon={<AlertTriangle size={16} />} />
<MetricCard label={t('warRoom.metrics.market')} value={warRoomMarketCandidates} tone="warn" icon={<Target size={16} />} />
<MetricCard label={t('warRoom.metrics.liveWrites')} value={warRoomLiveWrites} tone={warRoomLiveWrites === 0 ? 'ok' : 'danger'} icon={<BellOff size={16} />} />
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: 10 }}>
<div style={{ padding: 10, border: '0.5px solid #d7c7a1', borderRadius: 7, background: '#fff', minWidth: 0 }}>
<SmallLabel>{t('warRoom.coordinationTitle')}</SmallLabel>
<p style={{ margin: '6px 0 8px', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.5, color: '#5c5a55', overflowWrap: 'anywhere' }}>
{warRoom.coordination_model.summary}
</p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
<Chip value={t('warRoom.labels.arbiter', { value: warRoom.coordination_model.arbiter })} />
<Chip value={t('warRoom.labels.memory', { value: warRoom.coordination_model.memory_owner })} muted />
<Chip value={t('warRoom.labels.replay', { value: warRoom.coordination_model.replay_owner })} muted />
<Chip value={t('warRoom.labels.reports', { value: String(warRoomReportCadences) })} muted />
</div>
</div>
<div style={{ padding: 10, border: '0.5px solid #d7c7a1', borderRadius: 7, background: '#fff', minWidth: 0 }}>
<SmallLabel>{t('warRoom.telegramTitle')}</SmallLabel>
<p style={{ margin: '6px 0 8px', fontFamily: "'DM Mono', monospace", fontSize: 10, lineHeight: 1.5, color: '#5c5a55', overflowWrap: 'anywhere' }}>
{warRoom.telegram_contract.summary}
</p>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
<Chip value={t('warRoom.labels.directSend', { value: String(warRoom.telegram_contract.direct_send_allowed) })} />
<Chip value={t('warRoom.labels.botApi', { value: String(warRoom.telegram_contract.bot_api_call_allowed) })} muted />
<Chip value={t('warRoom.labels.dedup', { value: String(warRoom.telegram_contract.dedup_required) })} muted />
<Chip value={t('warRoom.labels.redaction', { value: String(warRoomRedactionLocked) })} muted />
</div>
</div>
</div>
<SmallLabel>{t('warRoom.rolesTitle')}</SmallLabel>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
{visibleWarRoomRoles.map(role => {
const roleTone = role.risk_tier === 'critical' ? 'danger' : role.risk_tier === 'high' ? 'warn' : 'neutral'
const roleColor = toneColor(roleTone)
return (
<div key={role.agent_id} style={{ padding: 10, border: `0.5px solid ${roleColor}55`, borderRadius: 7, background: '#fff', 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' }}>
{role.display_name}
</span>
<Chip value={role.risk_tier} muted={role.risk_tier !== 'critical'} />
</div>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{role.war_room_role}
</span>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
<Chip value={role.primary_agent} muted />
<Chip value={t('warRoom.labels.workUnits', { value: String(role.work_units) })} muted />
<Chip value={t('warRoom.labels.approvals', { value: String(role.approval_required_count) })} muted />
<Chip value={t('warRoom.labels.blockers', { value: String(role.blocker_count) })} muted />
<Chip value={t('warRoom.labels.liveWrites', { value: String(role.live_write_count) })} muted />
<Chip value={t('warRoom.labels.telegramSends', { value: String(role.telegram_send_count) })} muted />
</div>
</div>
)
})}
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }}>
<MiniBar
label={t('warRoom.report.daily')}
value={warRoom.reporting_contract.daily.required ? 100 : 0}
detail={warRoom.reporting_contract.daily.delivery_mode}
tone="ok"
/>
<MiniBar
label={t('warRoom.report.weekly')}
value={warRoom.reporting_contract.weekly.required ? 100 : 0}
detail={warRoom.reporting_contract.weekly.delivery_mode}
tone="ok"
/>
<MiniBar
label={t('warRoom.report.monthly')}
value={warRoom.reporting_contract.monthly.required ? 100 : 0}
detail={warRoom.reporting_contract.monthly.delivery_mode}
tone="warn"
/>
</div>
</div>
</GlassCard>
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1.05fr) minmax(0, 0.95fr)', gap: 12 }} className="automation-inventory-command-grid">
<GlassCard variant="subtle" padding="md">
<div style={{ display: 'flex', flexDirection: 'column', gap: 13, minWidth: 0 }}>

View File

@@ -329,6 +329,11 @@ export const apiClient = {
return handleResponse<AiAgentDeploymentLayoutSnapshot>(res)
},
async getAiAgent12AgentWarRoom() {
const res = await fetch(`${API_BASE_URL}/agents/agent-12-agent-war-room`)
return handleResponse<AiAgent12AgentWarRoomSnapshot>(res)
},
async getAiAgentProactiveOperationsContract() {
const res = await fetch(`${API_BASE_URL}/agents/agent-proactive-operations-contract`)
return handleResponse<AiAgentProactiveOperationsContractSnapshot>(res)
@@ -1284,6 +1289,120 @@ export interface AiAgentDeploymentLayoutSnapshot {
>
}
export interface AiAgent12AgentWarRoomSnapshot {
schema_version: 'ai_agent_12_agent_war_room_v1'
generated_at: string
program_status: {
overall_completion_percent: number
current_priority: 'P0' | 'P1' | 'P2' | 'P3'
current_task_id: 'P2-142'
next_task_id: 'P2-143'
read_only_mode: true
runtime_authority: '12_agent_war_room_read_only_no_live_write'
status_note: string
}
source_refs: string[]
coordination_model: {
logical_agent_count: number
subagent_batch_limit: number
subagent_batch_count: number
coordination_mode: string
arbiter: string
memory_owner: string
replay_owner: string
gateway_owner: string
summary: string
}
agent_roles: Array<{
agent_id: string
display_name: string
primary_agent: string
war_room_role: string
review_status: string
risk_tier: 'low' | 'medium' | 'high' | 'critical'
work_units: number
evidence_items: number
blocker_count: number
approval_required_count: number
live_write_count: number
telegram_send_count: number
bot_api_call_count: number
next_action: string
}>
workload_summary: {
total_work_units: number
total_evidence_items: number
status_report_visible: boolean
chart_ready: boolean
daily_report_required: boolean
weekly_report_required: boolean
monthly_report_required: boolean
standard_agent_metrics: string[]
}
risk_policy: {
low_risk_auto_handle: string
medium_risk_auto_handle: string
high_risk_requires_approval: string
openclaw_gate_required: boolean
qa_verifier_required: boolean
security_gate_required: boolean
}
reporting_contract: Record<'daily' | 'weekly' | 'monthly', {
required: boolean
delivery_mode: string
sections: string[]
}>
market_watch_contract: {
cadence: string
auto_collect_allowed: string[]
approval_required: string[]
p0_refresh_candidates: string[]
candidate_package_required_fields: string[]
}
telegram_contract: {
direct_send_allowed: boolean
bot_api_call_allowed: boolean
success_immediate_send_allowed: boolean
action_required_digest_allowed_after_approval: boolean
failure_only_escalation: boolean
dedup_required: boolean
receipt_required: boolean
forbidden_actions: string[]
summary: string
}
display_redaction_contract: {
redaction_required: boolean
conversation_transcript_display_allowed: boolean
raw_prompt_display_allowed: boolean
private_reasoning_display_allowed: boolean
secret_value_display_allowed: boolean
raw_runtime_payload_display_allowed: boolean
frontend_display_policy: string
}
rollups: {
agent_role_count: number
read_only_review_completed_count: number
subagent_batch_limit: number
subagent_batch_count: number
approval_required_total: number
blocker_total: number
total_work_units: number
total_evidence_items: number
daily_report_required_count: number
weekly_report_required_count: number
monthly_report_required_count: number
market_refresh_candidate_count: number
live_write_count: number
telegram_send_count: number
bot_api_call_count: number
production_write_count: number
paid_api_call_count: number
sdk_install_count: number
secret_read_count: number
destructive_operation_count: number
}
}
export interface AiAgentProactiveOperationsContractSnapshot {
schema_version: 'ai_agent_proactive_operations_contract_v1'
generated_at: string