Files
Agent-System-Documents/docs/guides/team-storage.md
weichen ca9b128f18 Document the storage-migrate tool and the switch/drill runbook (U4)
Why: U4 ships the managed migration entry; the runbook is the operator-facing contract for inventory/backup/migrate, migration identity and resume rules, verification semantics, and the authorized-window switch sequence.

Evidence: backend branch feature/collab-storage-u4-migrator - integration tests green against real PostgreSQL (idempotent rerun, resume, foreign-data refusal, wrong-snapshot refusal, unknown-owner block).

Impact: docs only.

Refs: proposals/2026-10-11-collaboration-storage-and-distribution.md U4 and section 6.
2026-10-11 08:29:38 +00:00

199 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 团队存储运行手册(协作存储 U1)
适用范围:[协作存储与分布式方案](../proposals/2026-10-11-collaboration-storage-and-distribution.md) U1/U2
(已批准,2026-10-11)落地后的 **team 部署档** 运维与验证。个人 `local` 档(SQLite)
用法不变,见 [usage](usage.md)。本文是 U1 的固定部署清单、配置合同、迁移映射、
容量合同、隔离测试方案与 KTD14 副本保护合同的单一事实源;实施状态以各任务卡为准。
## 1. 目标实例与固定部署清单
| 项 | 值 | 说明 |
|---|---|---|
| 部署形态 | svc.sh 管理的 `runtime/<name>` 实例 | 非容器;单机多实例按名隔离 |
| 当前团队候选 | `runtime/dev`(8788,SQLite)→ 目标切 team 档 PG | 切换窗口与回退按方案 §6,须另行授权 |
| 数据库(本机验证) | PostgreSQL 18.6 + pgvector 0.8.7(brew) | 本机验证用;正式实例待指定 |
| 数据库(CI 门禁) | Ubuntu 24.04 apt:postgresql 16 + postgresql-16-pgvector | 版本以 CI job 输出为准 |
| 缓存/限流 | Redis 8.10.2(本机);CI apt redis-server | 只存可重建状态(KTD10) |
| 应用制品 | `agent-system` 单二进制(make build) | 拷贝即运行;team 档需 `--tier team` |
未知项(正式实例主机、pgvector 正式启用版本、对象存储选型)在正式切换授权前
必须补齐;本清单不把本机验证环境当作正式部署事实。
## 2. team 档配置合同(U2 已实施)
启动语义(KTD1 fail-closed):
- `tier=team`:必须配置 `dsn` 且认证开启(`auth=on`;`auth=auto` 随 DSN 自动开);
任一缺失**拒绝启动**。PG 打开失败**拒绝就绪**,绝不回落 SQLite。未配置执行隔离
(`disableExecTools` 或 `execBackend`)时启动警告(多用户开放前必须补齐)。
- `tier=local`:SQLite;配置 `dsn` 是配置错误,拒绝启动。
- `tier` 缺省(auto):现状语义——`dsn` 非空走 PG,否则 SQLite。
配置键(四源合并:默认 → 文件 → 环境 → 显式 CLI,与 usage §启动一致):
| 键 | env | CLI | 语义(team 档) |
|---|---|---|---|
| `tier` | `AGENT_SYSTEM_TIER` | `--tier` | `local` / `team` / 空=auto |
| `dsn` | `AGENT_SYSTEM_DSN` | `--dsn` | PG 连接串;team 必填 |
| `auth` | `AGENT_SYSTEM_AUTH` | `--auth` | team 档要求最终为 on |
| `instance` | `AGENT_SYSTEM_INSTANCE` | `--instance` | 空=主机名:监听地址(多实例必须互异) |
| `pgMaxOpen` | `AGENT_SYSTEM_PG_MAX_OPEN` | `--pg-max-open` | 每进程最大连接(默认 16) |
| `pgMaxIdle` | `AGENT_SYSTEM_PG_MAX_IDLE` | `--pg-max-idle` | 每进程空闲连接(默认 8) |
| `pgConnMaxIdleSec` | `AGENT_SYSTEM_PG_CONN_MAX_IDLE_SEC` | `--pg-conn-max-idle-sec` | 空闲回收(默认 300s) |
| `pgConnMaxLifetimeSec` | `AGENT_SYSTEM_PG_CONN_MAX_LIFETIME_SEC` | `--pg-conn-max-lifetime-sec` | 连接寿命(默认不限) |
| `pgQueryTimeoutSec` | `AGENT_SYSTEM_PG_QUERY_TIMEOUT_SEC` | `--pg-query-timeout-sec` | statement_timeout 秒(默认不限) |
连接预算(KTD12):预算覆盖全部 API/Worker/LISTEN/migrator/监控连接;
100 在线用户 ≠ 100 连接。`agent-system config explain` 输出脱敏有效值
(DSN 密码打码)。启动日志打印 `storage tier: team (dialect=postgres pool=… schema=v…)`。
迁移(KTD8,U2 已实施):DDL 与版本登记同事务(中途失败整体回滚,不存在
「表已建、账本未记」中间态);PG 并发迁移者按会话咨询锁串行化;SQLite 写事务
`_txlock=immediate` 跨进程排队。库内出现比二进制新的 schema 版本时拒绝启动。
## 3. 迁移映射(SQLite → PG,U4 工具消费)
| SQLite 侧 | PG 侧 | 备注 |
|---|---|---|
| `agent-system.db`(WAL) | 同名逻辑库 | 活跃 WAL 不能只拷 `.db`;一致性备份用 VACUUM INTO |
| INTEGER 0/1 布尔列 | BOOLEAN | v9/v10/v11 起双方言已分型 |
| `INTEGER PRIMARY KEY AUTOINCREMENT` | `BIGSERIAL`/`SERIAL` | events、command_audit、audit_events |
| FTS5 虚表 + 触发器 | tsvector 生成列 + pg_trgm GIN | v4;中文子串走 trigram |
| `vec BLOB` | `BYTEA` | pgvector 类型切换在 U6,不在本映射 |
| `<data>/artifacts/` 工件对象 | 本期仍本地目录 + PG 清单 | 共享对象存储在 U5/U9 |
RDM 独立业务库与旧 Agent-System 治理库**不在**本映射内;迁移工具(U4)只处理
Backend 库,非空目标拒绝、同快照才可续传。
## 4. 容量合同(验收目标,非性能结论)
方案 §3 的量化指标(100 在线 / 300 SSE / 20 执行中 Agent / P95≤300ms 等)是
**待验证合同**。区分两个计数:**接纳的 run 数**(进入队列)与**执行许可**
(同时真正执行,含子代理、初始全局 20、每用户 2、索引 4);等待子代理/HITL 的
父 run 让出执行许可、保留会话所有权。压测在 U7 执行并绑定组件 SHA 出证。
## 5. 隔离测试库/目录/端口方案
| 资源 | 约定 | 生命周期 |
|---|---|---|
| 本机 PG 实例 | `scripts/svc.sh db create collabtest --port 8897 --tag test` | svc.sh 管理;用毕 `svc.sh collabtest stop` + `rm --purge` |
| 测试库/扩展 | 库 `agent_test`;`pg_trgm` 预装 public | 测试辅助幂等预装;CI 启动步显式预装 |
| 用例 schema | `t_*` / `pgbus_*` 前缀,随机名 | 每用例建、Cleanup 级联删 |
| 本机 Redis | `redis-server --port 6399 --save '' --appendonly no` | 纯内存、用毕即停 |
| CI | job `test-pg`:apt 安装 PG16+pgvector+Redis,端口 5432/6399 | 每次 PR 必跑;缺服务失败不跳过 |
本地跑真实库门禁:
```bash
export AGENT_PG_TEST_DSN="$(scripts/svc.sh db dsn collabtest --db agent_test --reveal | tail -1)"
export AGENT_REDIS_TEST_ADDR=127.0.0.1:6399
make test-backend-pg
```
禁止对共享/现役实例(如 `runtime/dev` 的库)跑测试;DSN 不入命令历史与任务卡。
## 6. KTD14 副本保护与保留合同
- 备份/导出/WAL/测试副本使用专用数据库角色(非应用角色),存放于受限目录
(0700,非工作区);传输与静态备份加密,解密材料存独立受管秘密存储。
- 保留期限:迁移演练副本用毕即删,最长 7 天;正式备份保留 30 天滚动 +
每月 1 份年度副本(待正式实例指定后确认)。
- 日志/报告只留统计与哈希:不落 DSN、密钥、文档正文;测试一律用脱敏数据。
- 恢复演练:每次演练恢复到新目标并核对应用可用与权限/文件完整性;
「备份命令成功」不等于可恢复。
- 阻塞项:正式导出前,未知 owner 的数据、未定位的权威文件、缺失的保留期限
任一存在即阻塞(不静默继续)。
## 7. 暂态 Worker 文件分类
| 类 | 内容 | 处置 |
|---|---|---|
| 可重建 | 构建产物 `bin/`、`node_modules/`、测试数据目录、`__pycache__` | 随时删除重建 |
| 必须迁移 | SQLite 库、`artifacts/` 工件、`.agentx/checkpoints.jsonl`、Squad FileStore/续跑标记 | U4 迁移 + 联合备份;U5 前禁止跨机接管 |
| 只读参考 | svc.env(600)、history.jsonl | 保留在实例目录,不入副本外流 |
## 8. 已知边界(诚实清单)
- CLI 子命令(apikey/user 等)不校验 tier;team 档语义只在 `serve` 入口强制。
- 迁移仍随启动执行(已原子 + 锁化);完全独立的 migrator 入口留待 U4 工具。
- 多实例安全**未**因此声明(R4/U5);本档只交付单实例 team 档与真库门禁。
- pgvector 扩展已安装 ≠ 启用;向量检索仍是应用内扫描(U6)。
## 9. 执行预算与动作授权(U3 切片 2 已实施)
### 执行许可(admission,R8)
- 设置键:`runtime.execBudgetGlobal`(全局并发执行上限,含子代理;0=不限,
默认)、`runtime.execBudgetPerUser`(每租户上限;0=不限)、
`runtime.execQueueMax`(待执行队列上限,默认 200)。数值为容量合同初值,
U7 压测后调整。
- 语义:会话回合与子代理同池计数;账本在数据库(`admission_leases`,PG 咨询
锁下原子清点),多实例天然共享;队列满时 API 在落库前 429(不写数据);
父 run 同步等待子代理或等待 HITL 时让出执行许可、保留会话所有权,恢复
执行重新获取——额度占尽时父子不互等。
- 接纳与执行分别计数:队列深度(接纳)与活跃租约(执行)是两个量,
诊断分别看 `Manager.QueueDepth()` 与 `store.ActiveExecutionSlots()`。
### KTD13 动作授权矩阵与公开契约兼容计划
矩阵(宿主侧 `server.ProjectAction`):
| 动作 | 语义 | 未注册 action-aware 时 |
|---|---|---|
| read | 读取项目资源(会话/消息/检索/下载) | 回落旧 EXT-8 只读适配器(兼容现网) |
| edit | 写入与修改 | **默认拒绝** |
| approve | 审批(HITL/命令确认) | **默认拒绝** |
| execute | 触发执行 | **默认拒绝** |
| admin | 管理 | **默认拒绝** |
规则:action-aware 适配器(组合根注入 `SetProjectActionAuthorizer`)注册后
对全部动作权威、出错 fail-closed;旧只读适配器不得自动获得写入能力。
**公开契约兼容计划**(后续版本落地):以版本化扩展把动作级判定并入
EXT-8 的 `ProjectAuthz` 公开契约(新增 action 参数的变体接口 + 契约版本号),
下游适配器按动作逐一声明能力;未声明动作保持默认拒绝,与宿主侧矩阵同语义。
旧 bool 契约在该版本内继续可用(映射为仅 read);Core/Host 与下游适配器
(RDM 的 ProjectAuthz 实现)一起验收,不另建成员权威。
## 10. SQLite → PostgreSQL 切换与恢复演练(U4 已实施)
工具:`make build` 产出 `bin/storage-migrate`(受管迁移入口;只处理 Backend 库,
不执行 SQLite dump 作为 PG SQL)。三个子命令:
```bash
# 1) 只读盘点:schema 版本、完整性、逐表计数、工件清单与哈希(§6.1)
storage-migrate inventory --source runtime/dev/data/agent-system.db \
--artifacts runtime/dev/data/artifacts --out inv.json
# 2) 一致性快照:VACUUM INTO(在线安全含 WAL)+ 可打开校验 + 逐表计数对账(§6.2)
storage-migrate backup --source runtime/dev/data/agent-system.db --out snap.db
# 3) 受管迁移:目标建 schema/扩展后按行复制;身份登记 + 逐表校验和 + 终验(§6.3)
storage-migrate migrate --source snap.db --target "$DSN" \
--migration-id <名> --artifacts runtime/dev/data/artifacts --out report.json
```
迁移身份与续传:`migration_id + source_snapshot_id(快照 SHA-256)+
source_schema_version` 登记在目标 `migration_control`;**仅同一冻结快照可续传**
(换快照/换身份均拒绝);目标业务表已有数据而身份为空即拒绝(不覆盖)。
校验与报告:逐表源/目标计数与主键序哈希链校验和(布尔列按目标 schema 对称
归一);复制后推进 SERIAL 序列;未知 owner(users 之外,''/'local' 单租户默认
除外)阻塞迁移;报告只含计数/校验和/清单哈希——无 DSN、密钥与行正文(KTD14)。
类型映射以目标 schema 为准(SQLite 0/1→BOOLEAN、BLOB→BYTEA、生成列不迁、
FTS5 影子表不迁——PG 侧生成列与索引自动重建);`admission_leases` 为运行态
不随迁。
### 切换顺序(正式窗口须另行授权;当前仅隔离演练已验证)
1. 固定源制品与路径,`inventory` 盘点;指定迁移 owner、窗口、回退判据。
2. `backup` 冻结快照(活跃 WAL 库不得只拷 `.db` 文件)。
3. 预演:独立测试目标 PG 上 `migrate`,核对报告全绿;预演库不作为正式目标。
4. 正式窗口:停新写 → 等待/收口在途 run(未知副作用记 recovery hold)→
停旧写者 → 终快照 → 空正式目标 `migrate` → 报告全绿。
5. 单入口切 team 档冒烟(登录/项目/会话/审批/检索/下载);fail-closed 不回 SQLite。
6. **PG 接受新写入前**可撤回;**之后**禁直切回旧 SQLite(向前修复或专项回迁)。
备份基线(正式目标启用后):pg_dump 逻辑备份 + pg_basebackup 物理基础备份与
WAL 归档/PITR;pg_dump 不能作 WAL 回放基础。每次演练恢复到新目标并核对。