fix(drift): render interpretation objects safely
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
CD Pipeline / tests (push) Successful in 1m13s
CD Pipeline / build-and-deploy (push) Successful in 3m37s
CD Pipeline / post-deploy-checks (push) Successful in 1m28s

This commit is contained in:
Your Name
2026-05-19 00:55:55 +08:00
parent fa9d2a5d5f
commit 69ed35fb5e

View File

@@ -29,8 +29,8 @@ interface DriftReport {
high_count: number
medium_count: number
info_count: number
interpretation: string | null
status: 'pending' | 'acknowledged' | 'rolled_back' | 'adopted' | 'ignored'
interpretation: DriftInterpretationValue
status: 'pending' | 'resolved' | 'acknowledged' | 'rolled_back' | 'adopted' | 'ignored'
created_at: string
resolved_at: string | null
}
@@ -42,9 +42,19 @@ interface ScanResult {
medium_count: number
info_count: number
has_critical_drift: boolean
interpretation: string | null
interpretation: DriftInterpretationValue
}
type DriftInterpretationValue =
| string
| {
intent?: string | null
explanation?: string | null
risk?: string | null
confidence?: number | null
}
| null
interface DriftFingerprintState {
namespace?: string
fingerprint?: string
@@ -98,6 +108,19 @@ const fmtTime = (iso: string) => {
}
}
const formatInterpretation = (value: DriftInterpretationValue) => {
if (!value) return null
if (typeof value === 'string') return value
const meta = [
value.intent,
value.risk,
typeof value.confidence === 'number' ? `${Math.round(value.confidence * 100)}%` : null,
].filter(Boolean).join(' / ')
const explanation = value.explanation || ''
if (meta && explanation) return `${meta}${explanation}`
return meta || explanation || null
}
// =============================================================================
// Sub-components
// =============================================================================
@@ -140,6 +163,7 @@ function DriftLevelBadge({ high, medium, info, t }: {
function StatusBadge({ status, t }: { status: DriftReport['status']; t: (k: string) => string }) {
const styles: Record<string, string> = {
pending: 'bg-status-warning/10 text-status-warning border-status-warning/20',
resolved: 'bg-status-healthy/10 text-status-healthy border-status-healthy/20',
acknowledged: 'bg-neutral-100 text-neutral-500 border-neutral-200',
rolled_back: 'bg-status-healthy/10 text-status-healthy border-status-healthy/20',
adopted: 'bg-status-healthy/10 text-status-healthy border-status-healthy/20',
@@ -340,9 +364,9 @@ export function DriftPanel() {
</span>
)}
</div>
{scanResult.interpretation && (
{formatInterpretation(scanResult.interpretation) && (
<p className="mt-1.5 text-neutral-600 font-normal pl-5">
{scanResult.interpretation}
{formatInterpretation(scanResult.interpretation)}
</p>
)}
</div>
@@ -397,9 +421,9 @@ export function DriftPanel() {
</span>
</div>
</div>
{report.interpretation && (
{formatInterpretation(report.interpretation) && (
<p className="mt-2 text-[11px] text-neutral-500 pl-1 border-l-2 border-neutral-100">
{report.interpretation}
{formatInterpretation(report.interpretation)}
</p>
)}
<div className="flex items-center gap-4 mt-2 text-[10px] text-neutral-400">