## Phase 1-3: Control Plane + Contract System - awooop_phase1_control_plane_2026-05-04.sql: 12 張核心表 + RLS - awooop_phase1_batch1_rls_2026-05-04.sql: 全部 FORCE RLS + GRANT - packages/awooop-contracts/: 六合約 JSON Schema + golden fixtures - src/models/awooop_contracts.py: Pydantic v2 contract models(extra=forbid) - src/repositories/contract_repository.py: contract lifecycle(draft→published→active) - src/services/contract_service.py: HMAC publish sig + Redis multi-sig activate - src/services/schema_validator.py: LLM output validator(retry×3, E-SCHEMA-001) ## Phase 2: Tenant Isolation - awooop_phase2_budget_ledger_2026-05-04.sql: budget_ledger + RLS - src/services/budget_service.py: Token Budget Hard Kill 三層防線 - src/core/context.py: PROJECT_ID ContextVar(31 background loop 自動繼承) - src/db/base.py + models.py: project_id 欄位 + RLS set_config 注入 - src/hermes/nl_gateway.py: project_id Redis key 前綴(Phase A 雙寫) - src/services/anomaly_counter.py: per-project 改造(Phase A fallback) ## Phase 4: Platform Shell in Shadow Mode - awooop_phase4_run_state_2026-05-04.sql: run_state + step_journal + idempotency - src/services/run_state_machine.py: 8-state FSM + SKIP LOCKED + stale reaper - src/services/platform_runtime.py: UUID v7 + W3C trace_id + shadow_execute - src/services/audit_sink.py: PII/secret redaction 9 patterns - src/api/v1/platform/runs.py: POST/GET /v1/platform/runs(Router→Service 架構) - src/workers/platform_worker.py: SKIP LOCKED worker + heartbeat + reaper loop - src/main.py: platform router + lifespan worker start/stop ## Phase 5: MCP Gateway 五閘門 - awooop_phase5_mcp_gateway_2026-05-04.sql: 4 表 + RLS - src/plugins/mcp/gateway.py: McpGateway(Gate 1~5, E-MCP-GATE-001~009) - src/plugins/mcp/redaction_middleware.py: 雙層 redaction + 16K 截斷 - src/plugins/mcp/registry.py: __provider name mangling(ADR-116) - src/plugins/mcp/credential_resolver.py: k8s secret ref 解析 - tests/test_mcp_credential_isolation.py: 10 個迴歸測試(secret leak 防再現) ## Phase 6-8: EwoooC + Channel Hub + Approval Token - awooop_phase6_ewoooc_onboarding_2026-05-04.sql: ewoooc tenant + 4 read-only MCP tools - awooop_phase7_channel_hub_2026-05-04.sql: conversation_event + outbound_message - src/services/provider_proxy.py: ProviderProxy + PlatformEnvelope(ADR-115) - src/services/channel_hub.py: Telegram inbound mirror + Progressive Feedback(30s) - src/services/awooop_approval_token.py: HS256 + jti NX replay 防護 + suggest mode Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.2 KiB
7.2 KiB
INV-1: Redis Key Inventory
版本:v1.0 初稿
日期:2026-05-03(台北)
範圍:apps/api/src/ 全 codebase grep
用途:Phase 2 三階段雙寫遷移的完整 Redis key 清單
使用方式
本 INV 列出所有 Redis key pattern、TTL、用途、寫入點、讀取點、是否硬碼跨兩處。 Phase 2 遷移按批次執行:P0(Critical)→ P1(高風險)→ P2(業務資料)→ P3(低影響)
1. P0 — Critical(必須優先遷移)
| Key Pattern | 用途 | TTL | 寫入點 | 讀取點 | 問題 | 新 Pattern(Phase 2 後) |
|---|---|---|---|---|---|---|
ollama:current_primary |
Ollama primary URL 選擇 | 無 | ollama_auto_recovery.py (兩處!) |
ollama_failover_manager.py |
🔴 P0-11:第二定義 at ollama_auto_recovery.py:230;三層 GCP 拓撲無法塞入單一 URL | platform:ollama:topology(JSON:primary/secondary/fallback) |
ollama:gemini_daily_count:{date} |
Gemini 每日使用計數 | 24h | ollama_auto_recovery.py |
same | 🔴 無 project 前綴,多 tenant 共用 | platform:ollama:gemini_daily_count:{date} |
telegram:polling:leader |
Telegram polling pod 鎖 | ~30s | telegram_gateway.py:55 |
same | 🔴 platform_resource,應明確標記 | platform:telegram:polling:leader |
telegram_silence:{target} |
告警靜默控制 | 設定值 | telegram_gateway.py:4079(用 SILENCE_KEY_PREFIX) |
decision_manager.py:240(🔴 硬碼 telegram_silence:{target},未 import 常數) |
P1-24:兩處定義不一致 | {project_id}:telegram:silence:{target} |
ai_rate:total_cost:{provider} |
費用上限控制 | 無 | ai_rate_limiter.py |
ai_router.py |
🔴 無 project 前綴,AWOOOI 費用計數會與 EwoooC 混算 | {project_id}:ai_rate:total_cost:{provider} |
2. P1 — 高風險(Phase 2 第二批)
| Key Pattern | 用途 | TTL | 寫入點 | 讀取點 | 問題 | 新 Pattern |
|---|---|---|---|---|---|---|
approval:{run_id}:* |
approval 審核狀態 | 15min | multi_sig_redis.py |
same | 🔴 P1-15:無 trace_id;approval_token 未簽章 | {project_id}:approval:{run_id}:*(Phase 8 後加 jti) |
incident:{incident_id} |
incident working memory | 24h | incident_service.py |
incident_service.py:603(SCAN incident:*) |
🔴 P1-18:SCAN 無 prefix 篩選 | {project_id}:incident:{incident_id} |
consensus:{*} |
consensus engine 狀態 | varies | consensus_engine.py(CONSENSUS_PREFIX="consensus:") |
same | 🔴 P0-12:無 project 前綴,multi-tenant 共用 | {project_id}:consensus:{*} |
playbook:{playbook_id} |
playbook cache | 1h | playbook_repository.py |
same | 🟠 無 project,但目前 AWOOOI 只有一個 tenant | {project_id}:playbook:{playbook_id} |
playbook:embedding:index |
embedding index | 無 | playbook_repository.py |
same | 🟠 無 project | {project_id}:playbook:embedding:index |
playbook:index:alert:{alert_name} |
alert → playbook 映射 | 1h | playbook_repository.py |
same | 🟠 無 project | {project_id}:playbook:index:alert:{alert_name} |
playbook:embedding:{playbook_id} |
embedding vector | 無 | playbook_repository.py |
same | 🟠 無 project | {project_id}:playbook:embedding:{playbook_id} |
km:backfill:dlq |
KM backfill dead letter queue | 無 | km_service.py |
same | 🟠 無 project | {project_id}:km:backfill:dlq |
3. P2 — 業務資料(Phase 2 第三批)
| Key Pattern | 用途 | TTL | 寫入點 | 讀取點 | 問題 | 新 Pattern |
|---|---|---|---|---|---|---|
anomaly:disposition:{alert_id} |
告警處置決定 | 7d | anomaly_counter.py:790 |
same | 🔴 P1-17:AnomalyCounter 全域單例,6 個 prefix 無 tenant | {project_id}:anomaly:disposition:{alert_id} |
anomaly:metadata:{alert_id} |
告警 metadata | 7d | anomaly_counter.py |
same | 同上 | {project_id}:anomaly:metadata:{alert_id} |
anomaly:permanent_fix:{alert_id} |
永久修復紀錄 | 30d | anomaly_counter.py |
same | 同上 | {project_id}:anomaly:permanent_fix:{alert_id} |
anomaly:repair_count:{alert_id} |
修復計數 | 7d | anomaly_counter.py |
same | 同上 | {project_id}:anomaly:repair_count:{alert_id} |
anomaly:repair_history:{alert_id} |
修復歷史 | 30d | anomaly_counter.py |
same | 同上 | {project_id}:anomaly:repair_history:{alert_id} |
anomaly:timeline:{alert_id} |
告警時間線 | 7d | anomaly_counter.py |
same | 同上 | {project_id}:anomaly:timeline:{alert_id} |
hermes:session:{chat_id}:{user_id} |
Hermes 對話狀態 | 30min | hermes/nl_gateway.py:146 |
same | 🔴 P1-16:無 project 前綴 | {project_id}:hermes:session:{chat_id}:{user_id} |
hermes:rl:{chat_id} |
Hermes rate limit | 1min | hermes/nl_gateway.py:163 |
same | 🔴 P1-16 | {project_id}:hermes:rl:{chat_id} |
hermes:approvers |
Hermes 審核者清單 | 無 | hermes/nl_gateway.py:7 |
same | 🔴 P1-16 | {project_id}:hermes:approvers |
session:{session_id} |
agent session | varies | agent_sessions service |
same | 🟠 無 project | {project_id}:session:{session_id} |
tg_sent:{fingerprint} |
Telegram 去重 dedup | 10min | telegram_gateway.py |
same | 🟢 ADR-109 已定(dedup 相容性);注意 EwoooC Telegram 需要不同 fingerprint scope | {project_id}:tg_sent:{fingerprint} |
telegram:{user_id}:{*} |
Telegram session / callback | varies | telegram_gateway.py |
same | 🟠 無 project | {project_id}:telegram:{user_id}:{*} |
4. P3 — 低影響(Phase 2 最後)
| Key Pattern | 用途 | TTL | 問題 | 新 Pattern |
|---|---|---|---|---|
playbook:*(SCAN) |
playbook 全量掃描 | — | 🟠 SCAN 無 prefix 篩選 | 禁止裸 SCAN,改 SCAN {project_id}:playbook:* |
approval:123:lock(測試用) |
測試 key | — | 🔵 hardcode 測試字串,清理 | 移除 |
5. Platform Resource(不按 project 隔離,明確標記)
| Key Pattern | 理由 | 備註 |
|---|---|---|
platform:telegram:polling:leader |
全域 polling leader 鎖,不屬於任何 tenant | ADR-111 platform_resource |
platform:ollama:topology |
GCP-A/GCP-B/Local 三層路由狀態,所有 tenant 共用 | ADR-111 + ADR-110 |
platform:ollama:gemini_daily_count:{date} |
全 platform Gemini 緊急路由計數 | ADR-111 |
6. 遷移執行順序(三階段)
Phase A(雙寫,30 天觀察):
新 key 寫入 + 舊 key 繼續寫入
讀取仍以舊 key 為主
監控:舊 key 讀取次數 / 新 key 命中次數
Phase B(雙讀,14 天):
新 key 為主,舊 key 為 fallback
讀不到新 key → 讀舊 key,並回填新 key
監控:舊 key fallback 率必須 < 1%
Phase C(移除舊 key 寫入):
停止寫入舊 key
舊 key 自然過期
監控:確認舊 key 0 讀取後才進行
7. 驗收標準
- 所有 P0 key 完成 Phase A 雙寫
decision_manager.py:240改為 importtelegram_gateway.SILENCE_KEY_PREFIXollama:current_primary改為platform:ollama:topology(JSON 格式)- 無任何裸
SCAN *或SCAN prefix:*(改為SCAN {project_id}:prefix:*)
最後更新:2026-05-03(台北)