承接 Wave 6/7/8 多 engineer 在 agent 限額前完成的代碼,補 commit 解 production HEAD 隱性 import error(decision_fusion 已被 decision_manager 引用但檔案 untracked)。 新增(後端核心): - decision_fusion.py (562 行) — P2.1 方法 III(OpenClaw + Hermes + Elephant 三 LLM 融合) - aiops_timeline.py + aiops_timeline_service.py — critic B4 修復 /api/v1/aiops/timeline endpoint,DB 存取抽到 service 層遵守 leWOOOgo 積木化 - migrations/p2_decision_fusion_columns.sql + rollback — approval_records fusion 欄位 修改(後端整合): - decision_manager.py — fusion 三斷鏈修補(critic B1+B2+B3): · B1: 寫 _evidence_snapshot_ref 到 token.proposal_data · B2: fusion 前計算 complexity_score 並寫 token · B3: fusion composite 寫 token.proposal_data["decision_fusion"] - auto_approve.py — fusion + consensus 認識(critic B3+B5): · composite > 0.7 → auto_execute_eligible bypass min_confidence · source=consensus_engine + score>=0.6 → 規則可信路徑 - consensus_engine.py — db-fix _save_consensus 重用 agent_sessions - governance_agent.py — db-fix _alert PG 寫入 ai_governance_events - approval_db.py — fusion 3 欄位 + 2 partial index + CheckConstraint - db/models.py — schema 對齊 migration - core/config.py — vuln #1 修復:OLLAMA_URL/_FALLBACK_URL field_validator 拒絕公網 IP + 外部域名,僅允許私網/loopback/K8s SVC 白名單 - core/feature_flags.py — P2 fusion + consensus flags - main.py — governance_agent lifespan 啟動 - failover_alerter.py — Wave8-X2: in-memory dedup fallback(Redis 拒絕後不 fail-open) - ollama_*.py — metrics 整合 + recovery 改善 - auto_repair_service.py — verifier 接線 新增(測試 2438 行): - test_decision_fusion.py / test_governance_agent.py / test_consensus_integration.py - test_p2_db_fixes.py / test_wave8_fusion_fixes.py - test_config_url_validation.py(vuln #1 12 tests) - test_failover_alerter.py +Wave8-X2 in-memory dedup 補測 驗收: 116 tests pass (decision_fusion + wave8_fusion + config_url + consensus + governance + p2_db_fixes + failover_alerter) Conflict resolution: - 3 檔(config.py + auto_approve.py + decision_manager.py)git stash pop 衝突 保留 stashed (engineer 最終版),補回 ValueError 「公網 IP」字樣對齊 test Note: 此 commit 解 production HEAD 隱性 import error 仍未修: vuln #4 prompt injection / debugger B14 quota fail-closed / B25-B26 drain_pending_tasks / B8 governance fail alert Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-Authored-By: Multiple Engineers (Wave 6/7/8) <noreply@anthropic.com>
256 lines
9.1 KiB
Python
256 lines
9.1 KiB
Python
"""
|
||
AWOOOI AIOps Feature Flags
|
||
==========================
|
||
AI 自主化飛輪 Phase 0-6 功能開關
|
||
|
||
ADR-080: AI 自主化飛輪總綱
|
||
MASTER: docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md
|
||
|
||
安全規則:
|
||
- 所有 flag 預設 False — 任何 Phase 必須明確開啟才生效
|
||
- Phase 總開關 = False 時,該 Phase 所有子開關均視為 False
|
||
- 自我降級後 (D6) 不得自動反向升級,升級必須人工設定 env var
|
||
|
||
回滾方式:
|
||
kubectl set env deployment/awoooi-api AIOPS_P1_ENABLED=false
|
||
# ⚠️ pydantic_settings 在 Pod 啟動時讀取 env var 並快取為 Singleton
|
||
# kubectl set env 修改後必須重啟 Pod 才生效(非熱重載)
|
||
# 緊急回滾:kubectl rollout restart deployment/awoooi-api
|
||
|
||
2026-04-15 ogt: Phase 0 — 初始建立,ADR-080 批准後啟用
|
||
"""
|
||
|
||
from pydantic import Field
|
||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||
|
||
|
||
class AIOpsFeatureFlags(BaseSettings):
|
||
"""
|
||
AI 自主化飛輪 Feature Flag 集合
|
||
|
||
每個 Phase 一個總開關 + 細粒度子開關。
|
||
讀取順序:環境變數 > .env 檔 > 預設值(全 False)。
|
||
"""
|
||
|
||
model_config = SettingsConfigDict(
|
||
env_file=".env",
|
||
env_file_encoding="utf-8",
|
||
case_sensitive=True,
|
||
extra="ignore",
|
||
)
|
||
|
||
# ==========================================================================
|
||
# Phase 總開關(Phase N 退出條件達到後才設 True)
|
||
# ==========================================================================
|
||
|
||
AIOPS_P1_ENABLED: bool = Field(
|
||
default=False,
|
||
description="Phase 1 感官縱深:PreDecisionInvestigator + EvidenceSnapshot + PostExecutionVerifier",
|
||
)
|
||
AIOPS_P2_ENABLED: bool = Field(
|
||
default=False,
|
||
description="Phase 2 多 Agent 協作:5 角色全部上線(Diagnostician/Solver/Reviewer/Critic/Coordinator)",
|
||
)
|
||
AIOPS_P3_ENABLED: bool = Field(
|
||
default=False,
|
||
description="Phase 3 學習閉環重建:3 根因修復 + EWMA + Evolver + Fine-tune pipeline",
|
||
)
|
||
AIOPS_P4_ENABLED: bool = Field(
|
||
default=False,
|
||
description="Phase 4 動態異常偵測:Holt-Winters + Drain3 + Prophet + 主動巡檢",
|
||
)
|
||
AIOPS_P5_ENABLED: bool = Field(
|
||
default=False,
|
||
description="Phase 5 修復抽象化:Declarative + Blast Radius 四級分控 + GitOps PR",
|
||
)
|
||
AIOPS_P6_ENABLED: bool = Field(
|
||
default=False,
|
||
description="Phase 6 自我治理閉環:SLO + Trust Drift + KB Rot + 離線回放 + 自我降級",
|
||
)
|
||
|
||
# ==========================================================================
|
||
# Phase 1 細粒度子開關
|
||
# ==========================================================================
|
||
|
||
AIOPS_P1_PRE_DECISION_INVESTIGATOR: bool = Field(
|
||
default=False,
|
||
description="P1: PreDecisionInvestigator 是否在決策前執行 MCP 感官蒐集(可獨立關閉)",
|
||
)
|
||
AIOPS_P1_POST_EXECUTION_VERIFIER: bool = Field(
|
||
default=False,
|
||
description="P1: PostExecutionVerifier 是否在每次執行後驗證狀態",
|
||
)
|
||
|
||
# ==========================================================================
|
||
# Phase 2 細粒度子開關
|
||
# ==========================================================================
|
||
|
||
AIOPS_P2_CRITIC_ENABLED: bool = Field(
|
||
default=False,
|
||
description="P2: Critic Agent 是否啟用辯證挑戰(關閉可降低延遲但失去質疑機制)",
|
||
)
|
||
AIOPS_P2_AGENT_TIMEOUT_SEC: int = Field(
|
||
default=5,
|
||
description="P2: 單 Agent 熔斷閾值(秒),超時則 Coordinator 降級處理",
|
||
)
|
||
# 2026-04-26 P2.1 by Claude — decision fusion 方法 III
|
||
AIOPS_P2_FUSION_ENABLED: bool = Field(
|
||
default=False,
|
||
description="P2.1: DecisionFusionEngine 方法 III 多源決策融合(LOW→Hermes/MED→雙軌/HIGH→OC+Elephant)",
|
||
)
|
||
|
||
# ==========================================================================
|
||
# Phase 3 細粒度子開關
|
||
# ==========================================================================
|
||
|
||
AIOPS_P3_FINETUNE_EXPORT: bool = Field(
|
||
default=False,
|
||
description="P3: Fine-tune JSONL 每週匯出到 MinIO 是否執行",
|
||
)
|
||
AIOPS_P3_EVOLVER_ENABLED: bool = Field(
|
||
default=False,
|
||
description="P3: Evolver Agent 是否執行 Playbook 自動合併與封存",
|
||
)
|
||
AIOPS_P3_KNOWLEDGE_DECAY: bool = Field(
|
||
default=False,
|
||
description="P3: 30 天知識遺忘 job 是否執行(標 decayed,降到 cold index)",
|
||
)
|
||
|
||
# ==========================================================================
|
||
# Phase 4 細粒度子開關
|
||
# ==========================================================================
|
||
|
||
AIOPS_P4_DYNAMIC_BASELINE: bool = Field(
|
||
default=False,
|
||
description="P4: Holt-Winters 動態基線服務是否啟用",
|
||
)
|
||
AIOPS_P4_LOG_ANOMALY: bool = Field(
|
||
default=False,
|
||
description="P4: Drain3 日誌異常偵測是否啟用",
|
||
)
|
||
AIOPS_P4_TREND_PREDICTOR: bool = Field(
|
||
default=False,
|
||
description="P4: Prophet 趨勢預測是否啟用(預測 4h 內超閾值風險)",
|
||
)
|
||
AIOPS_P4_PROACTIVE_INSPECTOR: bool = Field(
|
||
default=False,
|
||
description="P4: 主動巡檢每 5min 是否執行",
|
||
)
|
||
AIOPS_P4_SHADOW_MODE: bool = Field(
|
||
default=True,
|
||
description="P4: Shadow Mode = True 時動態偵測只記錄不觸發 Alert;False = 真實觸發(需先觀察噪音率)",
|
||
)
|
||
|
||
# ==========================================================================
|
||
# Phase 5 細粒度子開關
|
||
# ==========================================================================
|
||
|
||
AIOPS_P5_BLAST_RADIUS_CHECK: bool = Field(
|
||
default=False,
|
||
description="P5: Blast Radius 評估是否執行(False = 全部視為低風險自動執行,危險)",
|
||
)
|
||
AIOPS_P5_GITOPS_PR: bool = Field(
|
||
default=False,
|
||
description="P5: 高風險修復(Blast Radius > 50)是否走 GitOps Gitea PR 流程",
|
||
)
|
||
AIOPS_P5_DRY_RUN_ENFORCED: bool = Field(
|
||
default=False,
|
||
description="P5: Declarative apply 前是否強制 dry-run(False = 跳過 dry-run,危險)",
|
||
)
|
||
|
||
# ==========================================================================
|
||
# Phase 6 細粒度子開關
|
||
# ==========================================================================
|
||
|
||
AIOPS_P6_SELF_DEMOTION: bool = Field(
|
||
default=False,
|
||
description="P6: 自我降級邏輯是否啟用(SLO 違反 → 自動提高信心閾值)",
|
||
)
|
||
AIOPS_P6_OFFLINE_REPLAY: bool = Field(
|
||
default=False,
|
||
description="P6: 週度離線回放 100 案是否執行",
|
||
)
|
||
AIOPS_P6_KB_ROT_CLEANER: bool = Field(
|
||
default=False,
|
||
description="P6: 月度 KB 腐爛清理 job 是否執行",
|
||
)
|
||
AIOPS_P6_TRUST_DRIFT_DETECTOR: bool = Field(
|
||
default=False,
|
||
description="P6: Playbook trust 分布漂移偵測是否啟用",
|
||
)
|
||
AIOPS_P6_GOVERNANCE_ENABLED: bool = Field(
|
||
default=False,
|
||
description="P6: 治理閉環總開關(offline_replay_service / model_rollback_service 守衛)",
|
||
)
|
||
|
||
def is_phase_enabled(self, phase: int) -> bool:
|
||
"""
|
||
檢查指定 Phase 的總開關是否啟用。
|
||
|
||
Args:
|
||
phase: Phase 編號(1-6)
|
||
|
||
Returns:
|
||
bool: 該 Phase 是否開啟
|
||
|
||
Usage:
|
||
if flags.is_phase_enabled(1):
|
||
await pre_decision_investigator.investigate(...)
|
||
"""
|
||
phase_flags = {
|
||
1: self.AIOPS_P1_ENABLED,
|
||
2: self.AIOPS_P2_ENABLED,
|
||
3: self.AIOPS_P3_ENABLED,
|
||
4: self.AIOPS_P4_ENABLED,
|
||
5: self.AIOPS_P5_ENABLED,
|
||
6: self.AIOPS_P6_ENABLED,
|
||
}
|
||
return phase_flags.get(phase, False)
|
||
|
||
def is_sub_flag_enabled(self, flag_name: str) -> bool:
|
||
"""
|
||
檢查細粒度子開關(自動驗證父 Phase 開關)。
|
||
|
||
Args:
|
||
flag_name: 子開關名稱,例如 "AIOPS_P1_PRE_DECISION_INVESTIGATOR"
|
||
|
||
Returns:
|
||
bool: 子開關 AND 父 Phase 開關都為 True 才回 True
|
||
|
||
Usage:
|
||
if flags.is_sub_flag_enabled("AIOPS_P1_PRE_DECISION_INVESTIGATOR"):
|
||
...
|
||
"""
|
||
# 解析 Phase 編號
|
||
parts = flag_name.split("_")
|
||
if len(parts) < 3 or not parts[1].startswith("P"):
|
||
return False
|
||
|
||
try:
|
||
phase = int(parts[1][1:])
|
||
except ValueError:
|
||
return False
|
||
|
||
# 父 Phase 必須開啟
|
||
if not self.is_phase_enabled(phase):
|
||
return False
|
||
|
||
return bool(getattr(self, flag_name, False))
|
||
|
||
|
||
# Singleton — 與 core/config.py 的 settings 相同模式
|
||
# 使用:from src.core.feature_flags import aiops_flags
|
||
aiops_flags = AIOpsFeatureFlags()
|
||
|
||
|
||
def get_aiops_flags() -> AIOpsFeatureFlags:
|
||
"""
|
||
FastAPI dependency injection 用。
|
||
|
||
Usage:
|
||
@router.get("/status")
|
||
async def status(flags: AIOpsFeatureFlags = Depends(get_aiops_flags)):
|
||
return {"p1": flags.AIOPS_P1_ENABLED}
|
||
"""
|
||
return aiops_flags
|