From 6b8edd8ffefb9b5002476b8db16d2917e0c51688 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 2 Jul 2026 00:17:01 +0800 Subject: [PATCH] fix(web): keep autonomous cockpit visible during readback fallback --- .../tabs/automation-inventory-tab.tsx | 269 +++++++++++++++++- 1 file changed, 263 insertions(+), 6 deletions(-) diff --git a/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx b/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx index ac99bd6c..1cd63685 100644 --- a/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx +++ b/apps/web/src/app/[locale]/governance/tabs/automation-inventory-tab.tsx @@ -1084,6 +1084,263 @@ function AutonomyWorkspaceScene({ ) } +function AutonomousRuntimeControlCockpitCard({ + control, + t, +}: { + control: AiAgentAutonomousRuntimeControlSnapshot + t: ReturnType +}) { + const rollups = control.rollups + const runtimeReadback = control.runtime_receipt_readback + const loopLedger = runtimeReadback?.autonomous_execution_loop_ledger + const loopClosed = (rollups.live_autonomous_execution_loop_closed_count ?? 0) > 0 || Boolean(loopLedger?.closed) + const stages = loopLedger?.stages ?? [] + const stageById = new Map(stages.map(stage => [stage.stage_id, stage])) + const flowRows = [ + { key: 'candidate', stage: stageById.get('candidate'), label: t('globalControl.currentAutonomy.flow.candidate'), icon: }, + { key: 'checkMode', stage: stageById.get('check_mode'), label: t('globalControl.currentAutonomy.flow.checkMode'), icon: }, + { key: 'apply', stage: stageById.get('controlled_apply'), label: t('globalControl.currentAutonomy.flow.apply'), icon: }, + { key: 'verifier', stage: stageById.get('post_apply_verifier'), label: t('globalControl.currentAutonomy.flow.verifier'), icon: }, + { key: 'learning', stage: stageById.get('km_learning_writeback'), label: t('globalControl.currentAutonomy.flow.learning'), icon: }, + { key: 'telegram', stage: stageById.get('telegram_receipt'), label: t('globalControl.currentAutonomy.flow.telegram'), icon: }, + ] + const receiptStats = [ + { + key: 'apply', + label: t('globalControl.currentAutonomy.cockpit.apply'), + value: rollups.live_ansible_apply_executed_count ?? 0, + detail: t('globalControl.currentAutonomy.cockpit.receiptDetail'), + tone: (rollups.live_ansible_apply_executed_count ?? 0) > 0 ? 'ok' as const : 'warn' as const, + icon: , + }, + { + key: 'verifier', + label: t('globalControl.currentAutonomy.cockpit.verifier'), + value: rollups.live_post_apply_verifier_count ?? 0, + detail: t('globalControl.currentAutonomy.cockpit.verifierDetail'), + tone: (rollups.live_post_apply_verifier_count ?? 0) > 0 ? 'ok' as const : 'warn' as const, + icon: , + }, + { + key: 'km', + label: t('globalControl.currentAutonomy.cockpit.km'), + value: rollups.live_km_writeback_count ?? 0, + detail: t('globalControl.currentAutonomy.cockpit.kmDetail'), + tone: (rollups.live_km_writeback_count ?? 0) > 0 ? 'ok' as const : 'warn' as const, + icon: , + }, + { + key: 'telegram', + label: t('globalControl.currentAutonomy.cockpit.telegram'), + value: rollups.live_telegram_receipt_count ?? 0, + detail: t('globalControl.currentAutonomy.cockpit.telegramDetail'), + tone: (rollups.live_telegram_receipt_count ?? 0) > 0 ? 'ok' as const : 'warn' as const, + icon: , + }, + ] + + return ( + +
+
+
+
+ +
+
+ {t('globalControl.currentAutonomy.cockpit.liveLabel')} + + {t('globalControl.currentAutonomy.cockpit.title')} + + + {t('globalControl.currentAutonomy.cockpit.subtitle')} + +
+
+
+ + + + +
+
+ + + +
+
+
+ {t('globalControl.currentAutonomy.metrics.completion')} + +
+ + {control.program_status.implementation_completion_percent}% + +
+
+
+ + {control.program_status.deploy_readback_marker} + +
+
+ {receiptStats.map(stat => ( + + ))} +
+
+ +
+
+ {t('globalControl.currentAutonomy.cockpit.loopTitle')} + +
+
+ {flowRows.map(row => ( + + ))} +
+
+
+ + + ) +} + function AutonomousRuntimeControlReadbackGrid({ control, t, @@ -3370,7 +3627,10 @@ export function AutomationInventoryTab() { if (loading) { if (reportTruthActionabilityReview) { return ( -
+
+ {autonomousRuntimeControl ? ( + + ) : null}
@@ -3390,9 +3650,6 @@ export function AutomationInventoryTab() { t={t} pendingReadModelCount={1} /> - {autonomousRuntimeControl ? ( - - ) : null} {t('readModelPartial.boundary')} @@ -3416,9 +3673,9 @@ export function AutomationInventoryTab() { if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !warRoom || !professionalTaskExpansion || !receiptReadbackOwnerReview || !reportNoWriteAnalysisRuntime || !lowMediumRiskWhitelist || !highRiskOwnerReviewQueue || !controlledExecutorHandoff || !actionAuditLedger || !actionOwnerAcceptanceEventBus || !hostRunawayAiops || !proactiveOperations || !versionLifecycleProposal || !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 || !resultCaptureReleaseDecisionOwnerResponsePreflight || !resultCaptureReleaseDecisionOwnerResponseReadback || !resultCaptureReleaseDecisionOwnerResponseAcceptanceGate || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !dependencySupplyChainDriftMonitor || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) { return ( -
+
{autonomousRuntimeControl ? ( - + ) : null}