fix(pipeline): 三斷點修復 — SLO公式+NO_ACTION堆積+幻覺降級風險
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m3s
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m3s
D1 flywheel_stats_service: execution_count 欄位不存在 → 改讀
success_count+failure_count;消除飛輪執行成功率永遠 0.0% 假象
D2 openclaw._validate_deployment_inventory: 幻覺 deployment 降級後
原 HIGH/CRITICAL risk 未清零 → 加 result.risk_level = AIRiskLevel.LOW
D3 webhooks.py (兩處 alert path): NO_ACTION/INVESTIGATE/OBSERVE 三類
非破壞性動作強制 risk_level = LOW,跳過 Telegram 批准直接 auto-approve
→ approval_execution.py 的 NO_ACTION handler 立即標 EXECUTION_SUCCESS
Root cause 鏈:BUTTON_DATA_INVALID 修復後 TG 按鈕可發,但 NO_ACTION
積壓的 35 筆 PENDING 是因 HIGH risk 無法走 auto-approve 路徑導致。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -871,6 +871,18 @@ async def receive_alert(
|
|||||||
}
|
}
|
||||||
risk_level = risk_mapping.get(analysis_result.risk_level.value, RiskLevel.MEDIUM)
|
risk_level = risk_mapping.get(analysis_result.risk_level.value, RiskLevel.MEDIUM)
|
||||||
|
|
||||||
|
# 2026-04-21 ogt: NO_ACTION/INVESTIGATE/OBSERVE 強制 LOW risk,避免卡 PENDING
|
||||||
|
# 根因:_validate_deployment_inventory 降級後若原 risk 為 HIGH/CRITICAL,
|
||||||
|
# 會等 Telegram 批准,但無任何可執行動作 → 永久積壓 PENDING
|
||||||
|
_non_destructive_actions = {"NO_ACTION", "INVESTIGATE", "OBSERVE"}
|
||||||
|
_sa_val = (
|
||||||
|
analysis_result.suggested_action.value
|
||||||
|
if hasattr(analysis_result.suggested_action, "value")
|
||||||
|
else str(analysis_result.suggested_action)
|
||||||
|
)
|
||||||
|
if _sa_val in _non_destructive_actions:
|
||||||
|
risk_level = RiskLevel.LOW
|
||||||
|
|
||||||
impact_mapping = {
|
impact_mapping = {
|
||||||
"NONE": DataImpact.NONE,
|
"NONE": DataImpact.NONE,
|
||||||
"READ_ONLY": DataImpact.READ_ONLY,
|
"READ_ONLY": DataImpact.READ_ONLY,
|
||||||
@@ -1100,6 +1112,16 @@ async def _process_new_alert_background(
|
|||||||
}
|
}
|
||||||
risk_level = risk_mapping.get(analysis_result.risk_level.value, RiskLevel.MEDIUM)
|
risk_level = risk_mapping.get(analysis_result.risk_level.value, RiskLevel.MEDIUM)
|
||||||
|
|
||||||
|
# 2026-04-21 ogt: NO_ACTION/INVESTIGATE/OBSERVE 強制 LOW risk,避免卡 PENDING
|
||||||
|
_non_destructive_actions = {"NO_ACTION", "INVESTIGATE", "OBSERVE"}
|
||||||
|
_sa_val = (
|
||||||
|
analysis_result.suggested_action.value
|
||||||
|
if hasattr(analysis_result.suggested_action, "value")
|
||||||
|
else str(analysis_result.suggested_action)
|
||||||
|
)
|
||||||
|
if _sa_val in _non_destructive_actions:
|
||||||
|
risk_level = RiskLevel.LOW
|
||||||
|
|
||||||
blast = analysis_result.blast_radius
|
blast = analysis_result.blast_radius
|
||||||
impact_mapping = {
|
impact_mapping = {
|
||||||
"NONE": DataImpact.NONE,
|
"NONE": DataImpact.NONE,
|
||||||
|
|||||||
@@ -204,9 +204,9 @@ class FlywheelStatsService:
|
|||||||
status = pb.get("status", "")
|
status = pb.get("status", "")
|
||||||
if status == "approved":
|
if status == "approved":
|
||||||
count += 1
|
count += 1
|
||||||
exec_count = pb.get("execution_count", 0) or 0
|
|
||||||
success_count = pb.get("success_count", 0) or 0
|
success_count = pb.get("success_count", 0) or 0
|
||||||
total_exec += exec_count
|
failure_count = pb.get("failure_count", 0) or 0
|
||||||
|
total_exec += success_count + failure_count
|
||||||
total_success += success_count
|
total_success += success_count
|
||||||
except (json.JSONDecodeError, KeyError):
|
except (json.JSONDecodeError, KeyError):
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ from src.core.config import settings
|
|||||||
from src.core.prompts import NEMOTRON_SYSTEM_PROMPT, OPENCLAW_SYSTEM_PROMPT
|
from src.core.prompts import NEMOTRON_SYSTEM_PROMPT, OPENCLAW_SYSTEM_PROMPT
|
||||||
from src.core.redis_client import get_redis
|
from src.core.redis_client import get_redis
|
||||||
from src.models.ai import (
|
from src.models.ai import (
|
||||||
|
AIRiskLevel,
|
||||||
OpenClawDecision,
|
OpenClawDecision,
|
||||||
SuggestedAction,
|
SuggestedAction,
|
||||||
)
|
)
|
||||||
@@ -1214,6 +1215,12 @@ class OpenClawService:
|
|||||||
result.confidence = 0.0
|
result.confidence = 0.0
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
# 2026-04-21 ogt: 降級後風險強制 LOW,避免 NO_ACTION 因原 HIGH/CRITICAL risk
|
||||||
|
# 留在 PENDING 等 Telegram 批准(已無執行內容,等待毫無意義)
|
||||||
|
try:
|
||||||
|
result.risk_level = AIRiskLevel.LOW
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
def _parse_analysis_result(self, raw_response: str) -> OpenClawDecision | None:
|
def _parse_analysis_result(self, raw_response: str) -> OpenClawDecision | None:
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user