Commit Graph

1409 Commits

Author SHA1 Message Date
OG T
ee486fbd2b docs(logbook): 2026-04-15 深夜收官 — P0/P2 RCA + Phase 6 閉環
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 19:58:09 +08:00
OG T
05b774386b feat(Phase 6): AI SLO REST API — GET /api/v1/ai/slo 收官
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
ADR-087 Phase 6 自我治理閉環最後一塊拼圖:

1. api/v1/ai_slo.py — GET /api/v1/ai/slo
   - Service 層快取優先(TTL 5min,AiSloCalculator.get_cached_report)
   - force_refresh=true 強制重算(AiSloCalculator.run)
   - Router 層零 Redis 直接存取(leWOOOgo 積木化鐵律)

2. main.py — 路由掛載 ai_slo_v1.router(prefix=/api/v1)

3. MASTER §8 Living Changelog 追加:
   - P0 告警靜默 3 根因 RCA 完整紀錄
   - P2 飛輪斷鏈修復摘要
   - Phase 6 全元件完成清單

Phase 6 退出條件 5/6 已達(生產驗證待 image 上線)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 19:57:26 +08:00
OG T
14579ce149 fix(heartbeat): 系統沉默閾值 2h → 24h,消除假陽性告警
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
無事故期間系統正常不寫 KM,2h 必然誤報。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 19:51:01 +08:00
OG T
3ce5025ca7 fix(alerts): 3 個飛輪沉默節點 — DIAGNOSE routing + 心跳停用 + 通知格式
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
1. openclaw.py: DIAGNOSE 移除 require_local=True
   - v4.3 已決定 NIM 為主力且無隱私問題
   - require_local=True 導致所有 provider 被 privacy_skip → 告警永遠失敗
   - 修後 DIAGNOSE 走 _full_fallback_chain(NIM → Gemini → Claude)

2. ai_router.py: require_local 失敗通知改為 ADR-075 TYPE-1 格式
   - 禁止純文字 raw notification(統帥鐵律:所有訊息必須符合格式模板)
   - 改用 ├─ / └─ 樹狀結構 + 語義化標籤

3. main.py: 停用 Telegram 心跳監控
   - 心跳已轉發到另一個 Telegram 群組,不需在此頻道重複發送

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 19:49:43 +08:00
AWOOOI CD
2d85b49cc0 chore(cd): deploy f9ba200 [skip ci] 2026-04-15 11:47:40 +00:00
OG T
f9ba200638 fix(db): Phase 6 migration 三條 CREATE INDEX 拆開各自 execute
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
asyncpg 不支援 prepared statement 內多條 SQL 指令,
原本一個 text("""...""") 包含三條 CREATE INDEX 導致 CrashLoopBackOff。
拆成三個獨立 conn.execute() 呼叫。

2026-04-15 ogt + Claude Sonnet 4.6(亞太)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 19:37:58 +08:00
AWOOOI CD
160689a110 chore(cd): deploy f045506 [skip ci] 2026-04-15 11:31:02 +00:00
OG T
f045506abd fix(flywheel): P2 Approval 逾期不結案 → KM 學習鏈斷鏈修復
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 12m11s
問題根因:
  PENDING approval 無人處置超過 48h 後應自動 EXPIRED,
  但 get_pending_approvals() 只在用戶開 UI 時觸發,
  若無人開 UI → Incident 永遠 PENDING → KM 永遠不寫入
  → Phase 6 SLO human_override_rate 低估,EWMA 缺少負向樣本。

修復:
  1. anomaly_counter.py: 新增 "timeout_ignored" disposition 類型,
     與 auto_repair / human_approved / manual_resolved 區分
  2. incident_service.py: resolve_incident() 新增 resolution_type 參數,
     resolution_type="timeout" 時記錄 "timeout_ignored" 而非 "manual_resolved"
  3. jobs/approval_timeout_resolver.py (新): 每小時掃描逾期 PENDING approval,
     批次標記 EXPIRED,對每筆有 incident_id 的記錄呼叫 resolve_incident("timeout")
  4. main.py: startup 掛載 approval_timeout_resolver 排程(interval=3600s)

效果:
  - 告警無人處置 48h → Incident 自動結案 → KM 寫入 → EWMA 取得樣本
  - disposition="timeout_ignored" 讓 SLO 計算正確區分「AI 建議被忽略」
  - 飛輪學習鏈對「無人處置告警」閉環

