# 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//.start.lock`。 - `flock` 不可用或超时:退出非 0,写 hist_event,**不得**执行 deploy/start/stop/user。 - 账户操作与生命周期互斥(同一锁)。 ## 6. 验收用例(U1) | # | 场景 | 判据 | |---|---|---| | T1 | 实例有合法 manifest;`svc 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;实施需主提案阶段批准后再授权