fix(web): keep run status readable without chain batch
Some checks failed
CD Pipeline / tests (push) Successful in 1m28s
Code Review / ai-code-review (push) Successful in 14s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled

This commit is contained in:
Your Name
2026-06-04 19:42:12 +08:00
parent 9a965b666b
commit 8ad8bf48b5
3 changed files with 37 additions and 7 deletions

View File

@@ -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",

View File

@@ -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": "執行失敗",

View File

@@ -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({
<p className="mt-1 truncate font-mono text-xs text-[#77736a]" title={detail}>
{detail}
</p>
{chain && (
{shouldShowOperatorFallback && (
<>
<p className="mt-1 truncate text-xs font-semibold text-[#141413]" title={shortValue(outcomeSummary)}>
{shortValue(outcomeSummary)}
@@ -1907,6 +1928,7 @@ function RunRow({
<td className="px-4 py-3">
<SourceFlowCell
chain={statusChain}
summary={run.remediation_summary}
hasIncident={incidentIds.length > 0}
loading={sourceFlowLoading}
/>