2026-04-15 ogt + Claude Sonnet 4.6(亞太)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 19:21:21 +08:00
AWOOOI CD
586602e7ff chore(cd): deploy f31b4e3 [skip ci] 2026-04-15 11:18:56 +00:00
OG T
f31b4e31ba fix(approval): create_approval_with_fingerprint 補注 48h expires_at 預設值
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
根因(盤點後確認):
  所有 webhook 建立 approval 的路徑(webhooks.py:908/1426/1566)均未傳
  expires_at,DB 欄位為 NULL。get_pending_approvals() 的自動過期邏輯
  WHERE expires_at < now 對 NULL 永遠為 False → 殭屍 PENDING 永不清理。

修正策略:
  在 create_approval_with_fingerprint()(告警 approval 唯一共用入口)
  注入預設 48h TTL,一次覆蓋全部 3 個 webhook 呼叫點。
  手動 API 建立(approvals.py)自行傳 expires_at,不受影響。

與 2026-04-15 24h PENDING_TTL_HOURS 補丁協同工作:
  - 24h: find_by_fingerprint 不再收斂過期 PENDING → 新告警重新觸發通知
  - 48h: get_pending_approvals auto-expire → UI 殭屍記錄自動清除

2026-04-15 ogt + Claude Sonnet 4.6(亞太):完整盤點後補完

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 19:08:17 +08:00
AWOOOI CD
1d22376b86 chore(cd): deploy fab65e7 [skip ci] 2026-04-15 11:06:22 +00:00
OG T
fab65e7d7a fix(alerts): PENDING 收斂無 TTL → 老記錄永久封鎖 Telegram 告警
Some checks are pending
CD Pipeline / build-and-deploy (push) Has started running
根因:find_by_fingerprint 的 PENDING 匹配條件無時間上限,
2026-04-12 建立的 3 筆 PENDING approval records(hit=77/30/17)
持續吃掉所有同指紋告警,造成 2+ 小時 Telegram 靜音。

修正(approval_db.py):
  - PENDING_TTL_HOURS = 24:PENDING 記錄逾 24h 不再收斂新告警
  - 原本:OR(status=PENDING, created_at>=30min前)
  - 修正:OR(PENDING AND created_at>=24h前, created_at>=30min前)

緊急修復:kubectl exec 直接將 7 筆過期 PENDING 記錄設為 expired,
即時恢復 Telegram 告警流(不等部署)。

Phase 6 AI 自我治理閉環(ADR-087):
  - feat(db): 新增 ai_governance_events 表 + 3 個 index(base.py + models.py)
  - feat(svc): ai_slo_calculator.py — 7d 滾動 SLO(success/override/false_neg)
  - feat(svc): trust_drift_detector.py — Playbook 信任度極端偏態偵測
  - feat(job): kb_rot_cleaner.py — K8s API/Prom metric/老舊 incident_case 腐爛清理
  - feat(svc): decision_manager.py — 自我降級守衛(SLO 違反 → 提高門檻/保守模式)

2026-04-15 ogt + Claude Sonnet 4.6(亞太)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 18:56:26 +08:00
AWOOOI CD
37f4553349 chore(cd): deploy 4e2e665 [skip ci] 2026-04-15 08:22:53 +00:00
OG T
4e2e6652e3 fix(db): 移除 IncidentEvidence.incident_id 的重複 index 定義
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m50s
根本原因:incident_id 同時設定 index=True(mapped_column)
與 __table_args__ 中的 Index("ix_incident_evidence_incident_id"),
導致 table.create 生成重複的 CREATE INDEX,
觸發 "already exists" 被靜默捕捉,整個 CREATE TABLE transaction 回滾。
直接效果:Pod 啟動時 incident_evidence 表永遠不會被建立,
導致後續 ALTER TABLE 失敗 → CrashLoopBackOff。

修法:移除 mapped_column 中的 index=True,
索引由 __table_args__ 統一管理。

注意:已在 PostgreSQL 直接建立 incident_evidence 表解除 CrashLoop。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 16:13:18 +08:00
OG T
655d1a568a feat(Phase 5): Declarative 修復抽象化 + Blast Radius 分控 全部完成
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>
2026-04-15 16:06:54 +08:00
AWOOOI CD
53344c201e chore(cd): deploy 14a0226 [skip ci] 2026-04-15 07:57:10 +00:00
OG T
14a02263ae feat(Phase 4): 主動巡檢 + 趨勢預測 + 8D 感官升級 全部完成
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 12m32s
## Phase 4 完整交付(ADR-084)

### 新增服務
- trend_predictor.py: numpy 線性回歸,4h 閾值突破預警,R² 信心評分
- proactive_inspector.py: 每 5 分鐘主動巡檢協調器
  - DynamicBaselineService(3σ 偏離)
  - LogAnomalyDetector(新 Drain3 pattern)
  - TrendPredictor(斜率外推 4h 預測)
  - Shadow Mode + 30 分鐘去重 + Holt-Winters 背景重訓

