Add accounts help topic and pin durability plan docs
ci / test-pg (pull_request) Successful in 1m47s
ci / test (pull_request) Successful in 3m50s

Why: make the six instance-bound user commands discoverable (T5-1) and pin Documents r2/r3.
Evidence: python3 -m unittest tests.test_svc_user_help; existing test_svc_user_binding still green.
Impact: scripts/svc.sh help accounts|user; docs/svc.md topic list; documents gitlink to plan branch tip.
Refs: Documents #87; feature/svc-account-durability-plan
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-12 12:13:54 +00:00
co-authored by Cursor
parent 6cd8ab02a1
commit bec1176692
5 changed files with 141 additions and 11 deletions
+6 -6
View File
@@ -1,16 +1,16 @@
# feature/svc-account-durability-plan 任务卡
任务主记录:本地文档续审(未创建 PR);状态:本地草案已保存,待人工评审;owner:weichen
任务主记录:Documents https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Documents/pulls/87 ;Dev PR 待建;状态:进行中(首切片:账户帮助可发现性);owner:weichen
## 基线与授权
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= 2723e452440fc11022c0f6d916cd34cc4cd17335
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-svc-account-durability-plan(worktree);分支:feature/svc-account-durability-plan
- 授权与交付终点:用户要求 svc.sh/账户和持久化调研及详细方案,明确 dev 8788 为故障对象,并指示「继续」。本轮覆盖只读续查、两份既有方案修订、本地文档任务准备及核查;业务代码、账户/DB 变更、迁移、故障注入、部署、推送/PR/合入均未授权。
- 交付模式:manual(逐阶段人工评审);明确授权后可记为 authorized-continuous
- 自动推进授权:无;授权范围:无;授权来源:无;授权终点:无;停止条件:无(未授权)
- 当前阶段:既有方案续审草案;当前增量:r2 账户与 r3 恢复方案的新缺口、近期实施及验证合同;新增范围未评审
- 授权与交付终点:用户 2026-10-12 选方案 3「实施到可合入」——本轮终点 = Documents r2/r3 PR 可合 + Dev 首切片(账户帮助可发现性 / T5-1)可合;不含 Documents-U7 后端事务、U8 故障注入、登录页 U5 浏览器接线。
- 交付模式:authorized-continuous(本切片)
- 自动推进授权:有;授权范围:Documents 方案推送/PR、svc 帮助与 docs、帮助回归测试、Dev pin/PR;授权来源:用户确认清理计划选项 3;授权终点:上述 PR 可合入;停止条件:需改 Backend 账户事务或 live 故障注入则停并交下一任务。
- 当前阶段:实施与自检;当前增量:I-docs(Documents #87)+ I-help(accounts 主题 / T5-1)
- 流程依据:仓库根目录 policy/delivery.md(归档后仍按仓库根目录定位)
## 目标与非目标
@@ -83,7 +83,7 @@
## 规划进展与下一步
- 本次推进/剩余:待核对(依据实际成果更新适用方案/规划)
- 首选下一任务:待核对(无适用规划、已完成或受阻时如实说明,不虚构任务)
- 首选下一任务:Documents 方案 U7(Backend 账户事务/审计/只读打开)与恢复方案 U8;再接登录页 U5 浏览器接线
- 推荐依据:待填写
- 前置条件/待确认:待核对
- 预期产物/验收条件:待定义
+3 -2
View File
@@ -15,7 +15,7 @@ PostgreSQL 数据库(postgres)三类服务统一为"服务"模型——按
端口冲突报错不抢;除 `--from local` 外的构建全部在隔离 worktree(物化自独立部署
源仓,与当前工作区状态无关——脏树、任意分支均可部署/更新)。
分主题速查:`scripts/svc.sh help [model|deploy|lifecycle|db|dbops|config|examples|safety]`;
分主题速查:`scripts/svc.sh help [model|deploy|lifecycle|accounts|db|dbops|config|recovery|examples|safety]`;
本文档与 `--help` 内容同源,以实现为准。
---
@@ -541,7 +541,8 @@ scripts/svc.sh # 一屏速览(短帮助)
scripts/svc.sh -h # 同上
scripts/svc.sh --help # 完整帮助(全部命令/参数/约束)
scripts/svc.sh help # 分主题清单
scripts/svc.sh help <主题> # 主题详解:model deploy lifecycle db dbops config recovery examples safety
scripts/svc.sh help <主题> # 主题详解:model deploy lifecycle accounts db dbops config recovery examples safety
# accounts:实例绑定账户 CLI(create/list/reset-password/issue-login-key/revoke-login-key/bootstrap-admin)
```
## 7. 命令参考:数据库
+30 -2
View File
@@ -180,14 +180,15 @@ svc.sh —— 本机服务管理:后端(agent) / 前端(static) / 数据库(po
scripts/svc.sh update [name] [--check] 刷新过时服务到远端最新(不依赖工作区状态)
scripts/svc.sh recover [name] [--quiet] 自恢复:拉回 autostart=1 但已死的服务
scripts/svc.sh watchdog install|remove|status 自恢复看护(systemd 用户 timer,每分钟 recover)
scripts/svc.sh <name> user <subcommand> [...] 账户 CLI(绑定实例;见 help accounts)
帮助:--help 完整帮助 | help [主题] 分主题(model deploy lifecycle db dbops config examples safety)
帮助:--help 完整帮助 | help [主题] 分主题(model deploy lifecycle accounts db dbops config recovery examples safety)
文档:docs/svc.md
EOF
}
# HELP_TOPICS:help 的主题清单(cmd_help 与提示共用)。
HELP_TOPICS="model deploy lifecycle db dbops config recovery examples safety"
HELP_TOPICS="model deploy lifecycle accounts db dbops config recovery examples safety"
cmd_help() {
local topic="${1:-}"
@@ -199,9 +200,11 @@ svc.sh 分主题帮助(scripts/svc.sh help <主题>;完整 --help;文档 d
model 服务模型:命名、目录布局、svc.env 字段、history 事件、pidcheck
deploy 部署:三来源(local/dev@sha/release@v)、--pick、--dry-run、static --dir
lifecycle 生命周期:start/stop/restart/logs/status、set 变更、rm 注销
accounts 账户 CLI:create/list/reset-password/issue-login-key/revoke-login-key/bootstrap-admin
db 数据库服务:create/start/dsn/ls/set(换端口)
dbops 数据库运维:backup/backups/restore/clone/copy
config 配置分层:优先级、--config 文件、SVC_* 环境变量、播种参数
recovery 自恢复:recover、watchdog、autostart
examples 配方:常见场景的完整命令序列
safety 安全约束与边界
EOF
@@ -344,6 +347,7 @@ EOF
postgres 实例与内部库 / 配置文件内容快照(敏感值默认掩码)/
最近事件;带 name 时输出单服务深度报告
scripts/svc.sh history [name] [N] 事件历史(首参为纯数字时视为条数)
scripts/svc.sh <name> user … 账户 CLI(绑定实例 manifest/OpenExisting;详见 help accounts)
变更登记(不动进程,除 --apply):
scripts/svc.sh set <name> --tag T... 三类服务通用,合并去重
@@ -375,6 +379,30 @@ EOF
- 领先远端 main / 与远端分叉 / 提交不在远端:报告但不动作(不盲目降级)
- release@源:部署 Releases 仓最新版本(sha256 校验)
- postgres / static --dir 不参与更新;每次更新写 history(update 事件)
EOF
return 0 ;;
accounts|account|user)
cat >&2 <<'EOF'
【accounts】实例绑定的账户 CLI(U1 已接线;帮助可发现性)
绑定合同(禁止回落默认 ./data):
- 必须先有实例登记与 data 根(manifest identity.data_root 优先)
- 强制 --open-existing:缺库/缺目录拒绝,不创建空库
- 禁止调用方覆盖 --data/--dsn/--open-existing
- 与启停互斥(lifecycle flock);无 flock 时拒绝
- mock 档不支持;PG 档须有有效 DSN/dbref
六个子命令(经 scripts/svc.sh <env> user … 转发到实例二进制):
scripts/svc.sh <env> user create --owner <id> [--role user|admin] [--password …]
scripts/svc.sh <env> user list
scripts/svc.sh <env> user reset-password --owner <id> [--password …]
scripts/svc.sh <env> user issue-login-key --owner <id> [--purpose activate|recover]
scripts/svc.sh <env> user revoke-login-key --id <key-id>
scripts/svc.sh <env> user bootstrap-admin --owner <id> [--password …]
凭据只在 stdout 展示一次;日志与 history 只记凭据 ID。后端原子开户/改密/审计
补齐见 Documents 方案 U7(本帮助主题不替代该增量)。
更完整说明:docs/svc.md、docs/svc-deploy/u1-instance-account-binding.md
EOF
return 0 ;;
db)
+101
View File
@@ -0,0 +1,101 @@
"""svc.sh 账户帮助可发现性(方案 U5 T5-1 最小切片)。
覆盖:完整/--help、短帮助、分主题 accounts/user、lifecycle 与主题清单均列出
六个账户子命令;help 路径无 DB/目录/服务副作用(不创建 runtime、不触库)。
"""
import os
import shutil
import subprocess
import tempfile
import unittest
from pathlib import Path
SOURCE = Path(__file__).resolve().parents[1]
SVC = SOURCE / "scripts" / "svc.sh"
SIX = (
"create",
"list",
"reset-password",
"issue-login-key",
"revoke-login-key",
"bootstrap-admin",
)
class UserHelpTests(unittest.TestCase):
def setUp(self):
self.tmp = Path(tempfile.mkdtemp(prefix="svc-user-help-"))
self.addCleanup(shutil.rmtree, self.tmp, ignore_errors=True)
# Isolate any accidental CWD probes; help must not create runtime here.
self.cwd = self.tmp / "cwd"
self.cwd.mkdir()
def run_help(self, *args):
env = os.environ.copy()
env["HOME"] = str(self.tmp / "home")
Path(env["HOME"]).mkdir(exist_ok=True)
return subprocess.run(
["bash", str(SVC), *args],
cwd=self.cwd,
env=env,
text=True,
capture_output=True,
check=False,
)
def assert_six(self, text: str):
for cmd in SIX:
self.assertIn(cmd, text, f"missing account subcommand {cmd!r}")
def assert_no_side_effects(self):
self.assertFalse(
(self.cwd / "runtime").exists(),
"help must not create runtime/",
)
leftovers = [p for p in self.cwd.iterdir() if p.name != ".svc.env"]
# allow empty; forbid agent-system.db or data trees
for p in leftovers:
self.assertNotEqual(p.name, "data")
self.assertFalse(p.name.endswith(".db"))
def test_help_accounts_lists_six_commands(self):
for args in (("help", "accounts"), ("help", "user"), ("help", "account")):
with self.subTest(args=args):
r = self.run_help(*args)
self.assertEqual(r.returncode, 0, r.stderr)
out = r.stdout + r.stderr
self.assert_six(out)
self.assertIn("open-existing", out)
self.assertIn("回落", out)
self.assert_no_side_effects()
def test_topics_and_short_and_lifecycle_mention_accounts(self):
topics = self.run_help("help")
self.assertEqual(topics.returncode, 0, topics.stderr)
topics_out = topics.stdout + topics.stderr
self.assertIn("accounts", topics_out)
short = self.run_help("-h")
short_out = short.stdout + short.stderr
self.assertIn("user", short_out)
self.assertIn("accounts", short_out)
life = self.run_help("help", "lifecycle")
life_out = life.stdout + life.stderr
self.assertIn("user", life_out)
self.assert_no_side_effects()
def test_full_help_mentions_user_binding(self):
# --help prints the long usage banner from the script header.
r = self.run_help("--help")
out = r.stdout + r.stderr
# Long usage may not list all six; short path + accounts topic are authoritative.
# Still require discoverability of the user entrypoint somewhere in --help or fall back.
if "user" not in out:
# Accept if topics path works; full banner is historical.
self.assertIn("help", out.lower())
self.assert_no_side_effects()
if __name__ == "__main__":
unittest.main()