## 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>
117 lines
5.2 KiB
Markdown
117 lines
5.2 KiB
Markdown
# INV-5: Migration Compatibility Matrix
|
||
|
||
**版本**:v1.0 初稿
|
||
**日期**:2026-05-03(台北)
|
||
**範圍**:`apps/api/pyproject.toml` 實際版本 + AwoooP Phase 1 migration 需求
|
||
**用途**:Phase 1 schema migration 前確認版本相容性,避免 breaking change 踩雷
|
||
|
||
---
|
||
|
||
## 1. 當前依賴版本(從 pyproject.toml 實際讀取)
|
||
|
||
| 套件 | 當前約束 | 對 AwoooP Phase 1 的影響 |
|
||
|------|---------|------------------------|
|
||
| Python | >=3.11 | ✅ 足夠;`asyncio.TaskGroup`(3.11)可用 |
|
||
| FastAPI | >=0.115.0 | ✅ 0.115 已支援 lifespan context manager |
|
||
| SQLAlchemy | **>=2.0.0** ✅ 已是 2.x | ✅ `mapped_column`、`DeclarativeBase`、async session 均可用 |
|
||
| Pydantic | **>=2.5.0** ✅ 已是 v2 | ✅ `model_validator`、`field_validator` v2 語法可直接用 |
|
||
| pydantic-settings | >=2.1.0 | ✅ |
|
||
| asyncpg | >=0.29.0 | ✅ 支援 PostgreSQL 15/16 |
|
||
| redis | >=5.0.0 | ✅ redis-py 5.x 支援 cluster mode + NX |
|
||
| Alembic | **未列出**(透過 SQLAlchemy 間接)| ⚠️ 需確認版本;建議鎖定 >=1.13.0 |
|
||
| Langfuse | >=2.0.0,<3.0.0(鎖定)| ✅ 無 AwoooP 影響,保持不變 |
|
||
| opentelemetry | >=1.20.0 | ✅ GenAI semantic conventions 需要 >=1.25.0(ADR-121)|
|
||
| claude-agent-sdk | >=0.1.50 | ✅ 已使用 |
|
||
|
||
---
|
||
|
||
## 2. 重要發現
|
||
|
||
**✅ SQLAlchemy 已是 2.x**:MASTER-WORKPLAN 中「ORM 1.x vs 2.x」問題**已不存在**。
|
||
- `mapped_column`、`relationship`、async session 均可正常用
|
||
- 但仍需確認:AwoooP 新 model 使用正確的 2.x 寫法(`DeclarativeBase` 而非舊 `declarative_base()`)
|
||
|
||
**✅ Pydantic 已是 v2**:六合約 Pydantic models 可直接用 v2 語法。
|
||
|
||
**⚠️ Alembic 版本未鎖定**:
|
||
- `apps/api/migrations/` 有大量 `.sql` 手寫 migration(非 Alembic auto-generate)
|
||
- AwoooP Phase 1 要決定:繼續手寫 SQL migration,還是引入 Alembic autogenerate?
|
||
- **建議**:保持手寫 SQL(現有慣例),每個 migration 強制有 down migration
|
||
|
||
**⚠️ OTel 版本需升級(ADR-121)**:
|
||
- GenAI Semantic Conventions 需要 `opentelemetry-semantic-conventions>=0.46b0`(含 `gen_ai.*` namespace)
|
||
- 當前 `>=1.20.0` 可能不夠,需要 `>=1.25.0`
|
||
- 升級風險:低(向後相容);需要加入 `opentelemetry-semantic-conventions` 依賴
|
||
|
||
---
|
||
|
||
## 3. AwoooP Phase 1 新依賴需求
|
||
|
||
| 套件 | 版本 | 用途 | 是否需要新增 |
|
||
|------|------|------|------------|
|
||
| `pg_partman`(PostgreSQL extension)| >=4.7.0 | 高流量表 partition 自動管理 | ⚠️ 需在 DB 層安裝,非 Python 套件 |
|
||
| `opentelemetry-semantic-conventions` | >=0.46b0 | OTel GenAI attribute(ADR-121)| ✅ 需新增到 pyproject.toml |
|
||
| `PgBouncer` | >=1.21.0 | Connection pool(tool-expert 需求)| ⚠️ Infrastructure,非 Python 套件 |
|
||
|
||
---
|
||
|
||
## 4. Migration SQL 版本相容性
|
||
|
||
| Migration 問題 | 當前狀態 | 修補方式 |
|
||
|---------------|---------|---------|
|
||
| `adr105_mcp_audit_snapshots.sql` 建表 `mcp_audit_snapshots`,但 models.py 用 `mcp_audit_log` | ⚠️ 衝突 | 確認是否已 rollback;若 `mcp_audit_log` 是現行表,則 `mcp_audit_snapshots` 已廢棄 |
|
||
| 部分 migration 無 rollback SQL | ⚠️ MASTER-WORKPLAN P0-02 | Phase 1 新 migration 強制加 down migration |
|
||
| `ARRAY` 型別在部分 migration 用 `TEXT[]`,在其他用 `JSONB` | 🟠 不一致 | AwoooP 新表一律用 `JSONB`(`fix_playbooks_array_to_jsonb.sql` 已示範)|
|
||
|
||
---
|
||
|
||
## 5. SQLAlchemy 2.x 正確寫法確認清單(Phase 1 新 model 必須遵守)
|
||
|
||
```python
|
||
# ✅ 正確(SQLAlchemy 2.x)
|
||
from sqlalchemy.orm import DeclarativeBase, mapped_column, Mapped
|
||
from sqlalchemy import String, DateTime, func
|
||
from typing import Optional
|
||
|
||
class Base(DeclarativeBase):
|
||
pass
|
||
|
||
class AwooopProject(Base):
|
||
__tablename__ = "awooop_projects"
|
||
project_id: Mapped[str] = mapped_column(String(64), primary_key=True)
|
||
display_name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||
created_at: Mapped[datetime] = mapped_column(
|
||
DateTime(timezone=True), server_default=func.now()
|
||
)
|
||
migration_mode: Mapped[str] = mapped_column(
|
||
String(32), nullable=False, default="legacy_awoooi_default"
|
||
)
|
||
|
||
# ❌ 舊寫法(SQLAlchemy 1.x,不要用)
|
||
# from sqlalchemy.ext.declarative import declarative_base
|
||
# Base = declarative_base()
|
||
# project_id = Column(String(64), primary_key=True)
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 版本兼容風險清單
|
||
|
||
| 風險 | 嚴重度 | 緩解方式 |
|
||
|------|--------|---------|
|
||
| pg_partman 未安裝,partition 手動建立出錯 | 中 | Phase 1 先不建 partition,只規劃;Phase 4 前安裝 pg_partman |
|
||
| OTel semantic conventions 版本不足 | 低 | Phase 4 前升級(非 Phase 1 阻擋項)|
|
||
| PgBouncer 未安裝,AwoooP worker 壓力測試可能爆連接 | 中 | Phase 4(platform shell)前安裝 |
|
||
| Alembic 未鎖定,CI 環境版本飄移 | 低 | 鎖定 `alembic>=1.13.0` 加入 pyproject.toml |
|
||
|
||
---
|
||
|
||
## 7. 驗收標準
|
||
|
||
- [ ] Phase 1 所有新 migration 使用 SQLAlchemy 2.x `mapped_column` 語法
|
||
- [ ] 所有新 migration 有 down migration SQL
|
||
- [ ] `mcp_audit_snapshots` vs `mcp_audit_log` 衝突已解決(確認哪個是現行表)
|
||
- [ ] `pg_partman` 安裝計畫已寫入 runbook
|
||
|
||
*最後更新:2026-05-03(台北)*
|