403 lines
15 KiB
Markdown
403 lines
15 KiB
Markdown
# AWOOOI 最終執行主排程
|
||
# Master Execution Schedule — 統帥審核版
|
||
|
||
> **文件類型**: 最終執行授權書
|
||
> **建立**: 2026-03-29 14:05 (台北)
|
||
> **狀態**: 🟢 執行中 (Wave 1 已完成,進入 Wave 2)
|
||
> **本文件為所有 RunBook 和 ADR 的執行定序總綱**
|
||
|
||
---
|
||
|
||
## 第一章:最終確認的缺口清單(代碼確認級別)
|
||
|
||
### 1.1 已確認真實存在的問題(共 16 項)
|
||
|
||
| # | 問題 | 代碼位置 | 嚴重度 | 波次 |
|
||
|---|------|---------|--------|------|
|
||
| 1 | Worker stop() timeout 只有 5 秒 | `signal_worker.py:147` | 🔴 P0 | Wave 1 |
|
||
| 2 | XCLAIM / Active Sweeper 完全缺失 | `signal_worker.py` 全文 | 🔴 P0 | Wave 1 |
|
||
| 3 | StatefulSet 自動修復無硬阻斷 | `auto_repair_service.py:159` | 🔴 P0 | Wave 1 |
|
||
| 4 | AnomalyCounter Redis 無 try/except | `anomaly_counter.py:147` | 🔴 P0 | Wave 1 |
|
||
| 5 | OpenClaw 無 Circuit Breaker | `sentry_webhook.py:289` | 🔴 P0 | Wave 1 |
|
||
| 6 | OpenClaw 無 Concurrency Semaphore | `sentry_webhook.py` | 🔴 P0 | Wave 1 |
|
||
| 7 | Global Incident Debounce 缺失 | `incident_service.py` | 🔴 P0 | Wave 1 |
|
||
| 8 | Global Auto-Repair Cooldown 缺失 | `auto_repair_service.py` | 🔴 P0 | Wave 1 |
|
||
| 9 | terminationGracePeriodSeconds 未設定 | `08-deployment-worker.yaml` | 🔴 P0 | Wave 2 |
|
||
| 10 | ESLint i18n Plugin 只有 TODO | `.eslintrc.js:20-22` | 🟠 P1 | Wave 3 |
|
||
| 11 | i18n 40+ 違規 | `TECHNICAL_DEBT_PHASE2.md` | 🟠 P1 | Wave 3 |
|
||
| 12 | Playwright ignoreHTTPSErrors 未設定 | `playwright.config.ts` | 🟠 P1 | Wave 4 |
|
||
| 13 | Visual Baseline 無 Docker 規範 | (設計空白) | 🟠 P1 | Wave 4 |
|
||
| 14 | E2E 無 Auth Bypass(global.setup.ts 缺失)| `tests/e2e/` | 🟠 P1 | Wave 4 |
|
||
| 15 | SSE Event Sourcing 尚未實作 | `terminal.py` | 🟡 P2 | Wave 7 |
|
||
| 16 | Redis AOF/eviction 未確認 | `.188 主機` | 🔴 P0 | Wave 0 |
|
||
|
||
### 1.2 已確認不存在(稽核報告誤判)
|
||
|
||
| 項目 | 誤判內容 | 真實現況 |
|
||
|------|---------|---------|
|
||
| Worker SIGTERM 缺失 | 報告說「需要實作」| ✅ 已實作(line 450-455)|
|
||
| ADR-035 備援路徑 | 說「可觀測循環依賴」| ✅ Layer 3 繞過 AWOOOI 直接打 Telegram |
|
||
| Sentry Comment 缺失 | 說「尚未整合」| ✅ LOGBOOK 確認 Wave A.4 已整合 |
|
||
| CD Secret 注入 | 說「缺失」| ✅ ADR-035 確認 CD 已有自動注入 |
|
||
|
||
---
|
||
|
||
## 第二章:ADR 評估
|
||
|
||
### 2.1 本次新建 ADR(已建立)
|
||
|
||
| ADR | 標題 | 說明 |
|
||
|-----|------|------|
|
||
| [ADR-038](file:///Users/ogt/awoooi/docs/adr/ADR-038-openclaw-concurrency-governance.md) | OpenClaw 推理引擎併發治理 | Semaphore + Circuit Breaker 雙層保護 |
|
||
| [ADR-039](file:///Users/ogt/awoooi/docs/adr/ADR-039-global-autorepair-governance.md) | 全域自動修復熔斷機制 | Global Cooldown + StatefulSet 黑名單 |
|
||
|
||
### 2.2 現有 ADR 需更新(次要)
|
||
|
||
| ADR | 需追加內容 | 優先度 |
|
||
|-----|---------|--------|
|
||
| ADR-020 E2E Verification | 加入 global.setup.ts 和 Auth Bypass 規範 | 🟡 Wave 4 前 |
|
||
| ADR-028 Failure Auto-Repair | 加入對 ADR-039 的引用說明 | 🟡 Wave 1 後 |
|
||
|
||
### 2.3 不需要新建 ADR 的項目
|
||
|
||
| 項目 | 理由 |
|
||
|------|------|
|
||
| XCLAIM / Active Sweeper | 屬於 ADR-037 Signal Worker 實作細節 |
|
||
| terminationGracePeriodSeconds | 屬於 K8s 操作規範,不是架構決策 |
|
||
| ESLint i18n | 屬於 ADR-002 設計系統的工具鏈細節 |
|
||
|
||
---
|
||
|
||
## 第三章:Skills 更新評估
|
||
|
||
### 3.1 必須更新的 Skills
|
||
|
||
#### Skill 02: leWOOOgo Backend Core(新增章節)
|
||
|
||
```markdown
|
||
## 🛡️ OpenClaw 推理保護模式 (ADR-038, 2026-03-29)
|
||
|
||
### 鐵律:所有 OpenClaw 呼叫必須雙層保護
|
||
|
||
from src.core.circuit_breaker import get_openclaw_guard
|
||
|
||
async def call_openclaw_analyzer(...):
|
||
guard = get_openclaw_guard()
|
||
if guard.is_circuit_open(): # Layer 1: 斷路
|
||
return None
|
||
async with guard.semaphore: # Layer 2: 限流(最多 3 並發)
|
||
# ... httpx 請求 ...
|
||
|
||
## 🔴 全域修復冷卻 (ADR-039, 2026-03-29)
|
||
|
||
### 鐵律:任何自動修復前必須呼叫 check_global_repair_cooldown()
|
||
|
||
可以修復的服務: 僅無狀態服務(awoooi-api, awoooi-web, awoooi-worker)
|
||
絕對禁止修復: postgres, redis, clickhouse, minio, etcd
|
||
```
|
||
|
||
#### Skill 05: AWOOOI SRE & QA(新增章節)
|
||
|
||
```markdown
|
||
## 🎭 E2E Auth Bypass 鐵律 (2026-03-29)
|
||
|
||
### 必須在 tests/e2e/global.setup.ts 實作登入態
|
||
|
||
// global.setup.ts
|
||
async function setup() {
|
||
const { chromium } = require('@playwright/test');
|
||
const browser = await chromium.launch();
|
||
const page = await browser.newPage();
|
||
await page.request.post('/api/v1/auth/login', { data: { username: 'demo', password: process.env.E2E_PASSWORD } });
|
||
await page.context().storageState({ path: 'e2e-auth-state.json' });
|
||
}
|
||
|
||
### 絕對禁止在 Mac 本機產生 Visual Baseline
|
||
使用: pnpm test:visual:update(Docker 環境)
|
||
禁止: pnpm exec playwright test --update-snapshots(本機)
|
||
```
|
||
|
||
> **注意**:Skills 更新將在 Wave 1 代碼合併後,由後續 Session 執行。本次記錄評估結論即可。
|
||
|
||
---
|
||
|
||
## 第四章:模組化合規驗證
|
||
|
||
### 4.1 Wave 1 新代碼的合規性
|
||
|
||
| 新代碼 | 層次 | 依賴 | 介面 | 合規狀態 |
|
||
|--------|------|------|------|---------|
|
||
| `core/circuit_breaker.py` | core 基礎設施 | stdio + structlog | 直接類(無需 Protocol)| ✅ 合規 |
|
||
| `services/global_repair_cooldown.py` | Service 層 | Redis(透過 get_redis())| 函數式 API | ✅ 合規 |
|
||
| `signal_worker.py` XCLAIM 補充 | Worker(現有)| Redis Stream | 無新依賴 | ✅ 合規 |
|
||
| `anomaly_counter.py` Degradation | Service 層 | 無新依賴 | 現有 Protocol | ✅ 合規 |
|
||
|
||
### 4.2 違規預防
|
||
|
||
| 規則 | 驗證方式 |
|
||
|------|---------|
|
||
| Router 不直接存取 Redis | Code Review:所有 Webhook router 只呼叫 Service |
|
||
| Semaphore 在 core/ | `circuit_breaker.py` 放在 `src/core/`,非 `src/services/` |
|
||
| Singleton 透過工廠函數 | `get_openclaw_guard()`、`get_global_repair_cooldown()` |
|
||
|
||
---
|
||
|
||
## 第五章:整合工作衝突分析
|
||
|
||
### 5.1 必須串行的依賴關係
|
||
|
||
```
|
||
XCLAIM 代碼合併 → 才能部署 Worker HPA
|
||
i18n 清零完成 → 才能啟用 ESLint i18n Plugin(error 模式)
|
||
release/v1.x 建立 → 才能宣佈 Frontend Feature Freeze
|
||
global.setup.ts 實作 → 才能有效執行 E2E Visual 測試
|
||
Redis AOF 確認 → 才能實作 SSE Event Sourcing(依賴 Redis 持久化)
|
||
```
|
||
|
||
### 5.2 可以並行的工作
|
||
|
||
```
|
||
Wave 1 後端代碼修改(5 項)可以並行開發,捆綁一個 PR
|
||
Sentry Token 配置 與 SignOz 告警規則部署 可以並行
|
||
Storybook 建置 與 Omni-Terminal SSE Event Sourcing 可以並行(不同分支)
|
||
```
|
||
|
||
### 5.3 確認無衝突的部分
|
||
|
||
| 項目 | 衝突評估 | 結論 |
|
||
|------|---------|------|
|
||
| terminationGracePeriodSeconds | 需與 XCLAIM 同一 PR(相互依賴)| ✅ Wave 1 捆綁 |
|
||
| Global Cooldown + Global Debounce | 同為 Wave 1,無衝突 | ✅ 同一 PR |
|
||
| ADR-038 + ADR-039 同時生效 | 需確保 auto_repair_service 引用兩者 | ✅ 已在 ADR 中指定 |
|
||
|
||
---
|
||
|
||
## 第六章:詳細實施步驟
|
||
|
||
### Wave 0: 即時止血(統帥手動確認,當天)
|
||
|
||
```bash
|
||
# 0.1 確認 Redis AOF 狀態(5 分鐘)
|
||
ssh root@192.168.0.188 \
|
||
'docker exec awoooi-redis redis-cli CONFIG GET appendonly; \
|
||
docker exec awoooi-redis redis-cli CONFIG GET maxmemory-policy'
|
||
# 預期:appendonly=yes, policy=volatile-ttl 或 noeviction
|
||
# 若非 yes 則立即啟用:docker exec awoooi-redis redis-cli CONFIG SET appendonly yes
|
||
|
||
# 0.2 確認 Alertmanager 備援 Telegram(10 分鐘)
|
||
ssh root@192.168.0.188 'docker exec alertmanager cat /etc/alertmanager/alertmanager.yml' | grep -A 5 receiver
|
||
|
||
# 0.3 建立 release/v1.x 穩定分支(5 分鐘)
|
||
git checkout main && git pull
|
||
git checkout -b release/v1.x && git push origin release/v1.x
|
||
# 在 GitHub 設定 Protected Branch
|
||
|
||
# 0.4 確認 SENTRY_AUTH_TOKEN(3 分鐘)
|
||
kubectl get secret awoooi-secrets -n awoooi-prod \
|
||
-o jsonpath='{.data.SENTRY_AUTH_TOKEN}' | base64 -d | wc -c
|
||
# > 0 = Phase D 已完成;= 0 = 需執行 RunBook Phase D
|
||
```
|
||
|
||
### Wave 1: 底層安全網(代碼 PR,7.5h,原子性)
|
||
|
||
> **所有以下修改必須在同一個 PR 中,不可拆分!**
|
||
|
||
```
|
||
PR 標題: feat(safety): Wave 1 底層安全網(ADR-038 + ADR-039)
|
||
|
||
檔案清單(9 個):
|
||
新建:
|
||
apps/api/src/core/circuit_breaker.py (ADR-038)
|
||
apps/api/src/services/global_repair_cooldown.py (ADR-039)
|
||
|
||
修改:
|
||
apps/api/src/services/anomaly_counter.py
|
||
→ record_anomaly() 加 try/except + graceful degrade
|
||
→ 提取 _record_anomaly_impl()
|
||
|
||
apps/api/src/workers/signal_worker.py
|
||
→ start() 加 _reclaim_task = asyncio.create_task(_reclaim_loop())
|
||
→ 新增 _claim_orphaned_tasks()(XCLAIM 實作)
|
||
→ 新增 _reclaim_loop()(Active Sweeper,每 5 分鐘)
|
||
→ stop() timeout 從 5s 改為 75s,同步取消 _reclaim_task
|
||
|
||
apps/api/src/services/auto_repair_service.py
|
||
→ evaluate_auto_repair() 開頭加 check_global_repair_cooldown()
|
||
→ execute_auto_repair() 成功後加 record_global_repair_action()
|
||
→ 常數區加 STATEFUL_SERVICE_BLACKLIST
|
||
|
||
apps/api/src/api/v1/sentry_webhook.py
|
||
→ call_openclaw_analyzer() 加雙層保護(Circuit Breaker + Semaphore)
|
||
|
||
apps/api/src/api/v1/signoz_webhook.py
|
||
→ 同上
|
||
|
||
apps/api/src/services/incident_service.py
|
||
→ process_signal() 前加 _check_global_incident_storm()
|
||
|
||
k8s/awoooi-prod/08-deployment-worker.yaml
|
||
→ 加入 terminationGracePeriodSeconds: 90
|
||
→ 加入 preStop: sleep 5
|
||
```
|
||
|
||
**Wave 1 PR 審核要點**:
|
||
- `circuit_breaker.py` 在 `src/core/`(非 services)
|
||
- `global_repair_cooldown.py` 在 `src/services/`(非 core)
|
||
- 所有新代碼有 Google Style Docstring
|
||
- 所有 Singleton 透過工廠函數暴露
|
||
|
||
**Wave 1 驗收指令**:
|
||
```bash
|
||
# 部署後驗證 terminationGracePeriodSeconds
|
||
kubectl get deployment awoooi-worker -n awoooi-prod \
|
||
-o jsonpath='{.spec.template.spec.terminationGracePeriodSeconds}'
|
||
# 預期:90
|
||
|
||
# 驗證 Circuit Breaker + Semaphore(Alpha 測試)
|
||
curl -X POST http://192.168.0.125:32334/api/v1/webhooks/alertmanager \
|
||
-d '{"alerts": [{"labels": {"alertname": "TestAlert"}}]}'
|
||
# 觀察 API log:openclaw_semaphore_acquired / openclaw_circuit_open_skip
|
||
```
|
||
|
||
### Wave 2: Worker 擴縮容部署(30 分鐘,Wave 1 完成後)
|
||
|
||
```bash
|
||
# 部署 Worker HPA
|
||
kubectl apply -f k8s/awoooi-prod/12-hpa.yaml
|
||
|
||
# 驗證 HPA 建立
|
||
kubectl get hpa awoooi-worker-hpa -n awoooi-prod
|
||
# 預期:TARGETS 顯示實際 CPU%,MINPODS=1, MAXPODS=3
|
||
```
|
||
|
||
### Wave 3: 前端主幹手術(4 天窗口,Week 1)
|
||
|
||
```bash
|
||
# Day 1 準備:宣佈 Feature Freeze
|
||
# Day 1-3:i18n 閃電清零(依 TECHNICAL_DEBT_PHASE2.md 清單)
|
||
cd apps/web
|
||
git checkout -b fix/i18n-zero-violation
|
||
|
||
# 執行清零(依序修復 9 個違規組)
|
||
# 完成後驗證:
|
||
pnpm exec tsc --noEmit
|
||
|
||
# 安裝 ESLint Plugin(先 Warn 模式)
|
||
pnpm add -D eslint-plugin-i18next
|
||
# 修改 .eslintrc.js(markupOnly: true,先 warn)
|
||
|
||
# Day 4:PR 合併 → 解除 Freeze
|
||
git push origin fix/i18n-zero-violation
|
||
# PR 審核後合併到 main
|
||
# ESLint 切換為 error 模式
|
||
```
|
||
|
||
### Wave 4: CI 基礎設施(1 天,Wave 3 後)
|
||
|
||
```bash
|
||
# 修改 playwright.config.ts
|
||
# 加入 ignoreHTTPSErrors: true + deviceScaleFactor: 1 + threshold: 0.05
|
||
|
||
# 建立 tests/e2e/global.setup.ts(E2E Auth Bypass)
|
||
# 建立初始 Docker Visual Baseline
|
||
cd apps/web
|
||
pnpm test:visual:update # Docker 環境
|
||
|
||
# 部署 Weekly E2E Workflow
|
||
git add .github/workflows/e2e-weekly.yaml
|
||
git commit -m "feat(ci): weekly E2E + visual regression + Docker baseline"
|
||
```
|
||
|
||
### Wave 5: 告警後端完整化(2 小時,Wave 1 後即可)
|
||
|
||
```bash
|
||
# 部署 SENTRY_AUTH_TOKEN(若 Wave 0.4 確認缺失)
|
||
kubectl patch secret awoooi-secrets -n awoooi-prod \
|
||
--type=merge -p='{"stringData": {"SENTRY_AUTH_TOKEN": "YOUR_TOKEN"}}'
|
||
|
||
# 部署 SignOz 告警規則到 .188
|
||
ssh root@192.168.0.188 'cat > /tmp/signoz-rules.yaml' < ops/signoz/alerting/rules.yaml
|
||
# 透過 SignOz API 套用
|
||
|
||
# 驗證告警鏈路
|
||
python ops/scripts/alert_chain_smoke_test.py
|
||
```
|
||
|
||
> **Wave 6-12**: 中長期工作,依 INTEGRATION_ARCHITECTURE_MASTER.md 執行。
|
||
|
||
---
|
||
|
||
## 第七章:最終工作排程(供統帥審核)
|
||
|
||
```
|
||
📅 2026-03-29(今天)- Wave 0
|
||
□ 0.1 Redis AOF + eviction policy 確認(hand-on,5 min)
|
||
□ 0.2 Alertmanager 備援路徑確認(hand-on,10 min)
|
||
□ 0.3 release/v1.x 分支建立 + GitHub 設為 Protected(hand-on,5 min)
|
||
□ 0.4 SENTRY_AUTH_TOKEN 存在確認(hand-on,3 min)
|
||
|
||
📅 2026-03-30 (已完成) - Wave 1 ✅
|
||
□ core/circuit_breaker.py 開發(2h)
|
||
□ services/global_repair_cooldown.py 開發(1h)
|
||
□ anomaly_counter.py Graceful Degrade(1h)
|
||
□ signal_worker.py XCLAIM + Active Sweeper(2h)
|
||
□ auto_repair_service.py Guardrail 整合(1h)
|
||
□ sentry_webhook.py + signoz_webhook.py 雙層保護(0.5h)
|
||
□ incident_service.py Global Debounce(1.5h)
|
||
□ 08-deployment-worker.yaml terminationGracePeriodSeconds(0.5h)
|
||
□ Wave 1 PR 提交 → 審核 → 合併 → CD 部署 → 驗收
|
||
|
||
📅 2026-04-01(Wave 1 完成後)- Wave 2
|
||
□ Worker HPA YAML 部署(30 min)
|
||
|
||
📅 2026-04-02~04-05(4 天)- Wave 3(Feature Freeze)
|
||
□ Frontend Feature Freeze 宣佈
|
||
□ i18n 閃電清零(40+ 違規,4h 工時)
|
||
□ ESLint i18n Plugin 安裝(Warn 模式)
|
||
□ PR 合併 → Feature Unfreeze
|
||
□ ESLint 切換為 Error 模式
|
||
|
||
📅 2026-04-06(1 天)- Wave 4 / Wave 5
|
||
□ playwright.config.ts 修改(ignoreHTTPSErrors + threshold)
|
||
□ global.setup.ts E2E Auth Bypass 建立
|
||
□ Docker Visual Baseline 初始建立
|
||
□ E2E Weekly Workflow 部署
|
||
□ SignOz 告警規則部署到 .188
|
||
|
||
📅 2026-04 Week 3 - Wave 5 + 6(可視 Wave 1-4 完成情況調整)
|
||
□ Prometheus Federation(.110 → .188)
|
||
□ Redis AOF + Sentinel 評估
|
||
□ AI Autonomy Index Metrics 建立
|
||
|
||
📅 2026-04 Week 4+ - Wave 7-9(Month 2)
|
||
□ Storybook 10 核心組件
|
||
□ Omni-Terminal SSE Event Sourcing
|
||
□ 監控 GenUI 卡片(7 張)
|
||
□ Nexus AI 自治率 UI
|
||
|
||
📅 Q2 - Wave 10-12(長期)
|
||
□ CloudNativePG HA 評估
|
||
□ Kali SecurityAgent(MCP Tool 化)
|
||
□ Phase 4 視覺靈魂注入
|
||
□ CI 硬阻擋正式啟用(Warn → Block)
|
||
```
|
||
|
||
---
|
||
|
||
## 第八章:統帥審核要點
|
||
|
||
請特別審核以下決策點:
|
||
|
||
| # | 決策內容 | 選項 | 推薦 |
|
||
|---|---------|------|------|
|
||
| D1 | Wave 1 PR 是否原子性(9 個文件一次)| A. 原子 / B. 分批 | A(必須原子,互相依賴)|
|
||
| D2 | Feature Freeze 時長 | A. 3天 / B. 5天 | B(40+ 違規需要謹慎)|
|
||
| D3 | ESLint 啟用時機 | A. i18n清零後立即 / B. 一週緩衝期 | A(清零後立即,防新債)|
|
||
| D4 | Semaphore max_concurrent | A. 2 / B. 3 / C. 5 | B(3 = 60% .188 CPU)|
|
||
| D5 | Global Cooldown Threshold | A. 3次/15分鐘 / B. 5次/15分鐘 | B(3 次太嚴,5 次合理)|
|
||
| D6 | Redis HA 策略 | A. Sentinel / B. AOF+手動 / C. 暫緩 | C(暫緩,Month 2 評估)|
|
||
|
||
---
|
||
|
||
*此排程基於 2026-03-29 的完整代碼審計與 16 輪沙盤推演,已閉合所有已知漏洞。* 🦞
|