diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index bc4ea0306..b7634b84b 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -2220,9 +2220,22 @@ "errorTitle": "知識條目入口需重讀", "errorDescription": "知識條目入口回應:{reason}。頁面會保留 AI source-backed KM、Hermes 受控覆核與陳舊 KM 狀態,避免誤判成知識庫歸零。", "sourceBackedTitle": "AI source-backed KM 已接管", + "sourceBackedSummary": "資料未歸零", "sourceBackedDescription": "Primary KM DB readback 正在受控修復;目前顯示 source-backed 條目、分類與資產 taxonomy,不是知識庫歸零。原因:{reason};階段:{stage};下一步:{next}。", "degradedTitle": "知識條目讀取降級", + "degradedSummary": "Primary readback 降級;列表保留可用資料。", "degradedDescription": "主知識條目 API 已回 degraded:{stage};下一步:{next}。目前列表不視為真實歸零,AI 受控修復隊列與 RAG / PlayBook readback 仍會保留。", + "mode": { + "sourceBacked": "接管" + }, + "chip": { + "mode": "模式", + "reason": "原因", + "stage": "階段", + "next": "下一步", + "entries": "條目", + "taxonomy": "分類 / 資產" + }, "retry": "重新讀取" }, "decision": { diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index 74f974e91..ccf5b91e7 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -2220,9 +2220,22 @@ "errorTitle": "知識條目入口需重讀", "errorDescription": "知識條目入口回應:{reason}。頁面會保留 AI source-backed KM、Hermes 受控覆核與陳舊 KM 狀態,避免誤判成知識庫歸零。", "sourceBackedTitle": "AI source-backed KM 已接管", + "sourceBackedSummary": "資料未歸零", "sourceBackedDescription": "Primary KM DB readback 正在受控修復;目前顯示 source-backed 條目、分類與資產 taxonomy,不是知識庫歸零。原因:{reason};階段:{stage};下一步:{next}。", "degradedTitle": "知識條目讀取降級", + "degradedSummary": "Primary readback 降級;列表保留可用資料。", "degradedDescription": "主知識條目 API 已回 degraded:{stage};下一步:{next}。目前列表不視為真實歸零,AI 受控修復隊列與 RAG / PlayBook readback 仍會保留。", + "mode": { + "sourceBacked": "接管" + }, + "chip": { + "mode": "模式", + "reason": "原因", + "stage": "階段", + "next": "下一步", + "entries": "條目", + "taxonomy": "分類 / 資產" + }, "retry": "重新讀取" }, "decision": { diff --git a/apps/web/src/app/[locale]/knowledge-base/page.tsx b/apps/web/src/app/[locale]/knowledge-base/page.tsx index 2821f1923..3cf92d620 100644 --- a/apps/web/src/app/[locale]/knowledge-base/page.tsx +++ b/apps/web/src/app/[locale]/knowledge-base/page.tsx @@ -438,6 +438,18 @@ const humanizeSignalTag = (tag: string) => { .join(' ') } +const compactReadbackToken = (value: string | null | undefined) => { + if (!value) return '--' + if (value === 'primary_km_db_timeout_or_pool_exhausted') return 'DB pool' + if (value === 'knowledge_readback_source_backed_ai_controlled_repair') return '接管' + if (value === 'repair_primary_km_db_readback_then_promote_source_backed_receipts_to_persistent_km') return '修復 KM' + if (value === 'primary_km_taxonomy_readback_degraded') return 'Taxonomy 降級' + if (value === 'knowledge_primary_entries_ready_taxonomy_degraded') return 'Primary 可讀' + if (value === 'repair_primary_km_taxonomy_readback_without_hiding_entries') return '修復 taxonomy' + if (value.startsWith('source_backed')) return '接管' + return humanizeSignalTag(value) +} + const getSignalTags = (entry: KnowledgeEntry) => { const seen = new Set() return entry.tags @@ -698,6 +710,58 @@ export default function KnowledgeBasePage({ (value: number) => value.toLocaleString(localeCode), [localeCode], ) + const readbackNoticeChips = useMemo( + () => [ + { + label: t('dataChain.chip.mode'), + value: isKnowledgeSourceBacked ? t('dataChain.mode.sourceBacked') : compactReadbackToken(readbackStatus), + icon: CheckCircle2, + tone: 'border-status-healthy/20 bg-status-healthy/10 text-status-healthy', + }, + { + label: t('dataChain.chip.reason'), + value: compactReadbackToken(entryReadback?.degraded_reason_code), + icon: Database, + tone: 'border-status-warning/20 bg-status-warning/10 text-status-warning', + }, + { + label: t('dataChain.chip.stage'), + value: compactReadbackToken(entryReadback?.operator_stage), + icon: PlayCircle, + tone: 'border-claw-blue/20 bg-claw-blue/8 text-claw-blue', + }, + { + label: t('dataChain.chip.next'), + value: compactReadbackToken(entryReadback?.next_step), + icon: ArrowRight, + tone: 'border-nothing-gray-200 bg-white text-secondary', + }, + { + label: t('dataChain.chip.entries'), + value: formatCount(total), + icon: BookOpen, + tone: 'border-claw-blue/20 bg-white text-claw-blue', + }, + { + label: t('dataChain.chip.taxonomy'), + value: `${formatCount(categories.length)} / ${formatCount(assetTaxonomy.length)}`, + icon: Tag, + tone: 'border-purple-200 bg-purple-50 text-purple-600', + }, + ], + [ + assetTaxonomy.length, + categories.length, + entryReadback?.degraded_reason_code, + entryReadback?.next_step, + entryReadback?.operator_stage, + formatCount, + isKnowledgeSourceBacked, + readbackStatus, + t, + total, + ], + ) const formatCategoryLabel = useCallback( (category: string) => { if (KNOWN_CATEGORY_KEYS.has(category)) { @@ -1422,33 +1486,44 @@ export default function KnowledgeBasePage({ {(entryFetchError || isKnowledgeListDegraded) && ( -
-
-
-
-