### 8D 感官升級(EvidenceSnapshot Phase 4 增強)
- PreDecisionInvestigator._collect_phase4_anomalies(): 決策前讀取
  ProactiveInspector 最近巡檢快取 + LogAnomalyDetector 新 pattern
- EvidenceSnapshot.anomaly_context: 新欄位,Phase 4 動態異常上下文
- DiagnosticianAgent._build_prompt(): prompt 包含 anomaly_context,
  LLM RCA 可參考動態基線偏差與趨勢預警

### 資料庫遷移
- incident_evidence: ADD COLUMN anomaly_context JSONB(冪等)

### main.py
- 啟動 run_proactive_inspector_loop() asyncio task

2026-04-15 ogt + Claude Sonnet 4.6(亞太): Phase 4 全部完成

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:47:05 +08:00
OG T
952c10955b fix(db): 多 replica 並行啟動競爭 — 每 table 獨立 tx + DROP INDEX IF EXISTS
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
根因:單一大 transaction 內兩個 pod 同時建同一個 table,
其中一個 CREATE INDEX 失敗 → 整個 transaction ROLLBACK
→ table 也消失 → 下次重啟同樣情況 → 無限 CrashLoop。

修法三層:
1. 每個 table 用獨立 transaction 建立(失敗不影響其他)
2. 建 table 前先 DROP INDEX IF EXISTS 清殘留孤兒 index
3. 捕捉 "already exists" 讓並行 pod 優雅跳過(不 crash)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:38:43 +08:00
OG T
4a6aa16a94 fix(Phase 4): 修正呼叫點遺漏傳入參數 — promql 和 sample_log
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
關聯節點檢查發現:
- dynamic_baseline_service.py: _save_baseline() 在 train_baseline() 中
  未傳入 promql/lookback_hours → PG 記錄無法追蹤訓練來源
- log_anomaly_detector.py: _save_new_cluster() 未傳入 sample_log →
  PG 記錄 LogCluster 時 sample_log 欄位為空

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:34:33 +08:00
OG T
bf45b80bd2 feat(Phase 3.5 + Phase 4): AI 學習成果持久化到 PostgreSQL — 修正「AI 失憶」架構缺陷
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
ADR-085: AI 學習成果不可存在 Cache

架構鐵律確立:
- PostgreSQL = System of Record(AI 的永久記憶)
- Redis = Warm Cache(加速讀取,TTL 到期從 PG 復原)

核心變更:
1. models.py: 新增 PlaybookRecord / DynamicBaselineRecord / LogClusterRecord ORM
2. base.py: ALTER TABLE playbooks 補加 trust_score / requires_approval_level 等欄位
3. playbook_repository.py: 完整雙寫實作(PG upsert + Redis cache)
4. dynamic_baseline_service.py: Holt-Winters 訓練結果寫入 PG,Redis 只作 24h warm cache
5. log_anomaly_detector.py: Drain3 cluster template 寫入 PG(UPSERT on cluster_id)
6. main.py: 啟動時執行 backfill_redis_to_pg()(Redis → PG 冪等補救)

修正的問題:
- Playbook 7天 Redis TTL 到期 → AI 失去所有修復知識
- trust_score EWMA 隨 Redis TTL 歸零 → AI 重新回到初始信任度 0.3
- Holt-Winters 基線 24h TTL → AI 每天重新學習「正常」的定義
- Drain3 cluster 沒有持久化 → AI 把已知 log pattern 反覆當新 pattern

Phase 4 新服務(requirements.txt 已加入 statsmodels + drain3 + numpy)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:34:04 +08:00
AWOOOI CD
9126c594a4 chore(cd): deploy 0f2ec79 [skip ci] 2026-04-15 07:28:25 +00:00
OG T
0f2ec7987c fix(db): 改用 inspect 跳過現有 table,根治 CrashLoopBackOff
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 14m42s
checkfirst=True 只跳過 CREATE TABLE,SQLAlchemy 2.0 仍對
__table_args__ Index 物件發出獨立 CREATE INDEX → duplicate error。
改法:先 inspect 取得現有 tables,只對不存在的 table 呼叫
table.create(),index 永遠只隨新 table 建立,不再 duplicate。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:18:25 +08:00
AWOOOI CD
8997ba70cb chore(cd): deploy a142e6e [skip ci] 2026-04-15 07:11:37 +00:00
OG T
a142e6e937 fix(db): create_all checkfirst=True 修復 CrashLoopBackOff
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 12m19s
rolling update 時 create_all 嘗試重建既有 index 導致
"ix_incident_evidence_incident_id already exists" 啟動失敗。
checkfirst=True 讓 SQLAlchemy 跳過已存在的 table/index,
init_db() 從此冪等,不再造成 CrashLoopBackOff。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:00:49 +08:00
OG T
777e40d618 Merge remote-tracking branch 'gitea/main'
All checks were successful
Type Sync Check / check-type-sync (push) Successful in 1m8s
2026-04-15 15:00:48 +08:00
OG T
83e0fd882d chore(types): 重新生成 shared-types — Playbook.trust_score + IncidentId3
因 Phase 0/1 新增 Playbook.trust_score 欄位,
IncidentId 型別索引序號更新為 IncidentId3,
重新執行 pnpm generate 同步 API schema → TypeScript 型別。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 15:00:44 +08:00
AWOOOI CD
d493fb9b78 chore(cd): deploy 7da64ea [skip ci] 2026-04-15 06:18:11 +00:00
OG T
7da64eaad2 feat(Phase 3): 學習閉環重建 — 三根因修復 + 2x EWMA + Evolver Agent
Some checks failed
CD Pipeline / build-and-deploy (push) Failing after 19m7s
Type Sync Check / check-type-sync (push) Failing after 1m18s
ADR-083 Phase 3 學習閉環重建:

