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
4.7 KiB
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接线、U2install写身份。
8. 任务卡建议(待授权后 task-start)
- 分支名:
feature/svc-deploy-u1-account-binding - R0:与本提案合入后的
origin/main(或与 U4 兄弟共享批准时的同一 R0) - 交付模式:manual;实施需主提案阶段批准后再授权