fix(alerts): clarify execution result verdict
Some checks failed
CD Pipeline / tests (push) Successful in 1m17s
Code Review / ai-code-review (push) Successful in 12s
CD Pipeline / build-and-deploy (push) Successful in 4m11s
CD Pipeline / post-deploy-checks (push) Has been cancelled

This commit is contained in:
Your Name
2026-05-31 17:28:41 +08:00
parent c6d1106cfd
commit a21f94ced1
9 changed files with 266 additions and 1 deletions

View File

@@ -1204,6 +1204,11 @@ class ApprovalExecutionService:
if isinstance(outcome.get("notification"), dict)
else {}
)
execution_result = (
outcome.get("execution_result")
if isinstance(outcome.get("execution_result"), dict)
else {}
)
channels = notification.get("channels") if isinstance(notification.get("channels"), list) else []
lines = [
f"{icon} <b>處置結果</b> | <b>{html.escape(title)}</b>",
@@ -1214,6 +1219,12 @@ class ApprovalExecutionService:
f"├ 人工: <code>{'yes' if outcome.get('needs_human') else 'no'}</code>",
f"├ 通知: <code>{html.escape(','.join(str(item) for item in channels) or 'none')}</code>",
f"└ 下一步: <code>{html.escape(str(outcome.get('next_action') or '--'))}</code>",
"🧪 <b>執行判定</b>",
f"├ 完成狀態: <code>{html.escape(str(execution_result.get('completion_status') or 'unknown'))}</code>",
f"├ 指令狀態: <code>{html.escape(str(execution_result.get('command_status') or 'unknown'))}</code>",
f"├ 修復結果: <code>{html.escape(str(execution_result.get('repair_status') or 'unknown'))}</code>",
f"└ 失敗判定: <code>{html.escape(str(execution_result.get('failure_status') or 'unknown'))}</code>",
f"判讀: {html.escape(str(execution_result.get('summary_zh') or '尚未能判定執行是否完成或失敗'))}",
f"⚙️ Action: <code>{html.escape((approval.action or '')[:220])}</code>",
]
if error:

View File

