diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json index 21a76e4bb..887fb6451 100644 --- a/apps/web/messages/en.json +++ b/apps/web/messages/en.json @@ -3950,6 +3950,10 @@ "ansibleLine": "Ansible candidates={candidates}; apply={applied}; reason={reason}", "kmLine": "KM entries={count}", "operator": { + "fallbackMcpSummary": "Status chain batch is catching up; MCP evidence {count}, route={route}", + "fallbackMissingChain": "Status chain batch is catching up; using run evidence first", + "nextStatusChain": "Wait for status-chain batch, or open the incident detail", + "statusChainPending": "status_chain_pending", "statuses": { "needsHuman": "Needs human", "failed": "Execution failed", diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json index a1d1a6247..3dba08d3e 100644 --- a/apps/web/messages/zh-TW.json +++ b/apps/web/messages/zh-TW.json @@ -3950,6 +3950,10 @@ "ansibleLine": "Ansible candidates={candidates}; apply={applied}; reason={reason}", "kmLine": "KM entries={count}", "operator": { + "fallbackMcpSummary": "狀態鏈批次回補中;目前可見 MCP 證據 {count} 筆,route={route}", + "fallbackMissingChain": "狀態鏈批次回補中;先用 Run 證據判讀", + "nextStatusChain": "等待狀態鏈批次回補,或打開 Incident 詳情確認", + "statusChainPending": "status_chain_pending", "statuses": { "needsHuman": "需人工", "failed": "執行失敗", diff --git a/apps/web/src/app/[locale]/awooop/runs/page.tsx b/apps/web/src/app/[locale]/awooop/runs/page.tsx index f0e63bb38..3405d299c 100644 --- a/apps/web/src/app/[locale]/awooop/runs/page.tsx +++ b/apps/web/src/app/[locale]/awooop/runs/page.tsx @@ -1758,10 +1758,12 @@ function shortValue(value?: string | number | boolean | null) { function SourceFlowCell({ chain, + summary, hasIncident, loading, }: { chain?: AwoooPStatusChain | null; + summary?: RemediationSummary | null; hasIncident: boolean; loading: boolean; }) { @@ -1775,22 +1777,41 @@ function SourceFlowCell({ const ansible = chain?.execution?.ansible; const firstBlocker = chain?.blockers?.[0]; const nextAction = outcome?.next_action ?? chain?.next_step; + const fallbackMcpTotal = summary?.mcp_observation_total ?? summary?.evidence_total ?? 0; + const fallbackMcpSuccess = summary?.mcp_observation_success ?? (summary?.has_mcp_investigation ? fallbackMcpTotal : 0); + const fallbackMcpFailed = summary?.mcp_observation_failed ?? 0; + const hasChain = Boolean(chain); + const shouldShowOperatorFallback = hasChain || hasIncident; const outcomeSummary = outcome?.summary_zh ?? executionResult?.summary_zh - ?? (chain ? `${shortValue(chain.current_stage)} / ${shortValue(chain.stage_status)}` : null); + ?? (chain + ? `${shortValue(chain.current_stage)} / ${shortValue(chain.stage_status)}` + : summary?.has_mcp_investigation + ? t("operator.fallbackMcpSummary", { + count: fallbackMcpTotal, + route: shortValue(summary.latest_route), + }) + : hasIncident + ? t("operator.fallbackMissingChain") + : null); const blockerLine = firstBlocker ? t("blockedLine", { blocker: firstBlocker }) - : t("nextLine", { next: shortValue(nextAction) }); + : t("nextLine", { + next: shortValue( + nextAction + ?? (hasChain ? chain?.next_step : t("operator.nextStatusChain")) + ), + }); const mcpLine = t("mcpLine", { - success: gateway?.success ?? 0, - total: gateway?.total ?? 0, - failed: gateway?.failed ?? 0, + success: gateway?.success ?? fallbackMcpSuccess, + total: gateway?.total ?? fallbackMcpTotal, + failed: gateway?.failed ?? fallbackMcpFailed, blocked: gateway?.blocked ?? 0, }); const ansibleLine = t("ansibleLine", { candidates: ansible?.candidate_count ?? 0, applied: ansible?.apply_total ?? 0, - reason: shortValue(ansible?.not_used_reason), + reason: shortValue(ansible?.not_used_reason ?? (!hasChain && hasIncident ? t("operator.statusChainPending") : null)), }); const kmLine = t("kmLine", { count: chain?.evidence?.knowledge_entries ?? 0, @@ -1829,7 +1850,7 @@ function SourceFlowCell({
{detail}
- {chain && ( + {shouldShowOperatorFallback && ( <>{shortValue(outcomeSummary)} @@ -1907,6 +1928,7 @@ function RunRow({