diff --git a/docs/superpowers/plans/2026-04-19-aider-watch.md b/docs/superpowers/plans/2026-04-19-aider-watch.md index a8933afd..ab6f70db 100644 --- a/docs/superpowers/plans/2026-04-19-aider-watch.md +++ b/docs/superpowers/plans/2026-04-19-aider-watch.md @@ -1,4 +1,8 @@ -# aider-watch Implementation Plan +# aider-watch Implementation Plan(v1 — ⛔ DEPRECATED 2026-04-20) + +> ⛔ **已被 v2 取代** — 統帥於 2026-04-20 改走「完全整合進 awoooi」路線。 +> 新版 plan:[2026-04-20-aider-watch-v2.md](2026-04-20-aider-watch-v2.md) +> v1 Task 0-5 已完成(~/aider-watch 8 commits),events.py + redactor.py 會搬進 awoooi。 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. diff --git a/docs/superpowers/specs/2026-04-19-aider-watch-design.md b/docs/superpowers/specs/2026-04-19-aider-watch-design.md index f0b0e418..5ea103bb 100644 --- a/docs/superpowers/specs/2026-04-19-aider-watch-design.md +++ b/docs/superpowers/specs/2026-04-19-aider-watch-design.md @@ -1,4 +1,9 @@ -# aider-watch 設計稿 +# aider-watch 設計稿(v1 — ⛔ DEPRECATED 2026-04-20) + +> ⛔ **已被 v2 取代** — 統帥於 2026-04-20 指出此設計未對齊 awoooi AI 自主化飛輪全景, +> 獨立 PG + 獨立 bot + 獨立 repo 路線與 MASTER blueprint 割裂。 +> 新版 spec:[2026-04-20-aider-watch-v2-design.md](2026-04-20-aider-watch-v2-design.md) +> v1 保留僅供歷史對照;實作已停在 ~/aider-watch Task 5(8 commits)。 > 統帥本機 aider CLI 的全程監控系統 > 2026-04-19 Brainstorm 定稿,經統帥 §1-§7 逐段批准 diff --git a/docs/superpowers/specs/2026-04-20-aider-watch-v2-design.md b/docs/superpowers/specs/2026-04-20-aider-watch-v2-design.md new file mode 100644 index 00000000..cdcad192 --- /dev/null +++ b/docs/superpowers/specs/2026-04-20-aider-watch-v2-design.md @@ -0,0 +1,340 @@ +# aider-watch v2 設計稿 — 完全整合 awoooi 飛輪版 + +> **建立**:2026-04-20 @ Asia/Taipei +> **取代**:[v1 2026-04-19](2026-04-19-aider-watch-design.md)(已 DEPRECATED) +> **觸發**:統帥 2026-04-20 指示「C 路線 + 甲 bot」— 把 aider-watch 完全整合進 awoooi AI 自主化飛輪,而非獨立個人工具 + +--- + +## 0. 為何重寫 + +v1 把 aider-watch 做成 **獨立個人工具**: +- 獨立 repo `~/aider-watch` +- 獨立 PG DB `aider_watch`(放 188 但與 awoooi 平行) +- 獨立 Telegram bot `@NemoTronAwoooI_Bot` +- 被動記錄,無 AI 學習 + +**根本問題**:純記錄 ≠ AI 自主化。違反 `feedback_ai_autonomous_direction.md`(🔴🔴🔴 最高鐵律)的「AI 自主化北極星」— 設計裡沒有 learning、沒有 auto-repair、沒有 decision feedback loop。 + +**v2 方向**(統帥批准): +- ✅ 進 awoooi 主 PG(新 migration 一張 `aider_events` 表) +- ✅ 走 awoooi 既有 Telegram 告警鏈(`@tsenyangbot` + Redis dedup) +- ✅ 接進 AI Router feedback loop(Phase 24 ADR-052) +- ✅ aider error → 自動建 `incident`(走既有事件管線) +- ✅ 從 aider events 抽 `symptom_pattern` → 餵 `playbooks` 學習 +- ✅ Mac client 端保留為薄殼,純 HTTP 推送 + 本機 fallback buffer + +--- + +## §1 架構總覽(全景) + +``` +┌──────────── 統帥 Mac (外部 agent, K3s 外)────────────┐ +│ │ +│ aiderw (Python wrapper) │ +│ ├ subprocess aider + stdout tee │ +│ ├ 退出時 git diff / chat_history.md canonical rebuild │ +│ ├ redact secrets(本地先做一遍) │ +│ └ HTTP POST events → AWOOOI API (HMAC-signed) │ +│ │ +│ 本機 fallback: ~/aider-watch/buffer/*.jsonl │ +│ (API 不可達時寫這裡,launchd flush job 5min 補送) │ +│ │ +│ 本機只留: live.log (append-only, tail -F 用) │ +│ 無本機 PG,無本機 report │ +└──────────────┬───────────────────────────────────────────┘ + │ HTTPS + HMAC-SHA256 + ▼ +┌────── AWOOOI API (K3s svc 192.168.0.120:32334) ──────────┐ +│ │ +│ api/v1/aider_events.py │ +│ POST /api/v1/aider/events (HMAC verified) │ +│ → push Redis stream signals:aider:events │ +│ │ +│ jobs/aider_event_processor_job.py (loop, 5s poll) │ +│ ├ consume Redis stream │ +│ ├ write aider_events table │ +│ ├ classify: │ +│ │ error / non-zero exit / silent_timeout │ +│ │ → 建 incident(走 incident_service) │ +│ │ severity: silent=P3, error=P2, multi-error=P1 │ +│ │ alert_category: aider_activity │ +│ │ → incident_service 自己觸發 TG (既有 dedup 生效) │ +│ │ │ +│ └ 每 day 聚合: extract symptom_pattern │ +│ → 寫 playbooks.symptom_pattern JSONB │ +│ 例: {repo: "awoooi", model: "elephant", error_rate: 0.3} │ +│ │ +│ services/ai_router.py (既有, Phase 24) │ +│ 新增 hook: feedback_from_aider_events() │ +│ → 讀過去 7 日 aider_events: │ +│ 哪 model × 哪 repo/task 成功率 vs 失敗率 │ +│ → 調整 route() 的 provider priority │ +│ │ +│ services/telegram_gateway.py (既有, 不動) │ +│ incident → TG @tsenyangbot + Redis dedup 10min TTL │ +└──────────────────────────────────────────────────────────┘ +``` + +**關鍵設計決定**: + +1. **aider error → incident → 既有鏈路**:不做另一套告警機制,aider 的錯誤等同 awoooi 其他來源的錯誤,統一 incident table 統一 TG 通道。 +2. **Event 進 Redis stream 再處理**:沿用 Phase 6.1 Event Bus pattern。API 層快 response(<50ms),處理在背景。 +3. **AI Router feedback 是學習閉環的核心**:這就是「AI 自主化」的體現 — aider-watch 不只是記錄,是餵給 AI Router 讓 model 選擇越來越準。 +4. **symptom_pattern 抽取**:日 batch job,把 aider 失敗模式抽成 playbook candidate(跟 Phase 7 blindspot governance 同一機制)。 +5. **Mac 端盡量薄**:只做 event capture + HTTP POST + local buffer。所有商業邏輯在 server。 + +--- + +## §2 元件清單 + +### 2.1 AWOOOI 內新增(Server 端) + +| # | 檔案 | 職責 | 既有模式參考 | +|---|------|------|--------------| +| S1 | `apps/api/migrations/adr091_aider_events_schema.sql` | DB migration | 既有 `adr090_asset_inventory_foundation.sql` | +| S2 | `apps/api/src/models/aider.py` | Pydantic: `AiderEvent`, `AiderSessionStart`, `AiderFileEdit`, `AiderError`, `AiderSessionEnd`(6 種 + 通用外殼) | `models/incident.py` | +| S3 | `apps/api/src/repositories/aider_event_repository.py` | CRUD aider_events + 聚合查詢 | `repositories/incident_repository.py` | +| S4 | `apps/api/src/services/aider_event_service.py` | 分類、建 incident、抽 symptom_pattern | `services/incident_service.py` | +| S5 | `apps/api/src/api/v1/aider_events.py` | POST webhook + HMAC 驗證 | `api/v1/webhooks.py` (Alertmanager) | +| S6 | `apps/api/src/jobs/aider_event_processor_job.py` | Redis stream consumer + 分類 dispatcher + 日 batch pattern extractor | `jobs/asset_scanner_job.py` | +| S7 | `apps/api/src/services/ai_router.py` 新增 `feedback_from_aider_events()` | 從 aider_events 聚合統計 → 調整 model priority | 既有檔改一個 method | +| S8 | `apps/api/src/utils/secret_redactor.py` | 泛用 secret redactor(**從 v1 搬過來**) | 目前 awoooi 無,新增 | +| S9 | `apps/api/src/core/config.py` 新增 3 個 settings | `AIDER_WEBHOOK_SECRET`, `AIDER_EVENTS_STREAM_KEY`, `AIDER_PATTERN_EXTRACT_INTERVAL_HOURS` | 既有 core/config.py | +| S10 | `apps/api/src/main.py` lifespan 註冊 | `asyncio.create_task(run_aider_event_processor_loop())` | 既有 378-382 pattern | + +### 2.2 Mac 端(Client) + +**位置**:`awoooi/scripts/aider_watch_client/`(進 awoooi repo,不是獨立 repo) + +| # | 檔案 | 職責 | +|---|------|------| +| M1 | `aider_watch_client/aiderw.py` | subprocess aider + event capture + HTTP POST | +| M2 | `aider_watch_client/parsers.py` | aider stdout banner / chat_history.md / git numstat(從 v1 搬) | +| M3 | `aider_watch_client/api_client.py` | HTTP POST with HMAC + retry + buffer fallback | +| M4 | `aider_watch_client/buffer.py` | JSONL buffer(本機 fallback) | +| M5 | `aider_watch_client/install.sh` | 在 Mac 安裝(pipx or venv)+ 註冊 launchd flush job | +| M6 | `aider_watch_client/launchd/com.awoooi.aider-flush.plist` | 每 5min flush buffer | + +### 2.3 舊 v1 產物去向 + +| v1 產物 | v2 處理 | +|---------|---------| +| `~/aider-watch/aider_watch/events.py` | ✅ 搬 `apps/api/src/models/aider.py`(改為 awoooi 命名) | +| `~/aider-watch/aider_watch/redactor.py` | ✅ 搬 `apps/api/src/utils/secret_redactor.py` + 同一份用於 Mac client | +| `~/aider-watch/aider_watch/telegram.py` | ❌ 廢棄(走 awoooi telegram_gateway) | +| `~/aider-watch/aider_watch/config.py` | ⚠️ 拆:Mac 端用的部分搬進 `aider_watch_client/`;server 的改讀 awoooi `core/config.py` | +| `~/aider-watch/aider_watch/wrapper.py`(未完成) | 簡化搬進 `aider_watch_client/aiderw.py` | +| `~/aider-watch/bin/aiderw` | 搬 `aider_watch_client/bin/aiderw` | +| `~/aider-watch/pyproject.toml` | 改為 `aider_watch_client/pyproject.toml`(client 端獨立 pipx 裝) | +| `~/aider-watch/tests/*` | 搬:client 測試留 client,server 測試改寫走 awoooi pytest 約定 | +| `~/aider-watch/schema.sql` + `install_pg.sh` | ❌ 廢棄(v2 用 awoooi migration) | +| `~/aider-watch/` repo 本身 | 保留 1 週作備份,2026-04-27 後刪(或歸 archive 分支) | + +--- + +## §3 Event Schema(與 v1 一致,微調) + +7 種 event type,Mac 客戶端 POST 的 payload shape: + +```json +{ + "ts": "2026-04-20T10:15:33+08:00", + "session_id": "01J7XZ...", // ULID + "host": "ogt-mac", // 將來多機器區分 + "type": "session_start|file_edit|error|commit|silent_timeout|session_end|raw", + "payload": { ... type-specific (同 v1 §3) } +} +``` + +**批次推送**:`POST /api/v1/aider/events` body 接受 `{"events": [...]}` 陣列,最多 50 筆/次,降低 HTTP 往返成本。 + +--- + +## §4 DB Schema — awoooi 主 PG 新 migration + +**Migration**:`adr091_aider_events_schema.sql` + +```sql +-- aider events raw table(單一表,event + 一次性 session 元資料合一用 JSONB) +-- 設計參考: asset_discovery_run pattern +-- 2026-04-20 @ Asia/Taipei + +CREATE TABLE IF NOT EXISTS aider_events ( + id BIGSERIAL PRIMARY KEY, + session_id TEXT NOT NULL, + ts TIMESTAMPTZ NOT NULL, + type TEXT NOT NULL, -- session_start / file_edit / error / ... + host TEXT DEFAULT 'ogt-mac', + payload JSONB NOT NULL, + incident_id TEXT, -- 若觸發建 incident,記 FK + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); +CREATE INDEX aider_events_session_idx ON aider_events(session_id); +CREATE INDEX aider_events_type_ts_idx ON aider_events(type, ts DESC); +CREATE INDEX aider_events_ts_idx ON aider_events(ts DESC); +-- payload GIN for 查 repo / model 統計 +CREATE INDEX aider_events_payload_gin ON aider_events USING GIN (payload); + +-- 不另外建 sessions 表:從 events 聚合(session_start + session_end 配對), +-- 查詢性能可接受(session 量 <1000/day),避免雙寫漂移。 +``` + +**symptom_pattern 抽取**:不新增表,直接寫 `playbooks` 表的 `symptom_pattern` JSONB(既有): + +```json +{ + "source": "aider_watch", + "repo": "awoooi", + "model": "elephant-alpha", + "task_kind": "refactor", + "error_rate": 0.35, + "evidence_session_ids": ["01J...", "01J..."] +} +``` + +--- + +## §5 API 合約 + +### POST /api/v1/aider/events + +**Request**: +```http +POST /api/v1/aider/events +Content-Type: application/json +X-Aider-Signature: sha256= +X-Aider-Client: aiderw/0.2.0 + +{ + "events": [ + { "ts": "...", "session_id": "...", "type": "session_start", "payload": {...} }, + ... + ] +} +``` + +**Response**: +- `202 Accepted` → `{"accepted": N, "stream_id": "redis-id"}`(快速 ack,不等處理完成) +- `401 Unauthorized` → HMAC 驗證失敗 +- `400 Bad Request` → schema 驗證失敗,回具體錯誤欄位 +- `429 Too Many Requests` → 超過 rate limit(預設 120 req/min per client) +- `503 Service Unavailable` → Redis 不可達(client 必須 fallback 到 buffer) + +**HMAC 驗證**: +```python +import hmac, hashlib +expected = "sha256=" + hmac.new( + AIDER_WEBHOOK_SECRET.encode(), + request.body, hashlib.sha256 +).hexdigest() +if not hmac.compare_digest(expected, signature): + abort(401) +``` + +--- + +## §6 AI 學習回路 + +### 6.1 incident 自動建立(即時) +`aider_event_service.handle_error_event(ev)`: +- 若 `type in {"error", "session_end with exit≠0", "silent_timeout"}`: + - 建 incident: + - `alert_category = "aider_activity"` + - `severity = P1 if error_count>=3 else P2 if error else P3 if silent_timeout` + - `affected_services = [repo_name]` + - `signals = {source: "aider_watch", session_id, model, last_error_message}` + - incident_service 自動觸發既有 Telegram gateway(dedup 10min TTL 自動生效) + +### 6.2 symptom_pattern 日 batch 抽取 +`aider_event_processor_job.extract_patterns_daily()`(每日 02:30 台北): +- 聚合近 7 日 aider_events +- group by (repo, model, task_kind) +- 計算 error_rate / avg_tokens / avg_duration +- 若 `error_rate >= 0.25` 且 `sample_n >= 3` → 寫 playbook candidate + +### 6.3 AI Router feedback hook(每次 route() 呼叫) +`ai_router.py` 加: +```python +def feedback_from_aider_events(repo: str, task_kind: str) -> dict[str, float]: + """回傳 {model_name: success_rate} based on past 7 days aider usage.""" + # 從 aider_event_repository 聚合 + return {"elephant-alpha": 0.85, "gemini-pro": 0.92, ...} +``` +在 `AIRouter.route()` 內:如果有 feedback data,把 provider 權重乘 `success_rate`。 + +--- + +## §7 Telegram 整合 + +**100% 複用既有 `services/telegram_gateway.py`,零新增 bot**: + +- aider error → incident created → `telegram_gateway.send_alert(incident)` +- 訊息格式走 awoooi SOUL.md 標準(不再自訂 🚀/🏁 emoji 模板) +- Redis dedup `telegram_sent:{incident_id}` TTL 600s 自動生效 +- bot `@tsenyangbot`,chat_id 從 K8s secret `TELEGRAM_CHAT_ID` 讀 + +**aider 非 error 事件(session_start / file_edit / commit)**:**不推 Telegram**,只寫 aider_events 表。理由: +- awoooi Telegram 是 **告警通道**,不該塞正常活動洗版 +- 統帥要看活動 → 下次加 `/api/v1/aider/activity_feed` REST 查詢或前端 dashboard +- 若你堅持要推,單獨開 `AIDER_WATCH_PUSH_ACTIVITY` flag 預設 false + +### ⚠️ v1 @NemoTronAwoooI_Bot 怎麼處理 +- 這支 bot 2026-04-19 才建,無生產依賴 +- v2 不用它 → 建議 **deactivate** 或 **改用途**(例如 aider 測試 sandbox 用) +- 不刪 bot(BotFather 刪除不可逆) + +--- + +## §8 錯誤處理 / 降級策略 + +| 失敗情境 | 處理 | 結果 | +|---------|------|------| +| **AWOOOI API 不可達** | Mac client 寫 `~/aider-watch/buffer/*.jsonl`;launchd flush job 每 5min 重試 | 不丟資料 | +| **HMAC 驗證失敗** | API 回 401,記 `audit_log`;Mac client 留 buffer 等人工介入 | 防偽造 | +| **Redis stream 滿** | 自動 trim 10k 筆上限;溢位寫 `audit_log` warning | 不阻塞 API | +| **aider_event_processor 掛** | 既有 main.py lifespan supervisor 會重啟;消費位置從 Redis stream consumer group 恢復 | 自癒 | +| **incident_service 建 incident 失敗** | 降級:只寫 aider_events 表,不建 incident;TG 不推(可接受,event 還在) | 不丟資料 | +| **secret 外洩** | Mac client 進 buffer 前先 redact;server 再 redact 一次(depth-in) | 雙層防線 | +| **wrapper 崩潰** | aiderw 外層 try/except 全包;atexit 補 session_end | aider 照跑 | +| **aider 本身崩潰** | wrapper 收 SIGCHLD → 送 error event + session_end exit≠0 | 死得清楚 | + +--- + +## §9 測試策略 + +遵循 `feedback_no_mock_testing.md`: + +| 層級 | 範圍 | 工具 | 通過標準 | +|------|------|------|----------| +| **Unit (server)** | models schema, secret_redactor, HMAC 驗證, pattern extractor | pytest | 100% pass | +| **Unit (client)** | aiderw parsers, api_client retry, buffer write | pytest | 100% pass | +| **Integration (server)** | 真寫 PG `aider_events`, Redis stream round-trip | pytest + real PG (168 test schema) | round-trip OK | +| **Integration (client→server)** | Mac client POST events → server 消費 → 寫 DB → 查詢 | 本機 pytest + 打 awoooi API | 全流程通 | +| **E2E happy** | 真 aiderw 跑一次 aider →events 進 awoooi DB → 若 error 建 incident → TG 收到 | 手動 | TG 收到(走 @tsenyangbot 不是新 bot) | +| **E2E degradation** | 拔網路跑 aiderw → buffer 有檔 → 網路恢復 + flush job 跑 → buffer 清空 + DB 補齊 | 手動 | buffer → DB 無漏 | +| **AI Router feedback** | 灌 10 場 aider session 資料 → 查 ai_router.feedback_from_aider_events 回傳值 → 驗 success_rate 合理 | pytest | 數值正確 | + +--- + +## §10 相關 Memory 依據 + +- `feedback_ai_autonomous_direction.md` 🔴🔴🔴 — AI 自主化北極星(這是 v2 存在的根本原因) +- `feedback_alertmanager_awoooi_flow.md` — 告警鏈路 Alertmanager→AWOOOI API→TG +- `feedback_telegram_dedup.md` — Redis dedup 10min TTL +- `feedback_secrets_leak_incidents_2026-04-18.md` — secret 雙層 redact +- `feedback_architecture_review_gates.md` 🔴🔴 — 重大方向變更需架構 review(本 v2 就是) +- `feedback_solution_adoption_checklist.md` — 解決方案導入 7 問(已對照) +- `project_master_aiops_blueprint.md` — AI 自主化 MASTER blueprint 全景 +- `project_blindspot_governance.md` 🔴🔴🔴 — Phase 7 盲區治理(symptom_pattern 抽取沿用) +- `project_phase24_ai_router.md` — AI Router D1-D14 決策 + +--- + +## §11 後續 + +本設計批准後: +1. 寫 v2 plan(`2026-04-20-aider-watch-v2.md`) +2. 暫停 `~/aider-watch` repo 開發(Task 6 不跑 install_pg.sh) +3. 按 v2 plan 執行 server + client 雙半實作 +4. Mac client 部署在 awoooi repo 而非獨立 diff --git a/services/ai_advisory_helpers.py b/services/ai_advisory_helpers.py new file mode 100644 index 00000000..e69de29b