feat(governance): 新增 result capture writer dry-run readback
This commit is contained in:
@@ -71,6 +71,7 @@ import {
|
||||
type AiAgentResultCapturePromotionApprovalGateSnapshot,
|
||||
type AiAgentResultCaptureWriteGateReviewSnapshot,
|
||||
type AiAgentResultCaptureWriterDryRunFixtureSnapshot,
|
||||
type AiAgentResultCaptureWriterDryRunReadbackSnapshot,
|
||||
type AiAgentResultCaptureWriterImplementationReviewSnapshot,
|
||||
type AiAgentOwnerApprovedFixturePromotionGateSnapshot,
|
||||
type AiAgentRuntimeWorkerShadowGateSnapshot,
|
||||
@@ -465,6 +466,7 @@ export function AutomationInventoryTab() {
|
||||
const [resultCaptureWriteGateReview, setResultCaptureWriteGateReview] = useState<AiAgentResultCaptureWriteGateReviewSnapshot | null>(null)
|
||||
const [resultCaptureWriterImplementationReview, setResultCaptureWriterImplementationReview] = useState<AiAgentResultCaptureWriterImplementationReviewSnapshot | null>(null)
|
||||
const [resultCaptureWriterDryRunFixture, setResultCaptureWriterDryRunFixture] = useState<AiAgentResultCaptureWriterDryRunFixtureSnapshot | null>(null)
|
||||
const [resultCaptureWriterDryRunReadback, setResultCaptureWriterDryRunReadback] = useState<AiAgentResultCaptureWriterDryRunReadbackSnapshot | null>(null)
|
||||
const [reportTruthActionabilityReview, setReportTruthActionabilityReview] = useState<AiAgentReportTruthActionabilityReviewSnapshot | null>(null)
|
||||
const [ownerDryRunPackage, setOwnerDryRunPackage] = useState<AiAgentOwnerApprovedFixtureDryRunSnapshot | null>(null)
|
||||
const [hostStatefulInventory, setHostStatefulInventory] = useState<AiAgentHostStatefulVersionInventorySnapshot | null>(null)
|
||||
@@ -525,6 +527,7 @@ export function AutomationInventoryTab() {
|
||||
apiClient.getAiAgentResultCaptureWriteGateReview(),
|
||||
apiClient.getAiAgentResultCaptureWriterImplementationReview(),
|
||||
apiClient.getAiAgentResultCaptureWriterDryRunFixture(),
|
||||
apiClient.getAiAgentResultCaptureWriterDryRunReadback(),
|
||||
apiClient.getAiAgentReportTruthActionabilityReview(),
|
||||
apiClient.getAiAgentOwnerApprovedFixtureDryRun(),
|
||||
apiClient.getAiAgentHostStatefulVersionInventory(),
|
||||
@@ -584,6 +587,7 @@ export function AutomationInventoryTab() {
|
||||
resultCaptureWriteGateReviewResult,
|
||||
resultCaptureWriterImplementationReviewResult,
|
||||
resultCaptureWriterDryRunFixtureResult,
|
||||
resultCaptureWriterDryRunReadbackResult,
|
||||
reportTruthActionabilityReviewResult,
|
||||
ownerDryRunPackageResult,
|
||||
hostStatefulInventoryResult,
|
||||
@@ -640,6 +644,7 @@ export function AutomationInventoryTab() {
|
||||
setResultCaptureWriteGateReview(resultCaptureWriteGateReviewResult.status === 'fulfilled' ? resultCaptureWriteGateReviewResult.value : null)
|
||||
setResultCaptureWriterImplementationReview(resultCaptureWriterImplementationReviewResult.status === 'fulfilled' ? resultCaptureWriterImplementationReviewResult.value : null)
|
||||
setResultCaptureWriterDryRunFixture(resultCaptureWriterDryRunFixtureResult.status === 'fulfilled' ? resultCaptureWriterDryRunFixtureResult.value : null)
|
||||
setResultCaptureWriterDryRunReadback(resultCaptureWriterDryRunReadbackResult.status === 'fulfilled' ? resultCaptureWriterDryRunReadbackResult.value : null)
|
||||
setReportTruthActionabilityReview(reportTruthActionabilityReviewResult.status === 'fulfilled' ? reportTruthActionabilityReviewResult.value : null)
|
||||
setOwnerDryRunPackage(ownerDryRunPackageResult.status === 'fulfilled' ? ownerDryRunPackageResult.value : null)
|
||||
setHostStatefulInventory(hostStatefulInventoryResult.status === 'fulfilled' ? hostStatefulInventoryResult.value : null)
|
||||
@@ -694,6 +699,7 @@ export function AutomationInventoryTab() {
|
||||
resultCaptureWriteGateReviewResult,
|
||||
resultCaptureWriterImplementationReviewResult,
|
||||
resultCaptureWriterDryRunFixtureResult,
|
||||
resultCaptureWriterDryRunReadbackResult,
|
||||
reportTruthActionabilityReviewResult,
|
||||
ownerDryRunPackageResult,
|
||||
hostStatefulInventoryResult,
|
||||
@@ -1936,7 +1942,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 || !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 || !runtimeReadbackImplementationReview || !reportLiveDeliveryApprovalPackage || !runtimeReadbackFixtureApproval || !runtimeReadbackPromotionGate || !ownerApprovedFixturePromotionGate || !canonicalRuntimeReadbackOwnerAcceptance || !failureReceiptNoSendReplay || !reviewerQueueNoWriteReadback || !resultCaptureNoWriteReadback || !resultCapturePromotionApprovalGate || !ownerApprovedResultCapturePromotionDryRun || !resultCaptureWriteGateReview || !resultCaptureWriterImplementationReview || !resultCaptureWriterDryRunFixture || !resultCaptureWriterDryRunReadback || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
return (
|
||||
<div style={{ padding: 20 }}>
|
||||
<GlassCard variant="subtle" padding="lg">
|
||||
@@ -2745,6 +2751,40 @@ export function AutomationInventoryTab() {
|
||||
+ resultCaptureWriterDryRunFixture.rollups.playbook_trust_write_count
|
||||
+ resultCaptureWriterDryRunFixture.rollups.production_write_count
|
||||
)
|
||||
const resultCaptureWriterReadbackOverall = resultCaptureWriterDryRunReadback.program_status.overall_completion_percent
|
||||
const resultCaptureWriterReadbackCards = resultCaptureWriterDryRunReadback.rollups.dry_run_readback_card_count
|
||||
const resultCaptureWriterReadbackVerifiers = resultCaptureWriterDryRunReadback.rollups.receipt_verifier_check_count
|
||||
const resultCaptureWriterReadbackPromotionGates = resultCaptureWriterDryRunReadback.rollups.promotion_readiness_gate_count
|
||||
const resultCaptureWriterReadbackBlockers = resultCaptureWriterDryRunReadback.rollups.blocked_promotion_write_count
|
||||
const resultCaptureWriterReadbackActions = resultCaptureWriterDryRunReadback.rollups.operator_action_count
|
||||
const resultCaptureWriterReadbackApprovalRequired = (
|
||||
resultCaptureWriterDryRunReadback.rollups.approval_required_readback_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.approval_required_verifier_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.approval_required_gate_count
|
||||
)
|
||||
const resultCaptureWriterReadbackBlocked = (
|
||||
resultCaptureWriterDryRunReadback.rollups.blocked_readback_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.blocked_verifier_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.blocked_gate_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.critical_blocker_count
|
||||
)
|
||||
const resultCaptureWriterReadbackLiveWrites = (
|
||||
resultCaptureWriterDryRunReadback.rollups.writer_apply_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.dry_run_execution_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.receipt_write_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.promotion_apply_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.canonical_runtime_target_read_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.live_query_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.reviewer_queue_write_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.gateway_queue_write_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.telegram_send_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.bot_api_call_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.report_receipt_write_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.result_capture_write_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.learning_write_count
|
||||
+ resultCaptureWriterDryRunReadback.rollups.playbook_trust_write_count
|
||||
+ resultCaptureWriterDryRunReadback.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
|
||||
@@ -7294,6 +7334,110 @@ export function AutomationInventoryTab() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #aebfd8', borderRadius: 7, background: '#f8fbff', 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: '#275e9c' }} />
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 700, color: '#141413' }}>
|
||||
{t('resultCaptureWriterDryRunReadback.title')}
|
||||
</span>
|
||||
</div>
|
||||
<Chip
|
||||
value={t('resultCaptureWriterDryRunReadback.source', {
|
||||
generated: formatDateTime(resultCaptureWriterDryRunReadback.generated_at),
|
||||
current: resultCaptureWriterDryRunReadback.program_status.current_task_id,
|
||||
next: resultCaptureWriterDryRunReadback.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('resultCaptureWriterDryRunReadback.metrics.overall')} value={`${resultCaptureWriterReadbackOverall}%`} tone="ok" icon={<Gauge size={16} />} />
|
||||
<MetricCard label={t('resultCaptureWriterDryRunReadback.metrics.readbacks')} value={resultCaptureWriterReadbackCards} tone="warn" icon={<Layers3 size={16} />} />
|
||||
<MetricCard label={t('resultCaptureWriterDryRunReadback.metrics.verifiers')} value={resultCaptureWriterReadbackVerifiers} tone="warn" icon={<ShieldCheck size={16} />} />
|
||||
<MetricCard label={t('resultCaptureWriterDryRunReadback.metrics.promotionGates')} value={resultCaptureWriterReadbackPromotionGates} tone="warn" icon={<Lock size={16} />} />
|
||||
<MetricCard label={t('resultCaptureWriterDryRunReadback.metrics.blockers')} value={resultCaptureWriterReadbackBlockers} tone="danger" icon={<AlertTriangle size={16} />} />
|
||||
<MetricCard label={t('resultCaptureWriterDryRunReadback.metrics.actions')} value={resultCaptureWriterReadbackActions} tone="warn" icon={<Target size={16} />} />
|
||||
<MetricCard label={t('resultCaptureWriterDryRunReadback.metrics.approvalRequired')} value={resultCaptureWriterReadbackApprovalRequired} tone="warn" icon={<PackageCheck size={16} />} />
|
||||
<MetricCard label={t('resultCaptureWriterDryRunReadback.metrics.blocked')} value={resultCaptureWriterReadbackBlocked} tone="danger" icon={<ShieldAlert size={16} />} />
|
||||
<MetricCard label={t('resultCaptureWriterDryRunReadback.metrics.verifierPass')} value={resultCaptureWriterDryRunReadback.rollups.receipt_verifier_pass_count} tone="warn" icon={<Archive size={16} />} />
|
||||
<MetricCard label={t('resultCaptureWriterDryRunReadback.metrics.liveWrites')} value={resultCaptureWriterReadbackLiveWrites} tone={resultCaptureWriterReadbackLiveWrites === 0 ? 'ok' : 'danger'} icon={<BellOff size={16} />} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 12 }} className="automation-inventory-live-read-grid">
|
||||
<div style={{ padding: 11, border: '0.5px solid #aebfd8', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<SmallLabel>{t('resultCaptureWriterDryRunReadback.priorTitle')}</SmallLabel>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
||||
{resultCaptureWriterDryRunReadback.prior_result_capture_writer_dry_run_fixture.readiness_note}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={resultCaptureWriterDryRunReadback.prior_result_capture_writer_dry_run_fixture.schema_version} />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.metrics.readbacks') + ` ${resultCaptureWriterDryRunReadback.rollups.dry_run_readback_card_count}`} muted />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.metrics.liveWrites') + ` ${resultCaptureWriterDryRunReadback.prior_result_capture_writer_dry_run_fixture.result_capture_write_count}`} muted />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 11, border: '0.5px solid #aebfd8', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0 }}>
|
||||
<SmallLabel>{t('resultCaptureWriterDryRunReadback.truthTitle')}</SmallLabel>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.5, overflowWrap: 'anywhere' }}>
|
||||
{resultCaptureWriterDryRunReadback.readback_truth.truth_note}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.flags.fixtureLoaded', { value: String(resultCaptureWriterDryRunReadback.readback_truth.p2_123_fixture_loaded) })} />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.flags.receiptVerifier', { value: String(resultCaptureWriterDryRunReadback.readback_truth.receipt_verifier_required) })} />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.flags.promotionOwner', { value: String(resultCaptureWriterDryRunReadback.readback_truth.promotion_owner_required) })} />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.labels.writerApply', { value: String(resultCaptureWriterDryRunReadback.rollups.writer_apply_count) })} muted />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.labels.dryRunExecution', { value: String(resultCaptureWriterDryRunReadback.rollups.dry_run_execution_count) })} muted />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.labels.receiptWrite', { value: String(resultCaptureWriterDryRunReadback.rollups.receipt_write_count) })} muted />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.labels.gatewayWrites', { value: String(resultCaptureWriterDryRunReadback.rollups.gateway_queue_write_count) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 10 }} className="automation-inventory-live-read-card-grid">
|
||||
{resultCaptureWriterDryRunReadback.dry_run_readback_cards.slice(0, 5).map(card => (
|
||||
<div key={card.readback_id} style={{ padding: 10, border: '0.5px solid #aebfd8', 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' }}>
|
||||
{card.display_name}
|
||||
</span>
|
||||
<Chip value={card.status} muted={card.status === 'ready_for_owner_review'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{card.source_fixture} → {card.receipt_preview}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', card.owner_agent)} muted />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.labels.promotionCandidate', { value: card.promotion_candidate })} />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.labels.readbackOnly', { value: String(card.readback_only) })} muted />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.labels.runtimeWriteEnabled', { value: String(card.runtime_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">
|
||||
{resultCaptureWriterDryRunReadback.promotion_readiness_gates.slice(0, 5).map(gate => (
|
||||
<div key={gate.gate_id} style={{ padding: 10, border: '0.5px solid #aebfd8', 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={gate.status} muted={gate.status === 'ready_for_owner_review'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#64727a', lineHeight: 1.45, overflowWrap: 'anywhere' }}>
|
||||
{gate.required_evidence}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', gate.owner_agent)} muted />
|
||||
<Chip value={t('resultCaptureWriterDryRunReadback.labels.promotionAllowed', { value: String(gate.promotion_allowed) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #aebfd8', borderRadius: 7, background: '#f8fbff', 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 }}>
|
||||
|
||||
Reference in New Issue
Block a user