fix(alerts): clarify execution result verdict
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>",
|
||||
|
||||
Reference in New Issue
Block a user