**三根因修復**
- approval_execution.py: fire-and-forget create_task → await asyncio.wait_for(timeout=30) × 2
  (成功路徑 L265 + 失敗路徑 L353,超時記錄 learning_trigger_timeout metric,主流程不 crash)
- models/approval.py: ApprovalRequestBase 新增 matched_playbook_id 欄位
- decision_manager.py: _auto_execute 建立 ApprovalRequest 時填充 matched_playbook_id
- learning_service.py: 雙路徑查找 _matched_pb_id(matched_playbook_id + metadata fallback)

**2x EWMA 負向強化**
- models/playbook.py: 新增 trust_score: float = 0.3(EWMA 動態信任度欄位)
- repositories/playbook_repository.py: update_stats 加 EWMA
  成功: trust = 0.9 × old + 0.1 × 1.0
  失敗: trust = 0.8 × old + 0.2 × 0.0(衰減速度 2x)
  trust < 0.1 → log warning,等 Evolver 封存

**Evolver Agent(新建)**
- services/playbook_evolver.py: 三功能全靜態規則
  1. 低信任封存: trust < 0.1 → DEPRECATED
  2. 休眠封存: 30d 未使用 AND trust < 0.5 → DEPRECATED
  3. 相似合併: 症狀 Jaccard > 0.9 → 保留高 trust,封存低 trust
  AIOPS_P3_EVOLVER_ENABLED=False 預設關閉

**文件**
- ADR-083 學習閉環重建
- MASTER §8 Phase 3 完工記錄

AIOPS_P3_ENABLED=False(預設),骨架就位等統帥批准開啟

Co-Authored-By: Claude Sonnet 4.6(亞太)<noreply@anthropic.com>
2026-04-15 14:01:37 +08:00
AWOOOI CD
7edb298a75 chore(cd): deploy 42bc1df [skip ci] 2026-04-15 05:58:38 +00:00
OG T
42bc1df9f9 fix(phase2): 驗證發現兩處安全漏洞並修正
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
手動驗證執行中發現:
1. reviewer_agent.py: force push regex 只覆蓋「force push」文字順序,
   漏掉 git 實際格式「git push --force」(push 先, --force/-f 後)
   → 修正為雙向 pattern:(?:force.{0,5}push|push.{0,30}(?:--force|-f\b)).{0,30}main

2. coordinator_agent.py: Critic critical challenge 僅施 0.3 penalty,
   當原始信心 > 0.7(如 0.82)時 penalty 後仍 > 0.4 閾值,
   critical challenge 穿透到 auto-execute 路徑(驗證確認:0.82→0.52>0.4)
   → 新增 Critic REJECT 硬閘(等同 Reviewer REJECT 效力),
     在 penalty 邏輯前強制 requires_human_approval=True

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:48:55 +08:00
OG T
5ddba6d6e0 feat(adr-082): Phase 2 多 Agent 協作 — 5 角色辯證系統骨架上線
新增 5 個 Agent + Orchestrator + DecisionManager 接線:
- protocol.py: DiagnosisReport / ActionPlan / ReviewVerdict / CriticReport / DecisionPackage 型別系統
- DiagnosticianAgent: RCA 根因分析,confidence < 0.4 → ABSTAIN
- SolverAgent: 修復方案軍師,blast_radius 評分 + 降級 rule-based mock
- ReviewerAgent: 安全審查,HARD_RULES 靜態 pattern + blast_radius 閾值 (>50 revision, >80 reject)
- CriticAgent: 刻意唱反調,強制 3 問批判性思維,critical challenge → REJECT
- CoordinatorAgent: 純規則聚合,6 級決策閘,REQUEST_REVISION → 強制人工
- AgentOrchestrator: 30s 全局超時,Reviewer ‖ Critic 並行,DB Immutable Event Sourcing + Redis Streams
- DecisionManager: AIOPS_P2_ENABLED gate + _package_to_proposal_data 橋接既有 proposal_data 格式
- AgentSession DB table + 4 個複合 index
- ADR-082 決策記錄

