feat(governance): 新增 runtime readback 批准包
This commit is contained in:
@@ -57,6 +57,7 @@ import {
|
||||
type AiAgentReportRuntimeFixtureReadbackSnapshot,
|
||||
type AiAgentReportRuntimeReadinessSnapshot,
|
||||
type AiAgentReportTruthActionabilityReviewSnapshot,
|
||||
type AiAgentRuntimeReadbackApprovalPackageSnapshot,
|
||||
type AiAgentRuntimeWorkerShadowGateSnapshot,
|
||||
type AiAgentRuntimeVerifierEvidenceReviewSnapshot,
|
||||
type AiAgentRuntimeWriteGateReviewSnapshot,
|
||||
@@ -434,6 +435,7 @@ export function AutomationInventoryTab() {
|
||||
const [criticReviewerResultCapture, setCriticReviewerResultCapture] = useState<AiAgentCriticReviewerResultCaptureSnapshot | null>(null)
|
||||
const [ownerApprovedResultCaptureDryRun, setOwnerApprovedResultCaptureDryRun] = useState<AiAgentOwnerApprovedResultCaptureDryRunSnapshot | null>(null)
|
||||
const [ownerApprovedResultCaptureReadback, setOwnerApprovedResultCaptureReadback] = useState<AiAgentOwnerApprovedResultCaptureReadbackSnapshot | null>(null)
|
||||
const [runtimeReadbackApprovalPackage, setRuntimeReadbackApprovalPackage] = useState<AiAgentRuntimeReadbackApprovalPackageSnapshot | null>(null)
|
||||
const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState<AiAgentReportTruthActionabilityReviewSnapshot | null>(null)
|
||||
const [ownerDryRunPackage, setOwnerDryRunPackage] = useState<AiAgentOwnerApprovedFixtureDryRunSnapshot | null>(null)
|
||||
const [hostStatefulInventory, setHostStatefulInventory] = useState<AiAgentHostStatefulVersionInventorySnapshot | null>(null)
|
||||
@@ -479,6 +481,7 @@ export function AutomationInventoryTab() {
|
||||
apiClient.getAiAgentCriticReviewerResultCapture(),
|
||||
apiClient.getAiAgentOwnerApprovedResultCaptureDryRun(),
|
||||
apiClient.getAiAgentOwnerApprovedResultCaptureReadback(),
|
||||
apiClient.getAiAgentRuntimeReadbackApprovalPackage(),
|
||||
apiClient.getAiAgentReportTruthActionabilityReview(),
|
||||
apiClient.getAiAgentOwnerApprovedFixtureDryRun(),
|
||||
apiClient.getAiAgentHostStatefulVersionInventory(),
|
||||
@@ -523,6 +526,7 @@ export function AutomationInventoryTab() {
|
||||
criticReviewerResultCaptureResult,
|
||||
ownerApprovedResultCaptureDryRunResult,
|
||||
ownerApprovedResultCaptureReadbackResult,
|
||||
runtimeReadbackApprovalPackageResult,
|
||||
reportTruthActionabilityReviewResult,
|
||||
ownerDryRunPackageResult,
|
||||
hostStatefulInventoryResult,
|
||||
@@ -564,6 +568,7 @@ export function AutomationInventoryTab() {
|
||||
setCriticReviewerResultCapture(criticReviewerResultCaptureResult.status === 'fulfilled' ? criticReviewerResultCaptureResult.value : null)
|
||||
setOwnerApprovedResultCaptureDryRun(ownerApprovedResultCaptureDryRunResult.status === 'fulfilled' ? ownerApprovedResultCaptureDryRunResult.value : null)
|
||||
setOwnerApprovedResultCaptureReadback(ownerApprovedResultCaptureReadbackResult.status === 'fulfilled' ? ownerApprovedResultCaptureReadbackResult.value : null)
|
||||
setRuntimeReadbackApprovalPackage(runtimeReadbackApprovalPackageResult.status === 'fulfilled' ? runtimeReadbackApprovalPackageResult.value : null)
|
||||
setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null)
|
||||
setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null)
|
||||
setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null)
|
||||
@@ -603,6 +608,7 @@ export function AutomationInventoryTab() {
|
||||
criticReviewerResultCaptureResult,
|
||||
ownerApprovedResultCaptureDryRunResult,
|
||||
ownerApprovedResultCaptureReadbackResult,
|
||||
runtimeReadbackApprovalPackageResult,
|
||||
reportTruthActionabilityReviewResult,
|
||||
ownerDryRunPackageResult,
|
||||
hostStatefulInventoryResult,
|
||||
@@ -1484,6 +1490,62 @@ export function AutomationInventoryTab() {
|
||||
.slice(0, 4)
|
||||
}, [ownerApprovedResultCaptureReadback])
|
||||
|
||||
const visibleRuntimeReadbackPackets = useMemo(() => {
|
||||
if (!runtimeReadbackApprovalPackage) return []
|
||||
const statusPriority = { blocked_by_policy: 0, approval_required: 1, ready_for_owner_review: 2 } as Record<string, number>
|
||||
const riskPriority = { critical: 0, high: 1, medium: 2 } as Record<string, number>
|
||||
return [...runtimeReadbackApprovalPackage.approval_packet_templates]
|
||||
.sort((a, b) => {
|
||||
const leftStatus = statusPriority[a.status] ?? 3
|
||||
const rightStatus = statusPriority[b.status] ?? 3
|
||||
if (leftStatus !== rightStatus) return leftStatus - rightStatus
|
||||
const leftRisk = riskPriority[a.risk_tier] ?? 4
|
||||
const rightRisk = riskPriority[b.risk_tier] ?? 4
|
||||
if (leftRisk !== rightRisk) return leftRisk - rightRisk
|
||||
return a.packet_id.localeCompare(b.packet_id)
|
||||
})
|
||||
.slice(0, 5)
|
||||
}, [runtimeReadbackApprovalPackage])
|
||||
|
||||
const visibleRuntimeReadbackPlans = useMemo(() => {
|
||||
if (!runtimeReadbackApprovalPackage) return []
|
||||
const statusPriority = { blocked_by_policy: 0, planned_no_runtime_read: 1 } as Record<string, number>
|
||||
return [...runtimeReadbackApprovalPackage.canonical_readback_plans]
|
||||
.sort((a, b) => {
|
||||
const left = statusPriority[a.status] ?? 2
|
||||
const right = statusPriority[b.status] ?? 2
|
||||
if (left !== right) return left - right
|
||||
return a.plan_id.localeCompare(b.plan_id)
|
||||
})
|
||||
.slice(0, 4)
|
||||
}, [runtimeReadbackApprovalPackage])
|
||||
|
||||
const visibleRuntimeReadbackRollbackLanes = useMemo(() => {
|
||||
if (!runtimeReadbackApprovalPackage) return []
|
||||
const statusPriority = { blocked_by_policy: 0, planned_no_write: 1 } as Record<string, number>
|
||||
return [...runtimeReadbackApprovalPackage.rollback_drill_lanes]
|
||||
.sort((a, b) => {
|
||||
const left = statusPriority[a.status] ?? 2
|
||||
const right = statusPriority[b.status] ?? 2
|
||||
if (left !== right) return left - right
|
||||
return a.lane_id.localeCompare(b.lane_id)
|
||||
})
|
||||
.slice(0, 4)
|
||||
}, [runtimeReadbackApprovalPackage])
|
||||
|
||||
const visibleRuntimeReadbackTelegramGates = useMemo(() => {
|
||||
if (!runtimeReadbackApprovalPackage) return []
|
||||
const statusPriority = { blocked_by_policy: 0, ready_for_owner_review: 1 } as Record<string, number>
|
||||
return [...runtimeReadbackApprovalPackage.telegram_failure_receipt_gates]
|
||||
.sort((a, b) => {
|
||||
const left = statusPriority[a.status] ?? 2
|
||||
const right = statusPriority[b.status] ?? 2
|
||||
if (left !== right) return left - right
|
||||
return a.gate_id.localeCompare(b.gate_id)
|
||||
})
|
||||
.slice(0, 4)
|
||||
}, [runtimeReadbackApprovalPackage])
|
||||
|
||||
const visibleReportTruthFindings = useMemo(() => {
|
||||
if (!reportTruthActionabilityReview) return []
|
||||
const priority = { critical: 0, high: 1, medium: 2, low: 3 } as Record<string, number>
|
||||
@@ -1703,7 +1765,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 || !reportTruthActionabilityReview || !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 || !reportAutomationReview || !reportStatusBoard || !reportRuntimeReadiness || !reportRuntimeDryRun || !reportRuntimeFixtureReadback || !runtimeWorkerShadowGate || !operationPermissionModel || !candidateOperationDryRunEvidence || !taskResultAuditTrail || !matchedPlaybookLearningGap || !criticReviewerResultCapture || !ownerApprovedResultCaptureDryRun || !ownerApprovedResultCaptureReadback || !runtimeReadbackApprovalPackage || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
return (
|
||||
<div style={{ padding: 20 }}>
|
||||
<GlassCard variant="subtle" padding="lg">
|
||||
@@ -2024,6 +2086,35 @@ export function AutomationInventoryTab() {
|
||||
+ ownerApprovedResultCaptureReadback.rollups.telegram_send_count
|
||||
+ ownerApprovedResultCaptureReadback.rollups.production_write_count
|
||||
)
|
||||
const runtimeReadbackPackageOverall = runtimeReadbackApprovalPackage.program_status.overall_completion_percent
|
||||
const runtimeReadbackPackets = runtimeReadbackApprovalPackage.rollups.approval_packet_count
|
||||
const runtimeReadbackPlans = runtimeReadbackApprovalPackage.rollups.canonical_readback_plan_count
|
||||
const runtimeReadbackRollbackLanes = runtimeReadbackApprovalPackage.rollups.rollback_drill_lane_count
|
||||
const runtimeReadbackTelegramGates = runtimeReadbackApprovalPackage.rollups.telegram_failure_receipt_gate_count
|
||||
const runtimeReadbackActions = runtimeReadbackApprovalPackage.rollups.operator_action_count
|
||||
const runtimeReadbackApprovalRequired = runtimeReadbackApprovalPackage.rollups.approval_required_packet_count
|
||||
const runtimeReadbackBlocked = (
|
||||
runtimeReadbackApprovalPackage.rollups.blocked_packet_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.blocked_readback_plan_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.blocked_rollback_lane_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.blocked_telegram_gate_count
|
||||
)
|
||||
const runtimeReadbackOwnerApprovals = runtimeReadbackApprovalPackage.rollups.owner_approval_received_count
|
||||
const runtimeReadbackExecutions = runtimeReadbackApprovalPackage.rollups.runtime_readback_execution_count
|
||||
const runtimeReadbackTelegramSends = runtimeReadbackApprovalPackage.rollups.telegram_failure_receipt_send_count
|
||||
const runtimeReadbackRollbackWrites = runtimeReadbackApprovalPackage.rollups.rollback_work_item_write_count
|
||||
const runtimeReadbackLiveWrites = (
|
||||
runtimeReadbackApprovalPackage.rollups.result_capture_write_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.score_write_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.learning_write_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.playbook_trust_write_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.reviewer_queue_write_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.gateway_queue_write_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.telegram_failure_receipt_send_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.bot_api_call_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.rollback_work_item_write_count
|
||||
+ runtimeReadbackApprovalPackage.rollups.production_write_count
|
||||
)
|
||||
const reportTruthOverall = reportTruthActionabilityReview.program_status.overall_completion_percent
|
||||
const reportTruthFindings = reportTruthActionabilityReview.rollups.zero_signal_finding_count
|
||||
const reportTruthCritical = reportTruthActionabilityReview.rollups.critical_finding_count
|
||||
@@ -4790,6 +4881,187 @@ export function AutomationInventoryTab() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #bbdec8', borderRadius: 7, background: '#f8fffb', 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 }}>
|
||||
<ShieldCheck size={14} style={{ color: '#15803d' }} />
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
|
||||
{t('runtimeReadbackApprovalPackage.title')}
|
||||
</span>
|
||||
</div>
|
||||
<Chip
|
||||
value={t('runtimeReadbackApprovalPackage.source', {
|
||||
generated: formatDateTime(runtimeReadbackApprovalPackage.generated_at),
|
||||
current: runtimeReadbackApprovalPackage.program_status.current_task_id,
|
||||
next: runtimeReadbackApprovalPackage.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('runtimeReadbackApprovalPackage.metrics.overall')} value={`${runtimeReadbackPackageOverall}%`} tone="ok" icon={<Gauge size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.packets')} value={runtimeReadbackPackets} tone="warn" icon={<FileText size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.plans')} value={runtimeReadbackPlans} tone="warn" icon={<Database size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.rollback')} value={runtimeReadbackRollbackLanes} tone="danger" icon={<Route size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.telegramGates')} value={runtimeReadbackTelegramGates} tone="warn" icon={<BellOff size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.actions')} value={runtimeReadbackActions} tone="warn" icon={<Target size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.approvalRequired')} value={runtimeReadbackApprovalRequired} tone="warn" icon={<Lock size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.blocked')} value={runtimeReadbackBlocked} tone="danger" icon={<AlertTriangle size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.ownerApprovals')} value={runtimeReadbackOwnerApprovals} tone="warn" icon={<ShieldCheck size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.executions')} value={runtimeReadbackExecutions} tone={runtimeReadbackExecutions === 0 ? 'ok' : 'danger'} icon={<Gauge size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.telegramSends')} value={runtimeReadbackTelegramSends} tone={runtimeReadbackTelegramSends === 0 ? 'ok' : 'danger'} icon={<BellRing size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.rollbackWrites')} value={runtimeReadbackRollbackWrites} tone={runtimeReadbackRollbackWrites === 0 ? 'ok' : 'danger'} icon={<Database size={16} />} />
|
||||
<MetricCard label={t('runtimeReadbackApprovalPackage.metrics.liveWrites')} value={runtimeReadbackLiveWrites} tone={runtimeReadbackLiveWrites === 0 ? 'ok' : 'danger'} icon={<Database size={16} />} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) minmax(0, 1fr)', gap: 12 }} className="automation-inventory-live-read-grid">
|
||||
<div style={{ padding: 11, border: '0.5px solid #bbdec8', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<SmallLabel>{t('runtimeReadbackApprovalPackage.priorTitle')}</SmallLabel>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
||||
{runtimeReadbackApprovalPackage.prior_readback_readiness.readiness_note}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={runtimeReadbackApprovalPackage.prior_readback_readiness.source_schema_version} />
|
||||
<Chip value={t('ownerApprovedResultCaptureReadback.metrics.digests') + ` ${runtimeReadbackApprovalPackage.prior_readback_readiness.readback_digest_count}`} muted />
|
||||
<Chip value={t('ownerApprovedResultCaptureReadback.metrics.promotionReviews') + ` ${runtimeReadbackApprovalPackage.prior_readback_readiness.promotion_review_count}`} muted />
|
||||
<Chip value={t('ownerApprovedResultCaptureReadback.metrics.liveWrites') + ` ${runtimeReadbackApprovalPackage.prior_readback_readiness.result_capture_write_count}`} muted />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 11, border: '0.5px solid #bbdec8', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<SmallLabel>{t('runtimeReadbackApprovalPackage.truthTitle')}</SmallLabel>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
||||
{runtimeReadbackApprovalPackage.approval_package_truth.truth_note}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.readbackLoaded', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.p2_107_readback_loaded) })} />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.packageReady', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.approval_package_ready) })} />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.canonicalPlan', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.canonical_readback_plan_ready) })} />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.rollbackDrill', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.rollback_drill_ready) })} />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.failureReceipt', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.telegram_failure_receipt_gate_ready) })} />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.canonicalRead', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.canonical_runtime_readback_enabled) })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.resultWrite', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.runtime_result_capture_write_enabled) })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.queueWrite', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.reviewer_queue_write_enabled) })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.telegramSend', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.telegram_failure_receipt_send_enabled) })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.botApi', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.bot_api_call_enabled) })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.flags.rollbackWrite', { value: String(runtimeReadbackApprovalPackage.approval_package_truth.rollback_work_item_write_enabled) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{visibleRuntimeReadbackPackets.map(packet => (
|
||||
<div key={packet.packet_id} style={{ padding: 10, border: '0.5px solid #bbdec8', 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' }}>
|
||||
{packet.display_name}
|
||||
</span>
|
||||
<Chip value={t(`runtimeReadbackApprovalPackage.packetStatuses.${packet.status}` as never)} muted={packet.status === 'ready_for_owner_review'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{packet.operator_guidance}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', packet.owner_agent)} muted />
|
||||
<Chip value={t(`runtimeReadbackApprovalPackage.riskTiers.${packet.risk_tier}` as never)} muted={packet.risk_tier !== 'critical'} />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.approvalFields', { count: packet.required_approval_fields.length })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.blockedActions', { count: packet.blocked_runtime_actions.length })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.runtimeWrite', { value: String(packet.runtime_write_allowed) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{visibleRuntimeReadbackPlans.map(plan => (
|
||||
<div key={plan.plan_id} style={{ padding: 10, border: '0.5px solid #bbdec8', 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' }}>
|
||||
{plan.display_name}
|
||||
</span>
|
||||
<Chip value={t(`runtimeReadbackApprovalPackage.planStatuses.${plan.status}` as never)} muted={plan.status === 'planned_no_runtime_read'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{plan.query_scope}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', plan.owner_agent)} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.requiredFields', { count: plan.required_fields.length })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.redactionChecks', { count: plan.redaction_checks.length })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.liveQuery', { value: String(plan.live_query_enabled) })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.runtimeWrite', { value: String(plan.runtime_write_allowed) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{visibleRuntimeReadbackRollbackLanes.map(lane => (
|
||||
<div key={lane.lane_id} style={{ padding: 10, border: '0.5px solid #bbdec8', 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' }}>
|
||||
{lane.display_name}
|
||||
</span>
|
||||
<Chip value={t(`runtimeReadbackApprovalPackage.rollbackStatuses.${lane.status}` as never)} muted={lane.status === 'planned_no_write'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{lane.failure_if_missing}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', lane.owner_agent)} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.rollbackOwner', { value: lane.rollback_owner })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.requiredSteps', { count: lane.required_steps.length })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.rollbackWrite', { value: String(lane.rollback_write_enabled) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{visibleRuntimeReadbackTelegramGates.map(gate => (
|
||||
<div key={gate.gate_id} style={{ padding: 10, border: '0.5px solid #bbdec8', 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' }}>
|
||||
{gate.display_name}
|
||||
</span>
|
||||
<Chip value={t(`runtimeReadbackApprovalPackage.telegramStatuses.${gate.status}` as never)} muted={gate.status === 'ready_for_owner_review'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{gate.failure_if_missing}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', gate.owner_agent)} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.requiredEvidence', { count: gate.required_evidence.length })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.queueWrite', { value: String(gate.queue_write_enabled) })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.telegramSend', { value: String(gate.telegram_send_enabled) })} muted />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.botApi', { value: String(gate.bot_api_call_enabled) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{runtimeReadbackApprovalPackage.operator_actions.map(action => (
|
||||
<div key={action.action_id} style={{ padding: 10, border: '0.5px solid #bbdec8', 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' }}>
|
||||
{action.display_name}
|
||||
</span>
|
||||
<Chip value={redisDryRunValueLabel('agents', action.owner_agent)} muted />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{action.operator_instruction}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t(`runtimeReadbackApprovalPackage.actionTypes.${action.action_type}` as never)} />
|
||||
<Chip value={t('runtimeReadbackApprovalPackage.labels.runtimeWrite', { value: String(action.runtime_write_allowed) })} muted />
|
||||
</div>
|
||||
</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 }}>
|
||||
|
||||
@@ -440,6 +440,11 @@ export const apiClient = {
|
||||
return handleResponse<AiAgentOwnerApprovedResultCaptureReadbackSnapshot>(res)
|
||||
},
|
||||
|
||||
async getAiAgentRuntimeReadbackApprovalPackage() {
|
||||
const res = await fetch(`${API_BASE_URL}/agents/agent-runtime-readback-approval-package`)
|
||||
return handleResponse<AiAgentRuntimeReadbackApprovalPackageSnapshot>(res)
|
||||
},
|
||||
|
||||
async getAiAgentOwnerApprovedFixtureDryRun() {
|
||||
const res = await fetch(`${API_BASE_URL}/agents/agent-owner-approved-fixture-dry-run`)
|
||||
return handleResponse<AiAgentOwnerApprovedFixtureDryRunSnapshot>(res)
|
||||
@@ -3803,6 +3808,175 @@ export interface AiAgentOwnerApprovedResultCaptureReadbackSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
export interface AiAgentRuntimeReadbackApprovalPackageSnapshot {
|
||||
schema_version: 'ai_agent_runtime_readback_approval_package_v1'
|
||||
generated_at: string
|
||||
program_status: {
|
||||
overall_completion_percent: number
|
||||
current_priority: 'P0' | 'P1' | 'P2' | 'P3'
|
||||
current_task_id: 'P2-109'
|
||||
next_task_id: 'P2-110'
|
||||
read_only_mode: true
|
||||
runtime_authority: 'runtime_readback_approval_package_only_no_live_write'
|
||||
status_note: string
|
||||
}
|
||||
source_refs: string[]
|
||||
prior_readback_readiness: {
|
||||
source_schema_version: 'ai_agent_owner_approved_result_capture_readback_v1'
|
||||
readback_at: string
|
||||
readback_digest_count: number
|
||||
promotion_review_count: number
|
||||
failure_lane_count: number
|
||||
reviewer_queue_preview_count: number
|
||||
operator_action_count: number
|
||||
approval_required_digest_count: number
|
||||
blocked_total_count: number
|
||||
approved_without_execution_meta_24h: number
|
||||
execution_failed_with_matched_24h: number
|
||||
owner_approval_received_count: number
|
||||
readback_digest_generated_count: number
|
||||
promotion_approved_count: number
|
||||
reviewer_queue_write_count: number
|
||||
result_capture_write_count: number
|
||||
score_write_count: number
|
||||
learning_write_count: number
|
||||
playbook_trust_write_count: number
|
||||
gateway_queue_write_count: number
|
||||
telegram_send_count: number
|
||||
production_write_count: number
|
||||
readiness_note: string
|
||||
}
|
||||
approval_package_truth: {
|
||||
p2_107_readback_loaded: true
|
||||
approval_package_ready: true
|
||||
canonical_readback_plan_ready: true
|
||||
rollback_drill_ready: true
|
||||
telegram_failure_receipt_gate_ready: true
|
||||
owner_review_required_before_runtime: true
|
||||
canonical_runtime_readback_enabled: false
|
||||
runtime_result_capture_write_enabled: false
|
||||
runtime_score_write_enabled: false
|
||||
runtime_learning_write_enabled: false
|
||||
playbook_trust_write_enabled: false
|
||||
reviewer_queue_write_enabled: false
|
||||
gateway_queue_write_enabled: false
|
||||
telegram_failure_receipt_send_enabled: false
|
||||
bot_api_call_enabled: false
|
||||
rollback_work_item_write_enabled: false
|
||||
production_write_enabled: false
|
||||
secret_read_enabled: false
|
||||
destructive_operation_enabled: false
|
||||
owner_approval_received_count: number
|
||||
runtime_readback_execution_count: number
|
||||
result_capture_write_count_24h: number
|
||||
score_write_count_24h: number
|
||||
learning_write_count_24h: number
|
||||
playbook_trust_write_count_24h: number
|
||||
reviewer_queue_write_count_24h: number
|
||||
gateway_queue_write_count_24h: number
|
||||
telegram_failure_receipt_send_count_24h: number
|
||||
bot_api_call_count_24h: number
|
||||
rollback_work_item_write_count_24h: number
|
||||
production_write_count_24h: number
|
||||
secret_read_count_24h: number
|
||||
destructive_operation_count_24h: number
|
||||
truth_note: string
|
||||
}
|
||||
approval_packet_templates: Array<{
|
||||
packet_id: string
|
||||
display_name: string
|
||||
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
|
||||
status: 'ready_for_owner_review' | 'approval_required' | 'blocked_by_policy'
|
||||
risk_tier: 'medium' | 'high' | 'critical'
|
||||
required_approval_fields: string[]
|
||||
blocked_runtime_actions: string[]
|
||||
operator_guidance: string
|
||||
approval_required: true
|
||||
runtime_write_allowed: false
|
||||
evidence_hash: string
|
||||
}>
|
||||
canonical_readback_plans: Array<{
|
||||
plan_id: string
|
||||
display_name: string
|
||||
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
|
||||
status: 'planned_no_runtime_read' | 'blocked_by_policy'
|
||||
query_scope: string
|
||||
required_fields: string[]
|
||||
redaction_checks: string[]
|
||||
live_query_enabled: false
|
||||
runtime_write_allowed: false
|
||||
evidence_hash: string
|
||||
}>
|
||||
rollback_drill_lanes: Array<{
|
||||
lane_id: string
|
||||
display_name: string
|
||||
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
|
||||
status: 'planned_no_write' | 'blocked_by_policy'
|
||||
rollback_owner: string
|
||||
required_steps: string[]
|
||||
failure_if_missing: string
|
||||
rollback_write_enabled: false
|
||||
creates_runtime_write: false
|
||||
}>
|
||||
telegram_failure_receipt_gates: Array<{
|
||||
gate_id: string
|
||||
display_name: string
|
||||
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
|
||||
status: 'ready_for_owner_review' | 'blocked_by_policy'
|
||||
required_evidence: string[]
|
||||
failure_if_missing: string
|
||||
queue_write_enabled: false
|
||||
telegram_send_enabled: false
|
||||
bot_api_call_enabled: false
|
||||
evidence_hash: string
|
||||
}>
|
||||
operator_actions: Array<{
|
||||
action_id: string
|
||||
action_type: 'review_approval_package' | 'validate_canonical_plan' | 'review_rollback_drill' | 'review_failure_receipt_gate' | 'reject_or_promote'
|
||||
display_name: string
|
||||
owner_agent: 'openclaw' | 'hermes' | 'nemotron'
|
||||
operator_instruction: string
|
||||
runtime_write_allowed: false
|
||||
}>
|
||||
display_redaction_contract: {
|
||||
redaction_required: true
|
||||
frontend_display_policy: string
|
||||
raw_prompt_display_allowed: false
|
||||
private_reasoning_display_allowed: false
|
||||
secret_value_display_allowed: false
|
||||
raw_telegram_payload_display_allowed: false
|
||||
work_window_transcript_display_allowed: false
|
||||
}
|
||||
rollups: {
|
||||
approval_packet_count: number
|
||||
canonical_readback_plan_count: number
|
||||
rollback_drill_lane_count: number
|
||||
telegram_failure_receipt_gate_count: number
|
||||
operator_action_count: number
|
||||
approval_required_packet_count: number
|
||||
blocked_packet_count: number
|
||||
blocked_readback_plan_count: number
|
||||
blocked_rollback_lane_count: number
|
||||
blocked_telegram_gate_count: number
|
||||
approved_without_execution_meta_24h: number
|
||||
execution_failed_with_matched_24h: number
|
||||
owner_approval_received_count: number
|
||||
runtime_readback_execution_count: number
|
||||
result_capture_write_count: number
|
||||
score_write_count: number
|
||||
learning_write_count: number
|
||||
playbook_trust_write_count: number
|
||||
reviewer_queue_write_count: number
|
||||
gateway_queue_write_count: number
|
||||
telegram_failure_receipt_send_count: number
|
||||
bot_api_call_count: number
|
||||
rollback_work_item_write_count: number
|
||||
production_write_count: number
|
||||
secret_read_count: number
|
||||
destructive_operation_count: number
|
||||
}
|
||||
}
|
||||
|
||||
export interface AiAgentOwnerApprovedFixtureDryRunSnapshot {
|
||||
schema_version: 'ai_agent_owner_approved_fixture_dry_run_v1'
|
||||
generated_at: string
|
||||
|
||||
Reference in New Issue
Block a user