feat(ai): 新增 P2-407 報表 no-write 分析
Some checks failed
Code Review / ai-code-review (push) Successful in 14s
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled
Some checks failed
Code Review / ai-code-review (push) Successful in 14s
CD Pipeline / build-and-deploy (push) Has been cancelled
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / tests (push) Has been cancelled
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled
This commit is contained in:
@@ -47,6 +47,7 @@ import {
|
||||
type AiAgent12AgentWarRoomSnapshot,
|
||||
type AiAgentProfessionalTaskExpansionSnapshot,
|
||||
type AiAgentReceiptReadbackOwnerReviewSnapshot,
|
||||
type AiAgentReportNoWriteAnalysisRuntimeSnapshot,
|
||||
type AiAgentCandidateOperationDryRunEvidenceSnapshot,
|
||||
type AiAgentCriticReviewerResultCaptureSnapshot,
|
||||
type AiAgentDeploymentLayoutSnapshot,
|
||||
@@ -718,6 +719,7 @@ export function AutomationInventoryTab() {
|
||||
const [warRoom, setWarRoom] = useState<AiAgent12AgentWarRoomSnapshot | null>(null)
|
||||
const [professionalTaskExpansion, setProfessionalTaskExpansion] = useState<AiAgentProfessionalTaskExpansionSnapshot | null>(null)
|
||||
const [receiptReadbackOwnerReview, setReceiptReadbackOwnerReview] = useState<AiAgentReceiptReadbackOwnerReviewSnapshot | null>(null)
|
||||
const [reportNoWriteAnalysisRuntime, setReportNoWriteAnalysisRuntime] = useState<AiAgentReportNoWriteAnalysisRuntimeSnapshot | null>(null)
|
||||
const [proactiveOperations, setProactiveOperations] = useState<AiAgentProactiveOperationsContractSnapshot | null>(null)
|
||||
const [interactionLearningProof, setInteractionLearningProof] = useState<AiAgentInteractionLearningProofSnapshot | null>(null)
|
||||
const [liveReadModelGate, setLiveReadModelGate] = useState<AiAgentLiveReadModelGateSnapshot | null>(null)
|
||||
@@ -809,6 +811,7 @@ export function AutomationInventoryTab() {
|
||||
apiClient.getAiAgent12AgentWarRoom(),
|
||||
apiClient.getAiAgentProfessionalTaskExpansion(),
|
||||
apiClient.getAiAgentReceiptReadbackOwnerReview(),
|
||||
apiClient.getAiAgentReportNoWriteAnalysisRuntime(),
|
||||
apiClient.getAiAgentProactiveOperationsContract(),
|
||||
apiClient.getAiAgentInteractionLearningProof(),
|
||||
apiClient.getAiAgentLiveReadModelGate(),
|
||||
@@ -893,6 +896,7 @@ export function AutomationInventoryTab() {
|
||||
warRoomResult,
|
||||
professionalTaskExpansionResult,
|
||||
receiptReadbackOwnerReviewResult,
|
||||
reportNoWriteAnalysisRuntimeResult,
|
||||
proactiveOperationsResult,
|
||||
interactionLearningProofResult,
|
||||
liveReadModelGateResult,
|
||||
@@ -974,6 +978,7 @@ export function AutomationInventoryTab() {
|
||||
setWarRoom(warRoomResult.status === 'fulfilled' ? warRoomResult.value : null)
|
||||
setProfessionalTaskExpansion(professionalTaskExpansionResult.status === 'fulfilled' ? professionalTaskExpansionResult.value : null)
|
||||
setReceiptReadbackOwnerReview(receiptReadbackOwnerReviewResult.status === 'fulfilled' ? receiptReadbackOwnerReviewResult.value : null)
|
||||
setReportNoWriteAnalysisRuntime(reportNoWriteAnalysisRuntimeResult.status === 'fulfilled' ? reportNoWriteAnalysisRuntimeResult.value : null)
|
||||
setProactiveOperations(proactiveOperationsResult.status === 'fulfilled' ? proactiveOperationsResult.value : null)
|
||||
setInteractionLearningProof(interactionLearningProofResult.status === 'fulfilled' ? interactionLearningProofResult.value : null)
|
||||
setLiveReadModelGate(liveReadModelGateResult.status === 'fulfilled' ? liveReadModelGateResult.value : null)
|
||||
@@ -1057,6 +1062,7 @@ export function AutomationInventoryTab() {
|
||||
warRoomResult,
|
||||
professionalTaskExpansionResult,
|
||||
receiptReadbackOwnerReviewResult,
|
||||
reportNoWriteAnalysisRuntimeResult,
|
||||
proactiveOperationsResult,
|
||||
interactionLearningProofResult,
|
||||
liveReadModelGateResult,
|
||||
@@ -1541,6 +1547,39 @@ export function AutomationInventoryTab() {
|
||||
.slice(0, 5)
|
||||
}, [reportAutomationReview])
|
||||
|
||||
const visibleReportNoWriteRecommendations = useMemo(() => {
|
||||
if (!reportNoWriteAnalysisRuntime) return []
|
||||
const priority = { critical: 0, high: 0, medium: 1, low: 2 } as Record<string, number>
|
||||
return [...reportNoWriteAnalysisRuntime.draft_recommendations]
|
||||
.sort((a, b) => {
|
||||
const left = priority[a.risk_tier] ?? 3
|
||||
const right = priority[b.risk_tier] ?? 3
|
||||
if (left !== right) return left - right
|
||||
if (a.approval_required !== b.approval_required) {
|
||||
return a.approval_required ? -1 : 1
|
||||
}
|
||||
return b.actionability_score - a.actionability_score
|
||||
})
|
||||
.slice(0, 6)
|
||||
}, [reportNoWriteAnalysisRuntime])
|
||||
|
||||
const visibleReportNoWriteGates = useMemo(() => {
|
||||
if (!reportNoWriteAnalysisRuntime) return []
|
||||
const statusPriority = { owner_review_required: 0, blocked_by_runtime_gate: 1, draft_ready: 2 } as Record<string, number>
|
||||
const riskPriority = { critical: 0, high: 1, medium: 2, low: 3 } as Record<string, number>
|
||||
return [...reportNoWriteAnalysisRuntime.owner_review_gates]
|
||||
.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.gate_id.localeCompare(b.gate_id)
|
||||
})
|
||||
.slice(0, 4)
|
||||
}, [reportNoWriteAnalysisRuntime])
|
||||
|
||||
const visibleReportRuntimeLanes = useMemo(() => {
|
||||
if (!reportRuntimeReadiness) return []
|
||||
const priority = { blocked_by_runtime_gate: 0, ready_for_owner_review: 1 } as Record<string, number>
|
||||
@@ -2473,7 +2512,7 @@ export function AutomationInventoryTab() {
|
||||
)
|
||||
}
|
||||
|
||||
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !warRoom || !professionalTaskExpansion || !receiptReadbackOwnerReview || !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 || !resultCaptureReleaseDecisionOwnerResponsePreflight || !resultCaptureReleaseDecisionOwnerResponseReadback || !resultCaptureReleaseDecisionOwnerResponseAcceptanceGate || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !dependencySupplyChainDriftMonitor || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
if (error || !snapshot || !backlog || !backupTargets || !backupReadiness || !backupPolicy || !offsiteEscrow || !giteaHealth || !observabilityMatrix || !providerRouteMatrix || !deploymentLayout || !warRoom || !professionalTaskExpansion || !receiptReadbackOwnerReview || !reportNoWriteAnalysisRuntime || !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 || !resultCaptureReleaseDecisionOwnerResponsePreflight || !resultCaptureReleaseDecisionOwnerResponseReadback || !resultCaptureReleaseDecisionOwnerResponseAcceptanceGate || !reportTruthActionabilityReview || !ownerDryRunPackage || !hostStatefulInventory || !dependencySupplyChainDriftMonitor || !serviceHealthGapMatrix || !serviceHealthNotificationPolicy) {
|
||||
return (
|
||||
<div style={{ padding: 20 }}>
|
||||
<GlassCard variant="subtle" padding="lg">
|
||||
@@ -2717,6 +2756,28 @@ export function AutomationInventoryTab() {
|
||||
|| receiptReadbackOwnerReview.activation_boundaries.kubectl_action_enabled,
|
||||
},
|
||||
]
|
||||
const reportNoWriteAnalysisOverall = reportNoWriteAnalysisRuntime.program_status.overall_completion_percent
|
||||
const reportNoWriteSources = reportNoWriteAnalysisRuntime.rollups.source_readback_count
|
||||
const reportNoWriteInputs = reportNoWriteAnalysisRuntime.rollups.report_input_count
|
||||
const reportNoWriteAgentPasses = reportNoWriteAnalysisRuntime.rollups.agent_analysis_pass_count
|
||||
const reportNoWriteRecommendations = reportNoWriteAnalysisRuntime.rollups.draft_recommendation_count
|
||||
const reportNoWriteArtifacts = reportNoWriteAnalysisRuntime.rollups.draft_artifact_count
|
||||
const reportNoWriteGates = reportNoWriteAnalysisRuntime.rollups.owner_review_gate_count
|
||||
const reportNoWriteApprovals = reportNoWriteAnalysisRuntime.rollups.approval_required_recommendation_count
|
||||
const reportNoWriteBlocked = reportNoWriteAnalysisRuntime.rollups.blocked_runtime_action_count
|
||||
const reportNoWriteLiveTotal = (
|
||||
reportNoWriteAnalysisRuntime.rollups.live_report_delivery_count
|
||||
+ reportNoWriteAnalysisRuntime.rollups.live_ai_analysis_count
|
||||
+ reportNoWriteAnalysisRuntime.rollups.telegram_send_count
|
||||
+ reportNoWriteAnalysisRuntime.rollups.gateway_queue_write_count
|
||||
+ reportNoWriteAnalysisRuntime.rollups.bot_api_call_count
|
||||
+ reportNoWriteAnalysisRuntime.rollups.receipt_production_write_count
|
||||
+ reportNoWriteAnalysisRuntime.rollups.production_write_count
|
||||
+ reportNoWriteAnalysisRuntime.rollups.secret_read_count
|
||||
+ reportNoWriteAnalysisRuntime.rollups.paid_api_call_count
|
||||
+ reportNoWriteAnalysisRuntime.rollups.host_write_count
|
||||
+ reportNoWriteAnalysisRuntime.rollups.kubectl_action_count
|
||||
)
|
||||
const reportRuntimeOverall = reportRuntimeReadiness.program_status.overall_completion_percent
|
||||
const reportRuntimeLanes = reportRuntimeReadiness.rollups.runtime_lane_count
|
||||
const reportRuntimeReady = reportRuntimeReadiness.rollups.ready_contract_count
|
||||
@@ -4701,6 +4762,137 @@ export function AutomationInventoryTab() {
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
<GlassCard variant="subtle" padding="md">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 14, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, minWidth: 0 }}>
|
||||
<div style={{
|
||||
width: 38,
|
||||
height: 38,
|
||||
borderRadius: 8,
|
||||
border: '0.5px solid #0f766e35',
|
||||
background: 'rgba(15,118,110,0.08)',
|
||||
color: '#0f766e',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
flexShrink: 0,
|
||||
}}>
|
||||
<BookOpenCheck size={18} />
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 5, minWidth: 0 }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 18, fontWeight: 760, color: '#141413', lineHeight: 1.15, overflowWrap: 'anywhere' }}>
|
||||
{t('reportNoWriteAnalysis.title')}
|
||||
</span>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 11, color: '#5c5a55', lineHeight: 1.55, overflowWrap: 'anywhere' }}>
|
||||
{t('reportNoWriteAnalysis.subtitle', {
|
||||
current: reportNoWriteAnalysisRuntime.program_status.current_task_id,
|
||||
next: reportNoWriteAnalysisRuntime.program_status.next_task_id,
|
||||
recommendations: reportNoWriteRecommendations,
|
||||
blocked: reportNoWriteBlocked,
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', justifyContent: 'flex-end', gap: 6, minWidth: 0 }}>
|
||||
<Chip value={t('reportNoWriteAnalysis.badges.mode')} />
|
||||
<Chip value={t('reportNoWriteAnalysis.badges.room', { room: reportNoWriteAnalysisRuntime.telegram_policy.canonical_room })} muted />
|
||||
<Chip value={t('reportNoWriteAnalysis.badges.live', { count: reportNoWriteLiveTotal })} muted={reportNoWriteLiveTotal === 0} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(112px, 1fr))', gap: 10 }} className="automation-inventory-kpi-grid">
|
||||
<MetricCard label={t('reportNoWriteAnalysis.metrics.overall')} value={`${reportNoWriteAnalysisOverall}%`} tone="ok" icon={<Gauge size={16} />} />
|
||||
<MetricCard label={t('reportNoWriteAnalysis.metrics.sources')} value={reportNoWriteSources} tone="ok" icon={<Database size={16} />} />
|
||||
<MetricCard label={t('reportNoWriteAnalysis.metrics.inputs')} value={reportNoWriteInputs} tone="ok" icon={<FileText size={16} />} />
|
||||
<MetricCard label={t('reportNoWriteAnalysis.metrics.passes')} value={reportNoWriteAgentPasses} tone="ok" icon={<Route size={16} />} />
|
||||
<MetricCard label={t('reportNoWriteAnalysis.metrics.recommendations')} value={reportNoWriteRecommendations} tone="warn" icon={<Target size={16} />} />
|
||||
<MetricCard label={t('reportNoWriteAnalysis.metrics.artifacts')} value={reportNoWriteArtifacts} tone="ok" icon={<Archive size={16} />} />
|
||||
<MetricCard label={t('reportNoWriteAnalysis.metrics.gates')} value={reportNoWriteGates} tone="warn" icon={<UserCheck size={16} />} />
|
||||
<MetricCard label={t('reportNoWriteAnalysis.metrics.approvals')} value={reportNoWriteApprovals} tone={reportNoWriteApprovals > 0 ? 'danger' : 'ok'} icon={<Lock size={16} />} />
|
||||
<MetricCard label={t('reportNoWriteAnalysis.metrics.live')} value={reportNoWriteLiveTotal} tone={reportNoWriteLiveTotal === 0 ? 'ok' : 'danger'} icon={<BellOff size={16} />} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1.25fr) minmax(260px, 0.75fr)', gap: 12 }} className="automation-inventory-visual-grid">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
|
||||
<SmallLabel>{t('reportNoWriteAnalysis.sections.recommendations')}</SmallLabel>
|
||||
{visibleReportNoWriteRecommendations.map(recommendation => {
|
||||
const tone = recommendation.risk_tier === 'high' || recommendation.risk_tier === 'critical' ? 'danger' : recommendation.risk_tier === 'medium' ? 'warn' : 'ok'
|
||||
return (
|
||||
<div key={recommendation.recommendation_id} style={{ padding: 11, border: '0.5px solid #d8e7e3', borderRadius: 7, background: '#fff', display: 'flex', flexDirection: 'column', gap: 7, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 8, flexWrap: 'wrap' }}>
|
||||
<span style={{ fontFamily: 'Syne, sans-serif', fontSize: 13, fontWeight: 760, color: '#141413', overflowWrap: 'anywhere' }}>
|
||||
{redactPublicText(recommendation.display_name)}
|
||||
</span>
|
||||
<Chip value={t(`reportNoWriteAnalysis.riskTiers.${recommendation.risk_tier}` as never)} muted={tone !== 'danger'} />
|
||||
</div>
|
||||
<span style={{ fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#5f5a4f', lineHeight: 1.55, overflowWrap: 'anywhere' }}>
|
||||
{redactPublicText(recommendation.draft_solution)}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
<Chip value={redisDryRunValueLabel('agents', recommendation.owner_agent)} muted />
|
||||
<Chip value={t('reportNoWriteAnalysis.labels.score', { score: recommendation.actionability_score })} />
|
||||
<Chip value={t('reportNoWriteAnalysis.labels.approvalRequired', { value: String(recommendation.approval_required) })} muted={!recommendation.approval_required} />
|
||||
<Chip value={recommendation.blocked_runtime_action} muted />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 0 }}>
|
||||
<div style={{ padding: 12, border: '0.5px solid #d8e7e3', borderRadius: 7, background: '#fbfffd', minWidth: 0 }}>
|
||||
<SmallLabel>{t('reportNoWriteAnalysis.sections.agentPasses')}</SmallLabel>
|
||||
<div style={{ marginTop: 8 }}>
|
||||
{reportNoWriteAnalysisRuntime.agent_analysis_passes.map(pass => (
|
||||
<GateMatrixRow
|
||||
key={pass.agent_id}
|
||||
label={pass.display_name}
|
||||
value={t(`reportNoWriteAnalysis.riskTiers.${pass.highest_risk_tier}` as never)}
|
||||
detail={redactPublicText(pass.summary)}
|
||||
tone={pass.highest_risk_tier === 'high' || pass.highest_risk_tier === 'critical' ? 'danger' : pass.highest_risk_tier === 'medium' ? 'warn' : 'ok'}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #d8e7e3', borderRadius: 7, background: '#fff', minWidth: 0 }}>
|
||||
<SmallLabel>{t('reportNoWriteAnalysis.sections.ownerGates')}</SmallLabel>
|
||||
<div style={{ marginTop: 8 }}>
|
||||
{visibleReportNoWriteGates.map(gate => (
|
||||
<GateMatrixRow
|
||||
key={gate.gate_id}
|
||||
label={gate.display_name}
|
||||
value={gate.status}
|
||||
detail={t('reportNoWriteAnalysis.labels.gateDetail', {
|
||||
owner: gate.owner_agent,
|
||||
fields: gate.required_fields.length,
|
||||
checks: gate.acceptance_checks.length,
|
||||
})}
|
||||
tone={gate.status === 'owner_review_required' ? 'warn' : gate.status === 'blocked_by_runtime_gate' ? 'danger' : 'ok'}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: 12, border: '0.5px solid #d8e7e3', borderRadius: 7, background: '#fff', minWidth: 0 }}>
|
||||
<SmallLabel>{t('reportNoWriteAnalysis.sections.truth')}</SmallLabel>
|
||||
<span style={{ display: 'block', marginTop: 7, fontFamily: "'DM Mono', monospace", fontSize: 10, color: '#5f5a4f', lineHeight: 1.55, overflowWrap: 'anywhere' }}>
|
||||
{redactPublicText(reportNoWriteAnalysisRuntime.analysis_truth.truth_note)}
|
||||
</span>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginTop: 9 }}>
|
||||
<Chip value={t('reportNoWriteAnalysis.labels.generated', {
|
||||
generated: formatDateTime(reportNoWriteAnalysisRuntime.generated_at),
|
||||
})} muted />
|
||||
<Chip value={t('reportNoWriteAnalysis.labels.env', { value: reportNoWriteAnalysisRuntime.telegram_policy.canonical_room_env })} muted />
|
||||
<Chip value={t('reportNoWriteAnalysis.labels.redaction', { value: String(reportNoWriteAnalysisRuntime.display_redaction_contract.redaction_required) })} muted />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
<GlassCard variant="subtle" padding="md">
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 14, minWidth: 0 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
|
||||
|
||||
Reference in New Issue
Block a user