Gate 2 修復(7 項):
- CRITICAL: DELETE FROM regex lookahead 位置錯誤(移至 FROM 後)
- CRITICAL: REQUEST_REVISION 可抵達 auto-execute 路徑(改回 requires_human_approval=True)
- IMPORTANT: _extract_json flat regex 不支援巢狀 JSON(改 find/rfind 邊界提取)
- IMPORTANT: all_degraded 遺漏 verdict.degraded(補全 4 個 Agent)
- IMPORTANT: Solver ABSTAIN guard 放行降級假設(改為無論 hypotheses 有無均跳過)
- IMPORTANT: dataclasses.asdict() Enum 未序列化導致 DB 寫入靜默失敗(加 json.dumps default handler)
- IMPORTANT: P2 gate 直讀屬性繞過父 Phase 守衛(改用 is_phase_enabled(2))

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:48:55 +08:00
AWOOOI CD
d51705b4ec chore(cd): deploy b6cb199 [skip ci] 2026-04-15 05:40:15 +00:00
OG T
b6cb1999a9 Merge remote-tracking branch 'gitea/main'
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 16m36s
2026-04-15 13:28:36 +08:00
OG T
cae9833e5d fix(heartbeat): 修復多 replica 重複發送系統報告 bug
根因:RedisLock 在 async with 結束後立即 release,
兩個 pod 對齊同一 slot 但 offset 不同,第一個 pod
發完釋放鎖後 ~10s,第二個 pod 剛好 wake 並搶到空鎖
→ 同一個 30min slot 發出兩條相同報告。

修復:改用 slot-based key (heartbeat:slot:{slot_id})
SET NX EX interval_seconds,不主動 release,讓 TTL
自然過期。整個 30min slot 只有第一個搶到的 pod 能發。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:17:10 +08:00
OG T
f1cbf6db7d feat(adr-081): Phase 1 感官縱深 — 8D 情報蒐集 + 執行後驗證
成品:
- IncidentEvidence DB model(8D 感官 + pre/post 執行狀態)
- EvidenceSnapshot dataclass(build_summary → LLM 上下文)
- SanitizationService(Prompt Injection 0-tolerance,12 pattern)
- MCPToolRegistry(動態工具登記,suggest_tools 不寫死告警類型)
- PreDecisionInvestigator(8D 並行感官,P99 < 8s,Redis 30s 快取)
- PostExecutionVerifier(warmup 10s → 後狀態評估 success/degraded/failed)
- decision_manager + approval_execution 接線(feature flag 守衛)

Gate 1 修復:D4/D5/D7/D8 補 sanitize_dict_values;移除裸 "error" failure
signal 防 error_rate key 誤判;evidence_snapshot rowcount 零行警告。

測試:130 passed(+111 新增)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 13:08:38 +08:00
OG T
db9e304a14 feat(adr-080): Phase 0 防護欄建立 — AI 自主化飛輪啟動
- docs/superpowers/specs/2026-04-15-MASTER-ai-autonomous-flywheel-v2.md
  (1456 行,§0-§8 全填完:42-cell 戰術矩陣、7 Phase 計畫、7 ADR 摘要、
   15 KPI、21 Feature Flags、10 風險場景)

- docs/adr/ADR-080-ai-autonomy-flywheel-overview.md
  (7 Phase 結構 + 4 北極星 + 7 架構師 Review Gates + Phase 退出條件)

- apps/api/src/core/feature_flags.py
  (AIOpsFeatureFlags: P1~P6 總開關全 False + 15 細粒度子開關
   is_phase_enabled() / is_sub_flag_enabled() + bool cast 安全)

- apps/api/src/jobs/__init__.py + baseline_snapshot.py
  (Phase 0 基線快照 Job:MCP calls / Playbook confidence / general 比例
   / learning loop rate / auto_repair — 寫入 aiops:baseline:latest)

- apps/api/tests/test_feature_flags.py  (21 tests — 全綠)

- docs/HARD_RULES.md → v1.9
  (新增 Phase 退出條件鐵律:禁止未過 exit conditions 宣告 Phase 完成)

- CLAUDE.md 防失憶閘門 1:強制讀 MASTER §0 Session Resume Protocol

