From 5fb73a5612f5372c182ff574b9e7fa74a063c394 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 14 May 2026 00:37:31 +0800 Subject: [PATCH] fix(verifier): recognize rollout success evidence --- apps/api/src/services/mcp_tool_registry.py | 4 ++-- apps/api/src/services/post_execution_verifier.py | 12 +++++++++++- apps/api/tests/test_mcp_tool_registry.py | 6 ++++++ apps/api/tests/test_post_execution_verifier.py | 10 ++++++++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/apps/api/src/services/mcp_tool_registry.py b/apps/api/src/services/mcp_tool_registry.py index ce6585ba..35c6b81d 100644 --- a/apps/api/src/services/mcp_tool_registry.py +++ b/apps/api/src/services/mcp_tool_registry.py @@ -235,10 +235,10 @@ def _classify_tool(tool: MCPTool, provider: MCPToolProvider) -> RegisteredTool: priority = 5 # D1 K8s 狀態 - if any(k in name for k in ("describe", "pod", "deployment", "node", "hpa", "event", "k8s_get")): + if any(k in name for k in ("describe", "pod", "deployment", "node", "hpa", "event", "k8s_get", "rollout")): dims.append(SensorDimension.D1_K8S_STATE) hints = ["Kube", "Pod", "Deploy", "Node", "Velero", "ArgoCD"] - priority = 2 + priority = 1 if "rollout" in name else 2 # D2 日誌(精確匹配:避免 "topology" 中的 "log" substring 誤觸) elif any(k in name for k in ("logs", "stderr", "journal")) or "_log" in name or name.startswith("log"): diff --git a/apps/api/src/services/post_execution_verifier.py b/apps/api/src/services/post_execution_verifier.py index e52c66cb..01ebbf6d 100644 --- a/apps/api/src/services/post_execution_verifier.py +++ b/apps/api/src/services/post_execution_verifier.py @@ -464,7 +464,17 @@ def _assess_recovery( return "failed" # 成功信號 - success_signals = ["running", "ready", "1/1", "2/2", "3/3", "healthy"] + success_signals = [ + "running", + "ready", + "1/1", + "2/2", + "3/3", + "healthy", + "successfully rolled out", + "'success': true", + '"success": true', + ] if any(sig in post_str for sig in success_signals): # 但如果 pre_state 已經是 running,可能是無效操作 if pre_str and any(sig in pre_str for sig in success_signals): diff --git a/apps/api/tests/test_mcp_tool_registry.py b/apps/api/tests/test_mcp_tool_registry.py index b950fd88..5510921d 100644 --- a/apps/api/tests/test_mcp_tool_registry.py +++ b/apps/api/tests/test_mcp_tool_registry.py @@ -142,6 +142,12 @@ class TestClassifyTool: h in reg.incident_type_hints for h in ["Pod", "Deploy", "Node"] ) + def test_rollout_tool_is_high_priority_d1(self): + reg = _classify_tool(_make_tool("k8s_watch_rollout"), self._provider()) + assert SensorDimension.D1_K8S_STATE in reg.dimensions + assert reg.priority == 1 + assert "Deploy" in reg.incident_type_hints + def test_ssh_type_hints(self): reg = _classify_tool(_make_tool("ssh_run"), self._provider()) assert any(h in reg.incident_type_hints for h in ["Host", "Docker"]) diff --git a/apps/api/tests/test_post_execution_verifier.py b/apps/api/tests/test_post_execution_verifier.py index b0ff82ac..d3791188 100644 --- a/apps/api/tests/test_post_execution_verifier.py +++ b/apps/api/tests/test_post_execution_verifier.py @@ -76,6 +76,16 @@ class TestAssessRecovery: post = {"pod": {"containers": "1/1"}} assert _assess_recovery(None, post, "scale_up") == "success" + def test_rollout_success_is_success(self): + post = { + "k8s_watch_rollout": { + "deployment": "awoooi-auto-repair-canary", + "success": True, + "status": 'deployment "awoooi-auto-repair-canary" successfully rolled out', + } + } + assert _assess_recovery(None, post, "auto_repair_playbook:PB-CANARY") == "success" + def test_crashloopbackoff_is_failed(self): post = {"pod": {"status": "CrashLoopBackOff"}} assert _assess_recovery(None, post, "restart_service") == "failed"