@@ -48,6 +48,140 @@ def _build_notification(
}
def _build_execution_result(
*,
state: str,
verdict: str,
stage: str,
has_repair_execution: bool,
has_nonrepair_operation: bool,
verification: str,
) -> dict[str, Any]:
"""Describe execution completion separately from remediation outcome."""
approval_status = "unknown"
completion_status = "unknown"
command_status = "unknown"
repair_status = "unknown"
failure_status = "unknown"
summary = "尚未能判定執行是否完成或失敗"
terminal = False
if state == "completed_verified":
approval_status = "completed"
completion_status = "completed_verified"
command_status = "succeeded"
repair_status = "verified_repaired"
failure_status = "no_failure"
summary = "已完成:修復指令成功,且驗證通過"
terminal = True
elif state == "execution_failed_manual_required":
approval_status = "completed"
completion_status = "failed"
command_status = "failed"
repair_status = "failed"
failure_status = "command_failed"
summary = "已失敗:修復指令執行失敗,需人工接手"
terminal = True
elif state == "diagnostic_only_manual_review":
approval_status = "completed"
completion_status = "completed_no_repair"
command_status = "diagnostic_completed" if has_nonrepair_operation else "skipped_no_action"
repair_status = "not_executed"
failure_status = "no_command_failed"
summary = "流程已完成:只完成診斷/觀察,沒有修復指令成功或失敗"
terminal = True
elif state == "verification_degraded_manual_required":
approval_status = "completed"
completion_status = "completed_verification_degraded"
command_status = "succeeded" if has_repair_execution else "diagnostic_completed"
repair_status = "verification_degraded"
failure_status = "no_command_failed"
summary = "已執行,但驗證結果退化;需人工確認是否真的修復"
terminal = False
elif state == "execution_unverified_manual_required":
approval_status = "completed"
completion_status = "completed_unverified"
command_status = "succeeded"
repair_status = "unverified"
failure_status = "no_command_failed"
summary = "已執行成功,但缺少修復驗證結果"
terminal = False
elif state == "no_action_manual_review":
approval_status = "pending_manual_review"
completion_status = "not_started_no_action"
command_status = "not_started"
repair_status = "not_executed"
failure_status = "not_applicable"
summary = "尚未執行AI 建議不修復,等待人工決定是否接手"
terminal = False
elif state == "approval_rejected_no_execution":
approval_status = "rejected"
completion_status = "closed_no_execution"
command_status = "not_run"
repair_status = "not_executed"
failure_status = "not_applicable"
summary = "已拒絕:審批結案,未執行任何修復指令"
terminal = True
elif state == "approval_expired_manual_review":
approval_status = "expired"
completion_status = "expired_no_execution"
command_status = "not_run"
repair_status = "not_executed"
failure_status = "not_applicable"
summary = "審批逾期:未執行修復,需人工重新審查"
terminal = False
elif state == "approval_required":
approval_status = "pending"
completion_status = "pending_approval"
command_status = "not_started"
repair_status = "not_executed"
failure_status = "not_applicable"
summary = "尚未執行:等待人工批准"
terminal = False
elif state == "read_only_dry_run_manual_gate":
approval_status = "manual_gate"
completion_status = "dry_run_completed"
command_status = "dry_run_succeeded"
repair_status = "not_executed"
failure_status = "not_applicable"
summary = "只讀試跑完成,尚未執行修復"
terminal = False
elif state == "observed_not_executed":
approval_status = "not_required"
completion_status = "observed_not_executed"
command_status = "not_run"
repair_status = "not_executed"
failure_status = "not_applicable"
summary = "只完成收件/觀測,尚未進入執行"
terminal = False
elif has_repair_execution:
approval_status = "completed"
completion_status = "completed_needs_review"
command_status = "succeeded" if verification != "missing" else "completed"
repair_status = "needs_review"
failure_status = "no_command_failed"
summary = "已有執行紀錄,但仍需人工確認最終修復結果"
terminal = False
elif verdict in {"received_only", "observed_not_executed"} or stage == "received":
approval_status = "not_started"
completion_status = "not_started"
command_status = "not_started"
repair_status = "not_executed"
failure_status = "not_applicable"
summary = "尚未執行修復指令"
terminal = False
return {
"approval_status": approval_status,
"completion_status": completion_status,
"command_status": command_status,
"repair_status": repair_status,
"failure_status": failure_status,
"terminal": terminal,
"summary_zh": summary,
}
def build_operator_outcome(
*,
truth_status: dict[str, Any] | None = None,
@@ -206,6 +340,14 @@ def build_operator_outcome(
summary = "處置結果尚未形成明確結論"
reason = first_blocker or f"{verdict}:{stage}/{stage_status}"
execution_result = _build_execution_result(
state=state,
verdict=verdict,
stage=stage,
has_repair_execution=has_repair_execution,
has_nonrepair_operation=has_nonrepair_operation,
verification=verification,
)
mode = "action_required" if needs_human else "result_only"
channels = _ACTION_REQUIRED_CHANNELS if needs_human else _RESULT_ONLY_CHANNELS
return {
@@ -217,6 +359,7 @@ def build_operator_outcome(
"human_action_required": needs_human,
"human_action_reason": reason,
"next_action": next_action,
"execution_result": execution_result,
"notification": _build_notification(
mode=mode,
channels=channels,

View File

@@ -197,10 +197,17 @@ def _format_operator_outcome_lines(outcome: dict[str, object] | None) -> list[st
else {}
)
channels = notification.get("channels") if isinstance(notification.get("channels"), list) else []
execution_result = (
outcome.get("execution_result")
if isinstance(outcome.get("execution_result"), dict)
else {}
)
return [
"👤 <b>處置結論</b>",
f"├ 結果:<b>{html.escape(str(outcome.get('summary_zh') or '尚未形成明確結論'))}</b>",
f"├ 狀態:<code>{html.escape(str(outcome.get('state') or 'unknown'))}</code>",
f"├ 執行:<code>{html.escape(str(execution_result.get('completion_status') or 'unknown'))}</code> | "
f"修復:<code>{html.escape(str(execution_result.get('repair_status') or 'unknown'))}</code>",
f"├ 人工:<code>{'yes' if outcome.get('needs_human') else 'no'}</code> | "
f"通知:<code>{html.escape(','.join(str(item) for item in channels) or 'none')}</code>",
f"└ 下一步:<code>{html.escape(str(outcome.get('next_action') or '--'))}</code>",