feat(governance): surface AI agent execution runways
Some checks failed
Code Review / ai-code-review (push) Successful in 15s
CD Pipeline / tests (push) Successful in 1m43s
CD Pipeline / build-and-deploy (push) Successful in 5m38s
CD Pipeline / post-deploy-checks (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-26 06:30:21 +08:00
parent 3d78142fac
commit 1966647691
3 changed files with 219 additions and 0 deletions

View File

@@ -3576,6 +3576,41 @@
"pipelineBadge": "Sensor → Gate → Verifier", "pipelineBadge": "Sensor → Gate → Verifier",
"boundaryTitle": "真實邊界", "boundaryTitle": "真實邊界",
"boundaryBadge": "不誇大接管", "boundaryBadge": "不誇大接管",
"runwayTitle": "AI Agents 專業執行跑道",
"runwayBadge": "只讀 / 乾跑 / 審核 / 回寫",
"runwaySummary": "可無寫入推進 {noWrite} 類;正式執行 {runtime}、Telegram 發送 {sends}、production 寫入 {writes} 仍依 gate。",
"runway": {
"readOnlyInvestigation": {
"label": "主動巡檢與證據蒐集",
"detail": "只讀探針 {probes} 個,服務需處置訊號 {health} 個。",
"next": "下一步:整理 owner packetruntime blocker {blocked} 個。"
},
"dryRunCandidate": {
"label": "乾跑候選與套用審查",
"detail": "乾跑證據 {evidence} 筆Verifier plan {verifier} 個。",
"next": "下一步:{review} 個候選進 owner review不直接執行。"
},
"shadowReplay": {
"label": "Nemotron replay / shadow",
"detail": "無寫入 replay {replays} 次Verifier shadow case {verifier} 個。",
"next": "下一步:{approvals} 個 checkpoint 需批准才可升級。"
},
"permissionModel": {
"label": "操作權限模型",
"detail": "Gate transition {gates} 條blocked category {blocked} 個。",
"next": "下一步:{approvals} 類仍需人工批准。"
},
"reportTelegram": {
"label": "日週月報與 Telegram receipt",
"detail": "Gateway queue write {queue}live report delivery {delivery}。",
"next": "下一步:{approvals} 個報告/通知決策需批准。"
},
"learningWriteback": {
"label": "學習回寫與 PlayBook 成長",
"detail": "已匹配 approval {matched} 筆KM draft {drafts} 筆。",
"next": "下一步:{gates} 個 learning / trust gate 未打開。"
}
},
"badges": { "badges": {
"readOnly": "全域只讀控管", "readOnly": "全域只讀控管",
"noTranscript": "只顯示脫敏治理狀態", "noTranscript": "只顯示脫敏治理狀態",

View File

@@ -3576,6 +3576,41 @@
"pipelineBadge": "Sensor → Gate → Verifier", "pipelineBadge": "Sensor → Gate → Verifier",
"boundaryTitle": "真實邊界", "boundaryTitle": "真實邊界",
"boundaryBadge": "不誇大接管", "boundaryBadge": "不誇大接管",
"runwayTitle": "AI Agents 專業執行跑道",
"runwayBadge": "只讀 / 乾跑 / 審核 / 回寫",
"runwaySummary": "可無寫入推進 {noWrite} 類;正式執行 {runtime}、Telegram 發送 {sends}、production 寫入 {writes} 仍依 gate。",
"runway": {
"readOnlyInvestigation": {
"label": "主動巡檢與證據蒐集",
"detail": "只讀探針 {probes} 個,服務需處置訊號 {health} 個。",
"next": "下一步:整理 owner packetruntime blocker {blocked} 個。"
},
"dryRunCandidate": {
"label": "乾跑候選與套用審查",
"detail": "乾跑證據 {evidence} 筆Verifier plan {verifier} 個。",
"next": "下一步:{review} 個候選進 owner review不直接執行。"
},
"shadowReplay": {
"label": "Nemotron replay / shadow",
"detail": "無寫入 replay {replays} 次Verifier shadow case {verifier} 個。",
"next": "下一步:{approvals} 個 checkpoint 需批准才可升級。"
},
"permissionModel": {
"label": "操作權限模型",
"detail": "Gate transition {gates} 條blocked category {blocked} 個。",
"next": "下一步:{approvals} 類仍需人工批准。"
},
"reportTelegram": {
"label": "日週月報與 Telegram receipt",
"detail": "Gateway queue write {queue}live report delivery {delivery}。",
"next": "下一步:{approvals} 個報告/通知決策需批准。"
},
"learningWriteback": {
"label": "學習回寫與 PlayBook 成長",
"detail": "已匹配 approval {matched} 筆KM draft {drafts} 筆。",
"next": "下一步:{gates} 個 learning / trust gate 未打開。"
}
},
"badges": { "badges": {
"readOnly": "全域只讀控管", "readOnly": "全域只讀控管",
"noTranscript": "只顯示脫敏治理狀態", "noTranscript": "只顯示脫敏治理狀態",

View File

@@ -5364,6 +5364,97 @@ export function AutomationInventoryTab() {
tone: hostRedactionLocked && professionalTaskRedactionLocked && warRoomRedactionLocked && serviceHealthRedactionLocked ? 'ok' as const : 'warn' as const, tone: hostRedactionLocked && professionalTaskRedactionLocked && warRoomRedactionLocked && serviceHealthRedactionLocked ? 'ok' as const : 'warn' as const,
}, },
] ]
const globalControlRunwayRows: Array<{
key: string
label: string
owner: string
value: string
detail: string
next: string
tone: 'ok' | 'warn' | 'danger' | 'neutral'
icon: ReactNode
}> = [
{
key: 'readOnlyInvestigation',
label: t('globalControl.runway.readOnlyInvestigation.label'),
owner: 'Hermes / OpenClaw',
value: String(runtimeActionRequired + serviceHealthActions + hostRunawayAlertLanes),
detail: t('globalControl.runway.readOnlyInvestigation.detail', {
probes: hostStatefulInventory.rollups.readonly_probe_step_count,
health: serviceHealthActions,
}),
next: t('globalControl.runway.readOnlyInvestigation.next', { blocked: hostRunawayBlocked }),
tone: hostRunawayBlocked > 0 ? 'warn' : 'ok',
icon: <Fingerprint size={15} />,
},
{
key: 'dryRunCandidate',
label: t('globalControl.runway.dryRunCandidate.label'),
owner: 'OpenClaw / SRE',
value: `${candidateDryRunPassed}/${candidateDryRunCount}`,
detail: t('globalControl.runway.dryRunCandidate.detail', {
evidence: candidateDryRunEvidenceCount,
verifier: candidateDryRunVerifierPlans,
}),
next: t('globalControl.runway.dryRunCandidate.next', { review: candidateDryRunNeedsReview }),
tone: candidateDryRunNeedsReview > 0 ? 'warn' : 'ok',
icon: <ClipboardCheck size={15} />,
},
{
key: 'shadowReplay',
label: t('globalControl.runway.shadowReplay.label'),
owner: 'Nemotron / Critic',
value: `${runtimeShadowPassed}/${runtimeShadowCandidates}`,
detail: t('globalControl.runway.shadowReplay.detail', {
replays: runtimeShadowReplays,
verifier: runtimeShadowVerifierCases,
}),
next: t('globalControl.runway.shadowReplay.next', { approvals: runtimeShadowApprovals }),
tone: runtimeShadowApprovals > 0 || runtimeShadowBlocked > 0 ? 'warn' : 'ok',
icon: <RefreshCw size={15} />,
},
{
key: 'permissionModel',
label: t('globalControl.runway.permissionModel.label'),
owner: 'Security / OpenClaw',
value: `${operationPermissionObserveOnly + operationPermissionNoWrite + operationPermissionProposalOnly}/${operationPermissionCategories}`,
detail: t('globalControl.runway.permissionModel.detail', {
gates: operationPermissionGates,
blocked: operationPermissionBlocked,
}),
next: t('globalControl.runway.permissionModel.next', { approvals: operationPermissionHumanApproval }),
tone: operationPermissionBlocked > 0 || operationPermissionHumanApproval > 0 ? 'warn' : 'ok',
icon: <ShieldAlert size={15} />,
},
{
key: 'reportTelegram',
label: t('globalControl.runway.reportTelegram.label'),
owner: 'Hermes / Reporter',
value: `${reportRuntimeReady}/${reportRuntimeLanes}`,
detail: t('globalControl.runway.reportTelegram.detail', {
queue: reportRuntimeQueueWrites,
delivery: reportRuntimeLiveDelivery,
}),
next: t('globalControl.runway.reportTelegram.next', { approvals: reportRuntimeApprovals }),
tone: reportRuntimeApprovals > 0 || reportRuntimeBlocked > 0 ? 'warn' : 'ok',
icon: <BellRing size={15} />,
},
{
key: 'learningWriteback',
label: t('globalControl.runway.learningWriteback.label'),
owner: 'Hermes / OpenClaw',
value: String(matchedPlaybookCandidates + taskResultKmDrafts),
detail: t('globalControl.runway.learningWriteback.detail', {
matched: matchedPlaybookApprovalMatched,
drafts: taskResultKmDrafts,
}),
next: t('globalControl.runway.learningWriteback.next', {
gates: matchedPlaybookGates + learningWritebackApprovals,
}),
tone: matchedPlaybookGates + learningWritebackApprovals > 0 ? 'warn' : 'ok',
icon: <BookOpenCheck size={15} />,
},
]
return ( return (
<div className="automation-inventory-tab-root" style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 16, minWidth: 0 }}> <div className="automation-inventory-tab-root" style={{ padding: 20, display: 'flex', flexDirection: 'column', gap: 16, minWidth: 0 }}>
@@ -5505,6 +5596,63 @@ export function AutomationInventoryTab() {
</div> </div>
</div> </div>
<div style={{ padding: 12, border: '0.5px solid #d9e7f7', borderRadius: 7, background: '#f8fbff', display: 'flex', flexDirection: 'column', gap: 11, minWidth: 0 }}>
<div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 10, flexWrap: 'wrap' }}>
<div style={{ display: 'flex', flexDirection: 'column', gap: 4, minWidth: 0 }}>
<SmallLabel>{t('globalControl.runwayTitle')}</SmallLabel>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
{t('globalControl.runwaySummary', {
noWrite: operationPermissionObserveOnly + operationPermissionNoWrite + operationPermissionProposalOnly,
runtime: operationPermissionRuntimeRuns,
sends: operationPermissionSends,
writes: operationPermissionProductionWrites,
})}
</span>
</div>
<Chip value={t('globalControl.runwayBadge')} muted />
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 10 }} className="automation-inventory-global-control-runway-grid">
{globalControlRunwayRows.map(row => {
const color = toneColor(row.tone)
return (
<div key={row.key} style={{ padding: 10, border: `0.5px solid ${color}44`, borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
<div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'flex-start', minWidth: 0 }}>
<div style={{ display: 'flex', gap: 7, alignItems: 'center', minWidth: 0 }}>
<div style={{
width: 26,
height: 26,
borderRadius: 7,
border: `0.5px solid ${color}55`,
background: `${color}12`,
color,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
}}>
{row.icon}
</div>
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 12, fontWeight: 760, color: '#141413', lineHeight: 1.2, overflowWrap: 'anywhere' }}>
{row.label}
</span>
</div>
<Chip value={row.value} muted={row.tone === 'ok'} />
</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
<Chip value={row.owner} />
</div>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{row.detail}
</span>
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color, fontWeight: 700, lineHeight: 1.45, overflowWrap: 'anywhere' }}>
{row.next}
</span>
</div>
)
})}
</div>
</div>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 10 }} className="automation-inventory-global-control-domain-grid"> <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, minmax(0, 1fr))', gap: 10 }} className="automation-inventory-global-control-domain-grid">
{globalControlDomainRows.map(row => { {globalControlDomainRows.map(row => {
const color = toneColor(row.tone) const color = toneColor(row.tone)
@@ -18216,6 +18364,7 @@ export function AutomationInventoryTab() {
.automation-inventory-global-control-kpi-grid, .automation-inventory-global-control-kpi-grid,
.automation-inventory-global-control-grid, .automation-inventory-global-control-grid,
.automation-inventory-global-control-pipeline-grid, .automation-inventory-global-control-pipeline-grid,
.automation-inventory-global-control-runway-grid,
.automation-inventory-global-control-domain-grid, .automation-inventory-global-control-domain-grid,
.automation-inventory-kpi-grid, .automation-inventory-kpi-grid,
.automation-inventory-command-grid, .automation-inventory-command-grid,