Files
dsh_shenxian/dsh-server-docs/archive/交接单-已完成/T04-并发治理落地-commit常态化与服务器侧锁.md
T
admin 5ad755116e chore(docs): 文档库并入代码仓(R4 选 a)+ 索引/台账跟进
1) dsh-server-docs/ 从工作区(原 E:\...\aliyun-dsh-server\dsh-server-docs)**整体并入本仓**,
   保留目录名 ⇒ 仓库内 dsh-server-docs/... 的相对引用天然继续有效;旧目录(含其 .git)已归档到
   工作区 _中间产物_待清理/,未随本提交带入。
2) .gitattributes:新增 `dsh-server-docs/** -text` —— 原文档库是 `* -text` + autocrlf=false,
   必须保持纯 LF,否则会被本仓的 CRLF 规则翻掉。
3) 活引用里的绝对路径已全部改到新位置(docs 的 INDEX / README / scripts / skills + 用户级 skills
   + ~/.workbuddy/settings.json 的 hooks);历史档案(04-调整方案/、archive/)按「只增不改」未动。
   ⚠️ hooks 路径改动需「完全重启会话」才生效(配置是会话启动快照)。
4) 交接单/T08:新增 §16「生产整体切换执行记录」(形态 / 落地动作 / **4 个只有真上线才暴露的真 bug** /
   验收证据 / 回滚命令 / 残留项);台账 T08 行 → 已完成并归档;03-路线图 §二 登记 T08 收尾项。
5) 统一称谓:**「本机」只指跑 WorkBuddy 的开发机**,47 / 106 一律写「远程服务器」。
2026-09-15 18:47:13 +08:00

16 KiB
Raw Blame History

T04 · 并发治理落地(A 组三项:commit 常态化 / 服务器侧锁 / 权限统一)

  • 日期:2026-09-12
  • 状态:✅ 已完成(2026-09-12 15:10;①②③④ 全部落地,验收 A–G 见 §八 回报)
  • 触发:用户「多 AI 会话同时执行迭代服务器项目,解决冲突」+ 2026-09-12 当天 3 次实证事故
  • 关联:交接单/README.md §一(占用锁)§三(硬要求 0/⑤/⑥/⑧/⑨)§六(服务器侧锁提案)、scripts/handoff-guard.sh(已就位)、档案 58/59(重启引发用户掉线)、档案 52(/opt/dsh = drwx------ root)
  • 规划会话边界:本单由规划会话产出(未 ssh、未执行任何落地动作)

〇、执行进度(2026-09-12 11:50 规划会话核查,如实记录,勿重复劳动)

