## Phase 0(文件層,全部 Accepted) - ADR-106/107:AwoooP 平台架構 + 儲存策略 - ADR-111~118:Bootstrap → RLS 七項核心 ADR - ADR-119~124:SAGA → Singleton Decomposition 六項 ADR - ADR-UI-01~04:Operator Console 四個 UI ADR ## Phase 1(DB schema + migration) - awooop_phase1_control_plane_2026-05-04.sql:7 張新表 + trigger + RLS - Step 1:三角色(platform_admin/migration BYPASSRLS,awooop_app 受 RLS) - Step 13:GRANT awooop_app 最小權限(7 條) - Step 14:RLS fail-closed,移除 __platform__ 後門 - awooop_phase1_batch1_rls_2026-05-04.sql:高流量四表三步式 ADD COLUMN - awooop_phase1_batch1_backfill.py:SKIP LOCKED 分批回填腳本 - awooop_models.py:7 個 SQLAlchemy 2.x models ## Critic 修正(4 Critical + 3 Major) - C-1:ADD CONSTRAINT IF NOT EXISTS → DO 塊 + pg_constraint 查詢 - C-2:__mapper_args__ 字串 list → primary_key=True on mapped_column - C-3:__platform__ RLS 後門 → 全移除,改用 BYPASSRLS role - C-4:awooop_app role 從未建立 → Step 1 + 7 條 GRANT - M-1:active_pointer_guard SECURITY DEFINER(FORCE RLS 跨租戶保護) - M-2:pg_partman create_parent 加冪等防護 - M-3:immutability trigger 新增身份欄位保護(project_id/family/contract_id) ## Task 1.2 修補 - agent_loader.py:硬編碼 Mac 路徑 → AGENTS_DIR 環境變數 - Dockerfile:補 COPY .claude/agents/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
220 lines
6.7 KiB
Markdown
220 lines
6.7 KiB
Markdown
# ADR-107: AwoooP Control Plane Storage Strategy
|
|
|
|
**Status**: Accepted
|
|
**Date**: 2026-05-01
|
|
**Scope**: AwoooP control plane storage, contract materialization, cache/watch, K8s projection
|
|
|
|
## Context
|
|
|
|
ADR-106 defines AwoooP as the multi-tenant Agent Platform with six contracts:
|
|
|
|
- Project / Tenant
|
|
- Agent
|
|
- MCP Gateway
|
|
- Policy / Routing
|
|
- Runtime / Run State
|
|
- Communication / Channel Event
|
|
|
|
Those contracts need a physical source of truth. The key question is whether
|
|
the AwoooP control plane should be implemented as Kubernetes CRDs first, or as
|
|
PostgreSQL tables first.
|
|
|
|
AwoooP must serve more than Kubernetes:
|
|
|
|
- AWOOOI on K3s is the first runtime host and tenant.
|
|
- EwoooC / MOMO PRO currently runs Docker workloads.
|
|
- Tsenyang, Bitan, LINE, Slack, Email, and API entrypoints may not all be
|
|
Kubernetes-native.
|
|
- Runtime state, audit, budget, approval, and conversation events are
|
|
high-volume product control-plane data, not only deployment desired state.
|
|
|
|
ADR-105 already established the local pattern for MCP RAG: keep PostgreSQL +
|
|
pgvector + Redis hot cache as the source of truth unless scale, latency, or
|
|
tenant isolation requires a later split.
|
|
|
|
## Decision
|
|
|
|
### D1 - Use PostgreSQL as the Control Plane Source of Truth
|
|
|
|
AwoooP v1 uses PostgreSQL as the authoritative store for the six contract
|
|
families and runtime governance state.
|
|
|
|
PostgreSQL owns:
|
|
|
|
- contract drafts and immutable published revisions
|
|
- active revision pointers
|
|
- tenant/project records
|
|
- agent registry and version metadata
|
|
- policy and routing revisions
|
|
- MCP tool registry, grants, and audit summaries
|
|
- budget ledgers and hard-stop state
|
|
- ACL subjects and project access
|
|
- run state and approval state
|
|
- channel event and outbound delivery state
|
|
- audit and trace correlation records
|
|
|
|
Kubernetes etcd is not the source of truth for these records in v1.
|
|
|
|
### D2 - Materialize Contracts as Versioned Revisions
|
|
|
|
Each published contract must produce an immutable revision.
|
|
|
|
Minimum revision fields:
|
|
|
|
- `contract_family`
|
|
- `contract_id`
|
|
- `revision_id`
|
|
- `version`
|
|
- `lifecycle_status`
|
|
- `body_json`
|
|
- `body_schema_version`
|
|
- `body_hash`
|
|
- `created_by`
|
|
- `created_at`
|
|
- `published_at`
|
|
- `supersedes_revision_id`
|
|
|
|
Runtime reads only published or active revisions. Mutable drafts are never used
|
|
for runtime decisions.
|
|
|
|
### D3 - Keep Artifact Bodies Out of Control Tables
|
|
|
|
Large or independently governed artifacts are stored by reference plus hash:
|
|
|
|
- system prompts
|
|
- JSON Schemas
|
|
- eval suites
|
|
- policy fixtures
|
|
- replay fixtures
|
|
|
|
The database stores:
|
|
|
|
- artifact ref
|
|
- SHA-256 hash
|
|
- artifact type
|
|
- expected schema version
|
|
|
|
This makes historical runs replayable without stuffing large prompt bodies into
|
|
every contract row.
|
|
|
|
### D4 - Use Redis for Cache and Watch, Not Authority
|
|
|
|
Redis is allowed for:
|
|
|
|
- effective policy cache
|
|
- agent contract cache
|
|
- project boundary cache
|
|
- rate limit counters
|
|
- short-lived session hot state
|
|
- contract revision invalidation
|
|
- worker coordination
|
|
|
|
Redis is not allowed to be the only source of truth for:
|
|
|
|
- contract revisions
|
|
- active revision pointers
|
|
- budget hard-stop decisions
|
|
- run terminal state
|
|
- approval decisions
|
|
- audit history
|
|
|
|
Any cached value used by runtime must carry the source `revision_id` and
|
|
`body_hash`.
|
|
|
|
### D5 - Use Kubernetes CRDs Only as Runtime Projection
|
|
|
|
CRDs are not the primary control-plane database in v1.
|
|
|
|
Allowed future CRD projections:
|
|
|
|
- `AwoooPRuntime`
|
|
- `AwoooPWorker`
|
|
- `MCPServerBinding`
|
|
- `ChannelIngress`
|
|
- `TenantRuntimeBinding`
|
|
|
|
These CRDs describe Kubernetes runtime wiring, deployment, service exposure, and
|
|
MCP server binding. They do not own product contracts, budgets, run state,
|
|
conversation events, or audit ledgers.
|
|
|
|
If an operator is later built, it should project from PostgreSQL into Kubernetes
|
|
objects, not require Kubernetes CRDs to become the source of truth for all
|
|
AwoooP state.
|
|
|
|
### D6 - Define Read Paths by Stability
|
|
|
|
| Data | Source of truth | Runtime read path |
|
|
|---|---|---|
|
|
| Contract draft | PostgreSQL | Admin/API only |
|
|
| Published contract revision | PostgreSQL | DB read + Redis cache |
|
|
| Active revision pointer | PostgreSQL | DB read + Redis invalidation |
|
|
| Prompt/schema/eval artifact | Git or object storage | Ref + hash from DB |
|
|
| Effective policy | PostgreSQL-derived | Redis cache with revision IDs |
|
|
| Run state | PostgreSQL | Worker writes DB, optional Redis notification |
|
|
| Budget hard stop | PostgreSQL | DB transaction + Redis hot counter |
|
|
| Rate limit | PostgreSQL policy + Redis counter | Redis counter, DB policy |
|
|
| Audit history | PostgreSQL | DB append/query |
|
|
| K8s runtime wiring | CRD projection | Kubernetes watch |
|
|
|
|
## Consequences
|
|
|
|
### Benefits
|
|
|
|
- AwoooP remains useful for Docker, Next.js, API-only, and future non-K8s
|
|
tenants.
|
|
- Product governance data can be joined with incidents, Playbooks, KM, budget,
|
|
and audit records.
|
|
- Contract changes are transactional and replayable.
|
|
- Runtime can use Redis for speed without risking split-brain authority.
|
|
- K8s CRDs remain available for the infrastructure layer without forcing all
|
|
business control-plane data into etcd.
|
|
|
|
### Costs
|
|
|
|
- AwoooP needs explicit schema and migration discipline before runtime code.
|
|
- Runtime workers must implement revision-aware caches.
|
|
- K8s operator work, if needed later, must include a projection layer.
|
|
|
|
### Risks
|
|
|
|
- PostgreSQL schema can become a dumping ground if contract families are not
|
|
modeled explicitly.
|
|
- Redis cache can become stale if invalidation is not versioned by revision and
|
|
hash.
|
|
- Future CRDs can drift from DB state if projection reconciliation is not
|
|
audited.
|
|
|
|
### Mitigations
|
|
|
|
- Every runtime decision records `revision_id` and `body_hash`.
|
|
- Active revision changes must emit an invalidation event.
|
|
- Contract publish is append-only; do not mutate published `body_json`.
|
|
- CRD projection writes must be reconciled and auditable.
|
|
- High-volume audit/event tables should be partitioned before production scale.
|
|
|
|
## Non-Goals
|
|
|
|
- This ADR does not create database migrations.
|
|
- This ADR does not create AwoooP directories or runtime services.
|
|
- This ADR does not introduce Kubernetes CRDs.
|
|
- This ADR does not choose Temporal, Celery, Redis Streams, or another worker
|
|
engine.
|
|
- This ADR does not change paid provider behavior.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- PostgreSQL is declared as the v1 AwoooP control-plane source of truth.
|
|
- Redis is limited to cache/watch/counter responsibilities.
|
|
- Artifacts are referenced by ref + hash rather than copied into every runtime
|
|
record.
|
|
- CRD-first is explicitly rejected for v1.
|
|
- Future CRDs are limited to Kubernetes runtime projection.
|
|
- ADR-106 and the task-routing docs point to this ADR.
|
|
|
|
## References
|
|
|
|
- `docs/adr/ADR-105-mcp-agent-loop-governance.md`
|
|
- `docs/adr/ADR-106-agent-platform-architecture.md`
|
|
- `docs/LOGBOOK.md`
|
|
- `docs/12-agent-game-rules.md`
|