Gate 0 Pass — 21/21 tests green

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 12:44:53 +08:00
AWOOOI CD
40aa7ceba8 chore(cd): deploy 6c7f648 [skip ci] 2026-04-15 03:10:45 +00:00
OG T
6c7f648b60 fix: 3 個飛輪沉默未打通節點 — 統帥截圖盤出
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 18m56s
統帥截圖證據 (Telegram MEDIUM 告警仍走人工審核):
INC-20260411-A03B2E / A2BB29 顯示「[規則匹配]」+ action=unknown-service

節點 1: AutoApprovePolicy 擋下規則匹配 (飛輪主因)
  - ADR-073 規則匹配 confidence=0.0 (防偽造)
  - AutoApprovePolicy.min_confidence=0.50 → 擋下
  - 結果: MEDIUM 規則匹配永遠人工審核,飛輪不轉
  修復: auto_approve.py 加 _is_rule_based 判斷
        (is_rule_based / source=expert_system / rule_id / matched_rule)
        → bypass min_confidence 檢查
        → 驗證: should_auto_approve=True 

節點 2: _is_bad_target 漏 unknown-service magic string
  - _resolve_target_from_k8s fallback 產 unknown-service / unknown-pod
  - GAP-A4 Phase 1/2 只擋 'unknown' 而非前綴
  修復: alert_rule_engine.py 加 unknown-/none-/null-/undefined- 前綴黑名單
        → 驗證: 4 個 magic 全 bad 

節點 3: stale_ready_tokens_resend 無時效過濾
  - 截圖是 2026-04-11 (4 天前) 告警
  - 舊 labels 過期,重 process 也產不出新 target
  - 壓爆 Ollama + 污染 Telegram 卡片
  修復: decision_manager.py 跳過 > 3 天的 stale incident
        → skip + log stale_ready_token_skipped_too_old

回歸: 113/113

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-15 10:56:48 +08:00
OG T
e3d7c92100 docs(Phase 5): ADR-079 狀態 Completed + LOGBOOK 午夜收官
- ADR-079 Sprint 5.0-5.4 全數完成,狀態改 Completed
- LOGBOOK 新增午夜條目記錄 Phase 5 落地

本日 26 commits 總覽:
cc42aa0 aae7c12 43c9689 dedd7c2 dd0a778 0f48a50 b8b124c 8de807c
f54dea4 6cac507 10b74af aa4e575 8b7e9cb 914c7e7 ca862c5 10e3043
72dd0c5 3f8d087 2a37d1c 094aa95 2e2f5a1 36754a8 581b244 208c28e
de8bbd8 a92562d

涵蓋:
- GAP-A1/A2/A3/A4 (4 個 gap + Phase 2)
- GAP-B1/B4 (timeout fix)
- GAP-C1/C2/C3 (BP-1 + retry + SSH KM)
- GAP-D1/D5 (信任度 + 日報 + Postmortem)
- Phase 5 全 Sprint (分類按鈕完整化)
- 4 BLOCKER 修復 + Bug A 診斷 + Bug B 真修
- 下架死按鈕 + 重啟新按鈕(從 registry 動態產生)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-15 10:46:40 +08:00
AWOOOI CD
a52b550607 chore(cd): deploy a92562d [skip ci] 2026-04-14 13:50:09 +00:00
OG T
a92562d65c feat(Phase 5 Sprint 5.4): 分類按鈕從 registry 動態產生 — 按鈕重啟上線
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 17m11s
_build_inline_keyboard() 改寫:
- 原 hardcode _CATEGORY_BUTTONS dict (28 按鈕) 已下架
- 改從 callback_action_spec.yaml registry 動態產生
- spec.callback_format 決定格式:
  * nonce (寫類) → self._security.generate_callback_nonce(approval_id, action_name)
  * info (查類) → {action_name}:{incident_id}
- 新按鈕只需改 yaml,零改 code

分類覆蓋 (從 yaml 自動推算):
- kubernetes: 6 按鈕 (4 寫 + 2 查)
- host_resource: 3 按鈕 (1 查 + 2 寫)
- secops: 4 按鈕 (全寫類 + Multi-Sig)
- database: 3 按鈕
- storage: 2 按鈕
- network: 3 按鈕
- devops_tool: 2 按鈕
- external_site: 2 按鈕
- business: 1 按鈕
- flywheel_health: 1 按鈕
- ssl_cert: 1 按鈕

這次按鈕不是鬼魂 — 每個都有:
 callback_format 正確 (4-part nonce / 2-part info)
 Sprint 5.3 dispatch handler 接收
 Sprint 5.2 MCP registry 執行
 audit log + reply_to 原卡片