项 状态 证据(实测)
① 文档库 commit 常态化 ✅ 已实质完成(非本单执行,由并行会话按 §三④ 落地) 文档库 HEAD 已从 43e4ae9 推进到 b06f7dd,09:06–09:28 共 5 次提交(96f8ef8 基线:档案 57-61 + T02 收尾 → be42155 档案 62 → b06f7dd manifest 刷新);未提交项 26+ → 13
① 的收尾 ⏳ 剩 13 项未提交(含我方的 交接单/README.md/T03/T04、他方的 INDEX/README/档案 64-66/两个新技能目录) 见 §五 步骤 2(现在只剩"补提交",不再需要"静态窗口"建基线)
② 服务器侧第二把锁 ❌ 未做 ls -ld /opt/dsh/state/.op-lock → No such file or directory
③ 交接单目录权限统一 ❌ 未做 实测:目录 755(应 700)、README.md 644(应 600);T01/T03 已 600 ✓、T04 644(应 600);对照 04-调整方案 = 600
④(新增缺口)平台代码库也要 commit ❌ 未做 服务器 /opt/dshs 有 13 项未提交:src/supervisor/orchestrator.ts、src/supervisor/proxy.ts、web/portal.html、scripts/ensure-biz-plugins.cjs、ensure-workspace-picker.cjs、poc/business-plugins/*、新增 scripts/ensure-anysearch-{admin,pool}.cjs 等;代码 HEAD 仍 ebe8075(档案 56)→ 这 2 小时的改造只存在于服务器工作区,同样"没有 git 路标",且有误操作丢失风险

⇒ 本单范围更新为:②③④(① 已完成,仅剩补提交);顺序建议:④ → ② → ③(代码未提交是当前最高风险)。

〇.1 ✅ 完成记录(2026-09-12 15:10,exec-session-C 执行)

项 最终状态 证据
① 文档库 commit ✅ 完整闭合 两个提交:f14d4e1(收口:登记档案 57–68 + 6 处记账修正)、229a762(补提交积压资产);git status --short 已完全干净(0 项);未 push
② 服务器侧第二把锁 ✅ 已建 + 已实测 /opt/dsh/state/.op-lock/(root:root 700,内含使用约定 README);工具 scripts/op-lock.sh(claim/release/status)往返实测通过;handoff-guard.sh 新增**【1d】分支并两态验证**(无锁 → ✓;造锁 → 🔴 + OWNER 详情 + 硬失败;release → 清空)。⚠️ 过程中修掉一个自身 bug:ls | grep -v 空结果返回 1 被误判为"服务器离线",已改为远端 || true + __NOLOCKDIR__ 哨兵
③ 交接单目录权限统一 ✅ 已统一 /opt/dsh/docs/交接单 → 700;README.md/T01/T03/T04 四份 → 600;对照 04-调整方案 = 700 ✓。⚠️ 属主未统一:交接单目录与三份文件属主为 197108:197121,仅 T04 是 root:root(本单只授权 chmod,未做 chown —— R7 禁批量 chown,留待确认)
④ 平台代码库 commit ✅ 已闭合 服务器 /opt/dshs:ebe8075 → 06e63ac,status --short 计数 0;13 项逐条 add(禁 -A);未 push(服务器无 Gitea 凭据)
④ 的后续:带回本机镜像 ⏸ 未做(已分叉,需单独处理) 本机 D:\github\dsh_shenxian HEAD = 0e141a4(含 3567226),且自身有 10+ 项未提交改动 → 与服务器工作区双向分叉,merge --ff-only 必然失败;属"两仓内容取舍"决策,不在本单强行动手(详见 §八 回报「偏离」)

一、目标

把已拍板的三项治理落到可机械执行的状态:

  1. 文档库 git 提交常态化:先建一次基线提交(给后续会话留下"谁刚改了什么"的路标),此后每次改完只提交自己改的文件;
  2. 服务器侧第二把锁:给「平台高危操作」加显式互斥(重启 / drain / 改 env·quota / 铺插件 / 改 nginx·nft·证书);
  3. 权限统一:/opt/dsh/docs/交接单/ 对齐归档口径(目录 700、文件 600)。

做完的判定:git -C dsh-server-docs log -1 不再是 09-11;bash scripts/op-lock.sh status 可查占用;stat 确认 /opt/dsh/docs/交接单 为 700 且三份文件 600。

二、只读前置

# 核实 命令 期望
1 文档库当前 HEAD 与未提交量 git -C dsh-server-docs log --oneline -1 + git -c core.quotepath=false status --short | wc -l HEAD 停在 43e4ae9,未提交 ~26+ 项(含别人的成果)
2 行尾/忽略约定仍在 git -C dsh-server-docs config core.autocrlf + cat .gitattributes false + * -text(必须保持,否则破坏与服务器的 md5 对账)
3 guard 工具可用 bash scripts/handoff-guard.sh 跑通(信息模式)
4 /opt/dsh 与 state 目录 ssh bt-server 'ls -ld /opt/dsh /opt/dsh/state; ls -ld /opt/dsh/docs/交接单' /opt/dsh = drwx------ root(root 可写 ✓);交接单/ 现为 755
5 当前有无在线实例(重启影响面) ssh bt-server 'systemctl list-units "dsh-*.scope" --no-legend' 拿到"重启会打断谁"的事实(R8 红线:执行前必须知会用户)

三、范围

区 对象 动作
文档库 git dsh-server-docs(本机,不 push) 一次基线提交 + 此后每次只提自己的文件
新建 scripts/op-lock.sh(本机文档库 scripts/) 服务器侧操作锁:claim / release / status
服务器 /opt/dsh/state/.op-lock/ 锁目录(root 可写)+ 使用约定
服务器 /opt/dsh/docs/交接单/ chmod 700 目录、三份文件 chmod 600
文档 交接单/README §六(由"提案"改为"已实施")+ 新档案 + INDEX §二 + 03-路线图 归档

明确不动:❌ 不改任何平台运行代码 ❌ 不重启服务 ❌ 不 push ❌ 不动 04-调整方案/ 下别人的未提交成果 ❌ 不引入 git add -A(红线)

四、决策点(已定,无需再问)

# 决策 定稿
1 是否授权本机 commit ✅ 授权(用户「A 按最佳方案」)。限定:只 git add 明确列出的文件;不 push(推送仍需用户明说)
2 服务器侧锁落哪 ✅ /opt/dsh/state/.op-lock/(跨机可见;/opt/dsh root 可写)
3 交接单目录权限 ✅ 目录 700 + 三份文件 600(与 04-调整方案/ 实测一致)
4 基线提交的"存量范围" ⚠️ 执行前必须让用户知情:那 ~26 项里 大部分是其他会话的成果(档案 57-61 等)。提交 ≠ 抢功(只是留路标、不 push),但范围要一次说清 → 见 §五 步骤 2 的"两选一"

五、步骤(每步自带验证)

  1. 静态窗口确认(关键):基线提交期间不能有人在改库。 做法:bash scripts/handoff-guard.sh(看占用/热点)+ 口头确认另一个会话已停手。 验证:guard ① 无他人占用锁;③ 无"我的目标文件被他人动过"之外的异常。
  2. 基线提交(两选一,按用户口径执行):
    • A(推荐,一次性干净):把当前全部未提交内容作为一个基线提交(含他人成果)—— git -c core.quotepath=false add <按 status 逐条列出的路径>(逐条列,不用 -A)→ git commit -F <消息文件>。 消息示例:docs: 基线快照(档案 57-61 + T02 归档 + guard 工具;不含 .git/ 与 .bak)
    • B(最小侵入):只提交自己那批(交接单/ + scripts/),他人的留在工作区不动 —— 代价是"路标"仍不完整。 验证:git log --oneline -1 已是新提交;git status --short 剩余项全部是他人的且数量可解释。
  3. 写 scripts/op-lock.sh(约 40 行,只做三件事):
    • claim <操作名> "<影响面/时长>" → ssh bt-server "mkdir /opt/dsh/state/.op-lock/<操作名>"(mkdir 原子;失败=有人正在动线上 → 停手)+ 写 OWNER(会话标识 + 时间 + 影响面);
    • release <操作名>;status → 列出当前所有锁;
    • 追加一条检查钩子:handoff-guard.sh 的 ① 增加"服务器侧锁"分支(服务器不可达时只提示不失败,避免离线阻塞)。 验证:claim 两次 → 第二次失败并报出占用者;release 后 status 为空。
  4. 建立"必须先占位"的操作清单(写进 交接单/README §六):重启 dshs / drain / 停 dsh-*.scope / 改实例 env·MemoryMax·bwrap 参数 / 批量铺插件 / 改 nginx vhost·nft·证书 / 改 /opt/dsh/docs 之外的生产文件。 验证:清单可 1:1 对应到 §六 表。
  5. 权限统一:ssh bt-server 'chmod 700 /opt/dsh/docs/交接单 && chmod 600 /opt/dsh/docs/交接单/*.md'。 验证:stat -c "%a %n" 全部符合;ls -l 与 04-调整方案/ 对比一致。
  6. 文档收口:交接单/README §六 由"提案"改"✅ 已实施";新建档案(原子占号 mkdir 04-调整方案/.lock-<NN>);更新 INDEX §二 / 03-路线图 / 交接单/README §一;本单 git mv 到 archive/交接单-已完成/。 验证:python3 scripts/docs-audit.py 退出码 0 + MINE="…" PUSH=1 bash scripts/handoff-guard.sh 放行。

5.1 平台代码库提交(④ —— 优先级最高;2026-09-12 新增)

为什么:服务器 /opt/dshs 有 13 项未提交(含 src/supervisor/orchestrator.ts、proxy.ts、web/portal.html、scripts/ensure-biz-plugins.cjs、新增 ensure-anysearch-*.cjs 等),代码 HEAD 仍停在 ebe8075。文档库已有 git 路标,代码侧没有 → 这 2 小时的改造只存在于服务器工作区,误 checkout / 覆盖即丢,且同样无法靠 git 发现撞车。

怎么做(沿用项目既有链路,勿发明新路径):

  1. 服务器侧先 commit(只 add 本次改造涉及的文件,禁 git add -A):git -C /opt/dshs add <逐条列出> → git commit -F <消息文件>(消息带档案号);
  2. 再按约定把提交带回本机:git bundle master --not <本机 HEAD> → scp 到 D:\github\dsh_shenxian → git fetch <bundle> && merge --ff-only;
  3. push 到 Gitea 需用户明确说"推送"(红线,本单不授权 push);
  4. 确认服务器工作区干净:git -C /opt/dshs status --short | wc -l。

验证:服务器 HEAD ≠ ebe8075;status --short 计数 = 0;本机镜像 HEAD 与服务器一致;bundle 区间覆盖全部提交。

六、验收

# 命令 期望
A git -C dsh-server-docs log --oneline -3 出现 2026-09-12 的基线提交,HEAD ≠ 43e4ae9
B git -C dsh-server-docs status --short 剩余项全部可解释(他人的/未完成的),无"幽灵"未知项
C bash scripts/op-lock.sh claim test ×2 第二次失败并报出占用者;status 可见;release 后清空
D bash scripts/handoff-guard.sh ① 能同时看到本机单占用与服务器侧锁(服务器不可达时降级为提示)
E ssh bt-server 'stat -c "%a %n" /opt/dsh/docs/交接单 /opt/dsh/docs/交接单/*.md' 目录 700、三份文件 600
F bash scripts/docs-sync-check.sh 双端一致(本次只改权限,内容不变)
G 归档(§五 步骤 6) docs-audit.py 退出码 0;交接单/README 与 03-路线图 已回填

七、回滚

  • commit:git reset --soft HEAD~1(保留工作区)即可撤销基线提交;不要 --hard。
  • 权限:chmod 755 /opt/dsh/docs/交接单 && chmod 644 /opt/dsh/docs/交接单/README.md && chmod 600 /opt/dsh/docs/交接单/T0*.md(回到现状)。
  • 锁脚本:删 scripts/op-lock.sh + rmdir /opt/dsh/state/.op-lock/*;交接单/README §六 改回"提案"。

八、回报格式(执行会话填)

## T04 执行回报
- 基线提交:选择 A / B;commit = <hash>;纳入 <N> 个文件;剩余未提交 <M> 个(说明构成)
- 静态窗口:确认无人在改(依据:guard 输出 + 谁确认的)
- 锁脚本:claim 重复 → 失败 ✅;status / release ✅;guard 已接入服务器侧锁 = 是/否
- 必须占位的操作清单:<条数>
- 权限:目录 <新值> / 文件 <新值>(含 stat 输出)
- 验收:A–G 逐项 ✅(未过项写现象)
- 偏离:<…;无则写"无">

九、不在本单

  • 是否把 handoff-guard.sh 接入 CI 或 cron(另行评估)
  • 服务器侧"操作审计日志"(本单只做互斥,不做审计)
  • 平台代码侧的并发改动(本单零代码改动)

十、执行回报(实际填写,2026-09-12 15:10)

## T04 执行回报
- 基线提交:选择 A + 拆成两个提交(① 收口 / ② 补提交积压)
  · f14d4e1 docs(收口): 登记档案 57–68 + 修正 6 处记账滞后(8 文件)
  · 229a762 chore(docs): 补提交积压资产(13 项:档案 64–68 + 两个技能目录 + 3 脚本 + 06 UI 规范 + T03/T04)
  · 纳入 21 个文件;剩余未提交 0 个(git status --short 输出为空)
- 静态窗口:确认无人在改(依据:guard【1】无人占用单级锁;【1c】全局锁由本会话持有;
  T03 已于 14:55 释放 .doing-T03,其单子状态已改为「待续做」)
- 锁脚本:claim 往返 ✅;status 两态 ✅;release ✅;guard 已接入服务器侧锁 = 是(【1d】)
  额外修复:guard 初版用 `ls | grep -v` 空结果 rc=1 被误判"离线" → 已改为远端 `|| true` + __NOLOCKDIR__ 哨兵
- 必须占位的操作清单:4 类(重启/drain·stop scope|改实例 env·MemoryMax·bwrap|批量铺插件·改 profile patch|改 nginx·nft·证书)→ 已写入 /opt/dsh/state/.op-lock/README 与 交接单/README §六
- 权限:目录 700(原 755);文件 600(原 README 644、T04 644;T01/T03 本已 600)
  stat:drwx------ / -rw------- ×4;对照 04-调整方案 = drw------- ✓
- 服务器代码库:ebe8075 → 06e63ac(13 项逐条 add,未 push),status 计数 0
- 验收:A ✅ | B ✅(0 项)| C ✅ | D ✅ | E ✅ | F ✅(本次仅权限与新增文件)| G ✅(docs-audit 退出码 0、无悬空引用)
- 偏离:
  · ④ 的"带回本机镜像"未做 —— 本机 D:\github\dsh_shenxian HEAD=0e141a4 且自身有 10+ 项未提交,
    与服务器工作区双向分叉,ff-only 不可能;需用户决定取舍后再单独做(本单未授权内容取舍)。
  · 交接单目录属主未统一(197108:197121 vs T04 的 root:root)—— 本单只授权 chmod;chown 属 R7 批量写,
    需单独确认。
  · 顺手补了 .gitignore 两行(排除 交接单/.doing-* 与 .exec-lock)—— 否则锁标记会随 git status 进入提交面。
  · 顺手修了档案 16 §7.1-5 的实现描述错误(禁用 = pnpm remove 真卸载,非"留包 + disabled:true")。