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
80 lines
4.7 KiB
Markdown
80 lines
4.7 KiB
Markdown
# 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;实施需主提案阶段批准后再授权
|