回歸: 188/188

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-14 21:40:20 +08:00
OG T
de8bbd8ab9 feat(Phase 5 Sprint 5.3): 寫類分類按鈕 nonce action 路由 + audit log
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
插入點: _handle_callback_query Step 1.9 (nonce 驗證後, Step 2 approve/reject 前)

邏輯:
1. 從 spec registry 查 action 是否為註冊的寫類動作
2. 若 action in (approve/reject/silence/tune/log_manual_fix) → skip 走既有流程
3. 若 spec.requires_multi_sig=True 且 current_signatures < 2 → 提示「需 2 人簽核」
4. Audit log (category_write_action_audit_start) 含 user/risk/provider/tool
5. Ack Telegram (emoji + label + 執行中...)
6. 從 incident 取 labels 供模板替換
7. dispatch_action() → MCP 執行
8. Reply 結果到原告警卡片(Redis tg_msg lookup)
9. Audit log (category_write_action_audit_complete) 含 success/error/duration

支援的寫類 action:
- k8s_restart/scale_up/scale_down/rollback (kubernetes)
- host_restart_service/clear_log (host_resource)
- docker_restart/minio_restart (devops_tool/storage)
- reload_nginx/renew_cert (network/ssl_cert)
- kill_slow_query/clear_conn_pool (database)
- pause_1h/trigger_diagnose (business/flywheel)

Multi-Sig 支援 (Sprint 5.4 預留):
- secops_isolate/block_ip/evict → requires_multi_sig=True
- 簽核數未達 2 → 提示 + 不執行

回歸: 129/129

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-14 21:39:16 +08:00
AWOOOI CD
44545633a8 chore(cd): deploy 208c28e [skip ci] 2026-04-14 12:53:38 +00:00
OG T
208c28ed09 feat(Phase 5 Sprint 5.2): Callback dispatcher 接入真實 MCP registry
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 14m38s
dispatch_action() 升級:
- 從 Sprint 5.0 stub 升級為真實 MCP 調用
- internal provider: URL builder + authorization 記錄(不走 MCP)
- 其他 provider: from src.plugins.mcp.registry import get_provider → execute
- asyncio.wait_for 包 timeout_sec(按 spec 設定,每按鈕不同)

Graceful degradation:
- Provider 未註冊 → returns success=False + 'provider_not_found' 錯誤
- MCP returned success=False → reply 含錯誤訊息
- asyncio.TimeoutError → reply 「超時 Xs」+ log

新增 _handle_internal_action():
- build_signoz_url → https://signoz.wooo.work/services/{service}
- build_flywheel_url → https://awoooi.wooo.work/flywheel
- record_authorization → 24h 同源靜默確認

測試覆蓋 (26/26):
- 3 新 internal action tests (open_signoz/open_flywheel/secops_authorize)
- 1 MCP failure graceful test
- 既有 22 個保留(更新 2 個 Sprint 5.0 stub 測試為 Sprint 5.2 graceful)

Sprint 5.2 DOD:
 10 查類按鈕 dispatch 路徑完整
 3 internal actions 實作
 Graceful failure (no crash)
 asyncio.wait_for timeout 保護
 實際 end-to-end 測試(需 prod MCP providers 都註冊)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-14 20:43:40 +08:00
OG T
581b244ad1 feat(Phase 5 Sprint 5.1): Telegram callback_handler 接上 dispatcher
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
整合點: _handle_callback_query 未知 action fallback 路徑

變更:
1. Line 2601 原「⚠️ 未知操作」改呼叫 _dispatch_category_action()
2. 新增 _dispatch_category_action() method:
   - 查 callback_action_spec registry
   - 若 action 不存在 → 回「未知操作」(行為不變)
   - 若存在 → acknowledge + 從 incident 取 labels + dispatch + reply 原卡片

效果:
- check_process / check_port / check_log_* / check_health / open_signoz /
  open_flywheel 等 10 個查類按鈕現在有完整 flow(雖 Sprint 5.2 還沒接 MCP,但 stub 會 reply)
- 當 CD 部署 + Sprint 5.2 實裝 MCP 接線後,查類按鈕自動上線

Sprint 5.1 DOD:
-  callback_handler 接線 _dispatch_category_action
-  Dispatcher 讀 incident labels 替換模板變數
-  Reply to 原告警卡片(Redis tg_msg lookup)
-  MCP 實際執行(Sprint 5.2)

回歸測試: 109/109

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-14 20:41:22 +08:00
OG T
36754a8a84 fix: Bug A 診斷 + Bug B 真修 — LLM 120s/130s 硬編 → OPENCLAW_TIMEOUT
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
殘留兩個深層 bug 處理:

Bug A (approval.incident_id 仍 NULL) — 加診斷
  - update_incident_id 加 rowcount 檢查
  - 若 UPDATE 0 rows affected → warning log (id 型別 mismatch 或 session 不同步)
  - 手動 UPDATE 測試通過 → DB/permissions 正常,問題在應用層
  - 等 CD 部署後 live-fire 觀察 log 診斷真因

Bug B (LLM 仍 2m6s >> 30s) — 真修
  openclaw.py 兩處硬編 timeout:
  - line 146 httpx client default: 120.0s → settings.OPENCLAW_TIMEOUT (30s)
  - line 348 /analyze/incident POST: 130.0s → settings.OPENCLAW_TIMEOUT (30s)
  GAP-B4 commit dd0a778 只修了 ai_providers/ollama.py
  但 openclaw.py 自己的 httpx client 和 endpoint call 沒改
  這就是為什麼 Live-fire #2-#7 都卡 120s+ 的真因

回歸測試: 125/125 (dispatcher + a4 + classify + grouping)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-14 20:38:00 +08:00
OG T
2e2f5a1881 feat(Phase 5 Sprint 5.0): Callback Dispatcher 規格 + 骨架 + 22 測試
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
統帥批准 Phase 5 全 Sprint,Sprint 5.0 產出:

1. callback_action_spec.yaml (24 actions)
   - 10 查類 (info 2-part callback, 無副作用): check_process, check_port,
     check_log_*, check_health, check_pod_logs, describe_pod, open_signoz,
     open_flywheel
   - 10 寫類 (nonce 4-part, 有副作用): k8s_restart/scale_up/scale_down/rollback,
     host_restart_service/clear_log, docker_restart, minio_restart,
     reload_nginx, renew_cert
   - 4 secops (Multi-Sig CRITICAL): secops_isolate/block_ip/evict/authorize

2. callback_dispatcher.py
   - Registry pattern (lru_cache): get_action_spec / list_actions_for_category
   - 模板變數替換: {incident_id} / {labels.xxx} / {signals[0].xxx}
   - dispatch_action() 骨架 (Sprint 5.2+ 接 MCP)
   - _format_reply: text/code/truncated/url 4 種格式

3. test_callback_dispatcher.py (22 tests全過)
   - Registry loading 正確性
   - Category filtering
   - Template resolution (含 nested list index)
   - dispatch stub 返回正確 spec 提示

下一步 Sprint 5.1: 接入 MCP registry + telegram callback_handler 整合
MCP 底層能力已有 (k8s 10+ tools, ssh 15 tools)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-14 20:34:14 +08:00
AWOOOI CD
a120cc45b8 chore(cd): deploy 10e3043 [skip ci] 2026-04-14 12:29:34 +00:00
OG T
50edeaa9ea docs(Phase 5): 分類按鈕完整化 — 完整解決方案與實施步驟
統帥要求「提出完整的解決方案和詳細的實施步驟」→ 本 plan 回覆。

內容涵蓋:
- 28 按鈕完整 action → MCP tool 對應表(3 類:查/寫/secops)
- 6 個 Sprint 工作分解(5.0 規格 → 5.1 dispatch → 5.2 查類 → 5.3 寫類 → 5.4 secops → 5.5 E2E)
- 架構設計決策(callback_dispatcher registry pattern)
- 依賴與風險矩陣
- 5 個 E2E 驗收案例
- Rollout 策略(查類先上線,觀察 24h 再上寫類)

估時: 3-5 天(總計 5.5 工作日)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-14 20:22:03 +08:00
OG T
10e3043ce8 fix(UX): 下架 28 個鬼魂分類按鈕 + ADR-079 Phase 5 補完計畫
Some checks failed
CD Pipeline / build-and-deploy (push) Has been cancelled
統帥 2026-04-14 20:00 完整 audit 揭露:
_CATEGORY_BUTTONS 28 個按鈕全死 3 天(從 2026-04-11 commit 325b3851)
- callback_data 格式全錯(3-part 不符 parser 4-part/2-part)
- grep apps/api/src 無任何 dispatch handler
- 統帥今天真踩到:點「查程序」沒反應 → 信任破壞

首席架構師裁示 (C 分級):
A. 立刻下架(本 commit):_CATEGORY_BUTTONS = {} fallback 通用按鈕
B. Phase 5 完整化(ADR-079 規劃,3-5 天,另 Sprint 實作)

保留通用按鈕(全 ):
- 批准 / 拒絕 / 靜默(4-part nonce)
- 詳情 / 歷史 / 重診(2-part info)

新增防禦性文件:
- ADR-079 — Phase 5 工作分解 + 每按鈕 checklist
- feedback_no_ghost_buttons.md(memory)— 鬼魂按鈕鐵律

設計原則永久入檔: 寧可沒按鈕,不可有死按鈕

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-14 20:19:25 +08:00