feat(Phase 5): Declarative 修復抽象化 + Blast Radius 分控 全部完成
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
## Phase 5 交付(ADR-086)
### 新增服務(4 個)
- blast_radius_calculator.py: 爆炸半徑計算器(0-100 純函數)
- 18 種 kubectl 動作基礎分 + 命名空間倍率 + 特殊 flag 修正
- HARD_RULES 永擋:delete ns/pv/pvc/clusterrole + rm -rf + DROP TABLE
- 分級:≤10 auto / 11-50 human / 51-99 dual / 100 blocked
- declarative_remediation.py: DeclarativeSpec 不可變規格(frozen dataclass)
- evaluate() 封裝 Blast Radius + dry-run + rollback_plan + constraints
- rollback_plan 從 kubectl 動作類型自動推導(不呼叫 LLM)
- gitops_pr_service.py: Gitea Issue 高風險修復審核(tier=dual)
- 含 Blast Radius + 目標狀態 + 回滾計畫 + 雙人審核流程
- AIOPS_P5_GITOPS_PR flag 守衛
- rollback_manager.py: 驗證失敗自動回滾
- 先驗 rollout history ≥ 2 revision,防止無版本可回滾
- kubectl rollout undo + 120s 收斂等待
### decision_manager.py 接線(AIOPS_P5_BLAST_RADIUS_CHECK)
- _auto_execute() 在安全守衛後、ApprovalRequest 前插入分級守衛
- blocked → 永擋 + 人工審核通知
- dual → 非同步 GitOps Issue + 升級人工審核
- human → 升級人工審核(不自動執行)
- auto(≤10)→ 原有自動執行流程
- 失敗降級:計算異常 → 保守升人工
### learning_service.py
- record_declarative_outcome(): 記錄 DeclarativeSpec 執行結果
anomaly_key=declarative:{incident_id},含 blast_radius_score/tier/rollback
2026-04-15 ogt + Claude Sonnet 4.6(亞太): Phase 5 全部完成
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1471,6 +1471,84 @@ class DecisionManager:
|
||||
)
|
||||
return
|
||||
|
||||
# Phase 5 ADR-086: Blast Radius 分級守衛(AIOPS_P5_BLAST_RADIUS_CHECK 控制)
|
||||
# 評估修復動作的爆炸半徑,決定是否可自動執行或需升級審核
|
||||
# 2026-04-15 ogt + Claude Sonnet 4.6(亞太): Phase 5 初始建立
|
||||
try:
|
||||
from src.core.feature_flags import aiops_flags as _p5_flags
|
||||
if _p5_flags.AIOPS_P5_BLAST_RADIUS_CHECK:
|
||||
from src.services.blast_radius_calculator import get_blast_radius_calculator
|
||||
from src.services.declarative_remediation import get_declarative_remediation
|
||||
|
||||
_calc = get_blast_radius_calculator()
|
||||
_blast = _calc.calculate(action, namespace=_ns, target=_target)
|
||||
_spec = get_declarative_remediation().evaluate(
|
||||
action=action, target=_target, namespace=_ns,
|
||||
description=token.proposal_data.get("description", ""),
|
||||
)
|
||||
|
||||
# 記錄分級結果到 proposal_data(供學習 + 審計)
|
||||
token.proposal_data["blast_radius_score"] = _blast.score
|
||||
token.proposal_data["blast_radius_tier"] = _blast.tier
|
||||
token.proposal_data["blast_radius_reason"] = _blast.reason
|
||||
|
||||
if _blast.tier == "blocked":
|
||||
# HARD_RULES 永擋
|
||||
logger.warning(
|
||||
"auto_execute_blast_radius_hard_blocked",
|
||||
incident_id=incident.incident_id,
|
||||
action=action[:80],
|
||||
reason=_blast.reason,
|
||||
)
|
||||
token.state = DecisionState.READY
|
||||
token.proposal_data["auto_executed"] = False
|
||||
token.proposal_data["mcp_all_failed"] = True
|
||||
token.proposal_data["blocked_reason"] = f"HARD_RULES 永擋:{_blast.reason}"
|
||||
await self._save_token(token)
|
||||
_fire_and_forget(_push_decision_to_telegram(incident, token.proposal_data))
|
||||
return
|
||||
|
||||
elif _blast.tier in ("human", "dual"):
|
||||
# 中高衝擊 → 升級人工審核,不自動執行
|
||||
logger.info(
|
||||
"auto_execute_blast_radius_escalated",
|
||||
incident_id=incident.incident_id,
|
||||
tier=_blast.tier,
|
||||
score=_blast.score,
|
||||
action=action[:80],
|
||||
)
|
||||
token.state = DecisionState.READY
|
||||
token.proposal_data["auto_executed"] = False
|
||||
token.proposal_data["requires_human_review"] = True
|
||||
token.proposal_data["blast_radius_escalated"] = True
|
||||
await self._save_token(token)
|
||||
# dual tier → 非同步建立 GitOps Issue
|
||||
if _blast.tier == "dual" and _p5_flags.AIOPS_P5_GITOPS_PR:
|
||||
from src.services.gitops_pr_service import get_gitops_pr_service
|
||||
_fire_and_forget(
|
||||
get_gitops_pr_service().create_repair_issue(
|
||||
spec=_spec,
|
||||
incident_id=incident.incident_id,
|
||||
diagnosis=token.proposal_data.get("debate_summary", ""),
|
||||
)
|
||||
)
|
||||
_fire_and_forget(_push_decision_to_telegram(incident, token.proposal_data))
|
||||
return
|
||||
# tier == "auto" → 繼續自動執行流程
|
||||
except Exception as _blast_err:
|
||||
# Blast Radius 計算失敗 → 保守:視為 human tier,升級人工審核
|
||||
logger.warning(
|
||||
"blast_radius_check_failed_conservative_escalate",
|
||||
incident_id=incident.incident_id,
|
||||
error=str(_blast_err),
|
||||
)
|
||||
token.state = DecisionState.READY
|
||||
token.proposal_data["auto_executed"] = False
|
||||
token.proposal_data["blast_radius_tier"] = "unknown_conservative"
|
||||
await self._save_token(token)
|
||||
_fire_and_forget(_push_decision_to_telegram(incident, token.proposal_data))
|
||||
return
|
||||
|
||||
try:
|
||||
# 延遲導入避免循環依賴
|
||||
from src.models.approval import ApprovalRequest, ApprovalStatus
|
||||
|
||||
Reference in New Issue
Block a user