Files
Agent-System-Dev/docs/svc-deploy/u1-instance-account-binding.md
T
weichen 8a29e40d0d Record the account and recovery plan review
Why: preserve evidence, current contracts and the next review scope without changing the running system.

Evidence: SELF startup, sync and document validation receipts in the task card; runtime and fault acceptance NOT_RUN.

Impact: task metadata, planning index and account specifications only; component pins and business code unchanged.

Refs: feature/svc-account-durability-plan; Documents account r2 and recovery r3
2026-10-12 10:10:29 +00:00

80 lines
4.7 KiB
Markdown
Raw 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 实例—账户绑定补齐(规格 v0.2 候选)
状态:已启动实施(分支 `feature/svc-deploy-u1-account-binding`)。主记录:`modules/documents/docs/proposals/2026-10-12-svc-unified-deploy-and-login-key.md` §7 U1。
上述为 v0.1 历史状态,基础已见当前固定源码。本轮 v0.2 只细化账户方案 r2 的 R15/U7,新增合同未批准或实现;Documents 候选尚未推进 Dev gitlink。
前置:恢复方案 recovery U1 已合入 main(Dev #415)——`docs/recovery/u1-identity-manifest.md`、`scripts/svc_manifest.py`、启动身份校验与 `svc init`。
本增量**不重做** manifest 层;只补齐账户操作与安装入口对既有身份合同的消费缺口。
基线:任务卡 R0;实施中。真实 PG 绑定专项缺环境标 NOT_RUN。
## 1. 目标与非目标
**目标:** 同一实例的启停、升级、开户、签发/撤销登录 Key 始终命中同一存储与数据根;缺失、不符或锁不可用时拒绝;为后续 `install` / doctor 提供稳定的实例解析入口。
非目标:不实现二进制下载(U2)、不实现 doctor/env prepare 全量(U3)、不实现一次性 Key 语义(U4)、不改登录页(U5)。
## 2. 不变量(相对 recovery U1)
| ID | 不变量 | 相对 #415 |
|---|---|---|
| B1 | 账户 CLI 只接受「实例名 → manifest 解析出的 data_root / db / secrets 引用」 | 新增消费方 |
| B2 | 禁止回落默认 `./data` 或未声明 DSN | 新增硬拒绝 |
| B3 | OpenExisting:目标不存在则失败;账户模式只校验兼容 schema,禁止自动 migrate | r2 候选收紧,当前代码仍 migrate |
| B4 | 无 `flock` / 锁获取失败 → 拒绝冲突操作(deploy/start/stop/user/*) | 收紧现状「直通」 |
| B5 | `install` / 兼容 `--from` 写入同一 manifest 身份字段,不另起配置根 | 入口骨架 |
## 3. 触点与文件
| 文件 | 变更 |
|---|---|
| `scripts/svc.sh` | `user` 子命令骨架:解析 `ENV_NAME` → 读 manifest/`svc_manifest.py` → 组装 `--data`/`AGENT_SYSTEM_DSN`/`--open-existing` 调 `$ENV_BIN`;锁检查收紧;`install` 可先做 dry-run 计划打印(完整 binary/source 属 U2) |
| `scripts/svc_manifest.py` | 如需:导出「账户操作所需最小字段」查询(data_root、db mode/ref、auth);不改 schema=1 语义 |
| `modules/backend/cmd/agent-system/main.go` | `user` 子命令增加 `--open-existing`(或全局 store 打开标志);缺库/缺目录失败 |
| `modules/backend/internal/store/store.go` | `OpenExistingSQLite` / PG 等价:不创建新根,账户模式只校验兼容;迁移另行执行 |
| `tests/test_svc_identity.py` 或新 `tests/test_svc_user_binding.py` | 错误 data、缺 manifest、无 flock 拒绝;正确绑定命中 |
## 4. OpenExisting 合同
```
OpenExisting(path|dsn, opts):
if storage path/parent missing → error (do not create)
if SQLite file missing → error
open DB
account operations → read schema/identity only; incompatible or missing identity → error
explicit maintenance migration → separate approved entry with service isolation
never create empty business DB as side effect of account recovery
```
CLI 默认:账户运维命令使用 `OpenExisting` + 兼容检查,不 migrate。当前 requireCompatible 自动迁移属于待整改基础,不是本候选允许的行为。
`svc init` / 首次服务启动仍走现有 Open(可创建)路径,与 recovery U1 一致。
## 5. 锁合同
- 复用 `runtime/<name>/.start.lock`。
- `flock` 不可用或超时:退出非 0,写 hist_event,**不得**执行 deploy/start/stop/user。
- 账户操作与生命周期互斥(同一锁)。
## 6. 验收用例(U1)
| # | 场景 | 判据 |
|---|---|---|
| T1 | 实例有合法 manifest;`svc <name> user list` | 使用 manifest data_root/DSN;列表与该库一致 |
| T2 | 故意传错误 `--data` 或未绑定实例 | 拒绝;不创建目录;不写默认 `./data` |
| T3 | 删除 data 根后再 user create | OpenExisting 失败;无新空库 |
| T4 | 隐藏 `flock`(PATH 去掉)后 deploy/user | 拒绝;旧服务若在跑则仍在 |
| T5 | recovery U1 既有 T1–T6 回归 | 全绿(不破坏 identity) |
真实 PG:绑定 dbref 与 marker 一致才允许 user 操作;缺环境标 NOT_RUN。
## 7. 完成门槛与依赖
- 完成条件见主提案 §7 U1 行。
- 依赖:main 已含 recovery U1(#415)。
- 被依赖:U4 CLI 签发、U5 `svc user` 接线、U2 `install` 写身份。
## 8. 任务卡建议(待授权后 `task-start`)
- 分支名:`feature/svc-deploy-u1-account-binding`
- R0:与本提案合入后的 `origin/main`(或与 U4 兄弟共享批准时的同一 R0)
- 交付模式:manual;实施需主提案阶段批准后再授权