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 一律写「远程服务器」。
6.3 KiB
6.3 KiB
69 · 并发治理落地(T04):文档库 commit 常态化 + 服务器侧操作锁 + 权限统一
- 日期:2026-09-12
- 触发:用户「多 AI 会话同时执行迭代服务器项目,解决冲突」+ 当日 3 次实证事故(两通道并行改同一批文件致内容丢失;规划会话把已归档文件推回服务器制造"幽灵文件";T03 占位 2.5 小时未回填台账)
- 结论一句话:把"多会话并行"从「靠人记得」变成「靠工具判据」 —— 文档库留下 git 路标、服务器侧加显式操作锁、两级锁进预检脚本,冲突在动手前就能被判定。
- 状态:✅ 已完成(2026-09-12 15:10,
exec-session-C执行;单子交接单/T04已归档)
TL;DR|文档冲突靠
git status/mtime 还能看出来,服务器态变更看不出来(systemctl不会告诉你 10 分钟前谁重启过)→ 必须靠显式锁。本档记录这套机制的最终形态与验证证据。
一、问题(为什么必须做)
| 风险面 | 实证 | 原有防护 |
|---|---|---|
| 文档冲突 | 同日两次「两会话并行改同一批文件」造成内容丢失;编号 37/38 各被两份档案占用 | handoff-guard.sh 单级锁 + 全局锁(本档同日加) |
| 文档无路标 | 文档库此前长期不提交 —— 没有 commit 就无法用 merge 发现撞车 | 本档:commit 常态化 |
| 服务器态无互斥 | 重启 dshs 引发用户掉线(档案 58/59 两次报障);改实例 env / 批量铺插件同样无人知会 |
本档:服务器侧操作锁 |
| 代码侧无路标 | 服务器 /opt/dshs 有 13 项未提交、HEAD 停在 ebe8075(档案 56)→ 两小时改造只存在于磁盘,误 checkout 即丢 |
本档:代码库留路标 |
二、改动(四项,逐条可复现)
| # | 动作 | 落地物 |
|---|---|---|
| ① | 文档库 commit 常态化 | f14d4e1(收口:登记档案 57–68 + 6 处记账修正)、229a762(补提交积压 13 项)→ git status --short 0 项 |
| ② | 服务器侧第二把锁 | /opt/dsh/state/.op-lock/(root 700,内含使用约定 README);工具 scripts/op-lock.sh {claim|release|status};handoff-guard.sh 新增**【1d】**分支 |
| ③ | 权限统一 | /opt/dsh/docs/交接单 755 → 700;README.md/T01/T03/T04 → 600(对照 04-调整方案 = 700) |
| ④ | 服务器代码库留路标 | /opt/dshs:ebe8075 → 06e63ac(13 项逐条 add,禁 -A),status --short = 0 |
| ⑤ | 对账工具降噪(本轮副作用修复) | docs-sync-check.sh 的 find 增加 ! -path './交接单/.doing-*' ! -path './交接单/.exec-lock*' —— 此前只要有人持锁,对账就恒判「仅本地 ❌」(锁标记被当成内容差异);与 handoff-guard.sh【2】的过滤规则对齐 |
两级锁的分工(不要混用):
- 本机
.exec-lock(粗) = 同一时刻只允许一个执行会话动「文档 / 代码 / 服务器」; - 本机
.doing-<单>(细) = 这个单归谁做; - 服务器
.op-lock/<操作名>(生产态) = 谁正在动线上(跨机可见)。 - 顺序:先抢
.exec-lock→ 再占.op-lock;完工反序释放。
三、验证(命令 + 期望)
| 项 | 命令 | 结果 |
|---|---|---|
| 文档库路标 | git -C dsh-server-docs status --short |
空 ✅ |
| 锁脚本往返 | bash scripts/op-lock.sh claim t1 → status → release t1 |
占位成功 → 🔴 t1 + OWNER 详情 → 释放后「无人占用 ✓」 ✅ |
| guard 两态 | bash scripts/handoff-guard.sh(无锁 / 造锁) |
「✓ 无平台操作锁」/「⚠ 有会话正在动线上 + 🔴 + OWNER」并置 VERDICT=1 ✅ |
| 权限 | ssh bt-server 'stat -c "%a %n" /opt/dsh/docs/交接单 /opt/dsh/docs/交接单/*.md' |
700 + 四份 600 ✅ |
| 代码路标 | ssh bt-server 'git -C /opt/dshs log --oneline -1; git -C /opt/dshs status --short | wc -l' |
06e63ac / 0 ✅ |
| 文档审计 | python scripts/docs-audit.py |
退出码 0、无悬空引用 ✅ |
| 双端一致 | bash scripts/docs-sync-check.sh |
一致 122 / 不一致 0 / 仅本地 0 / 仅服务器 0 → ✅(含清掉锁标记造成的假 ❌) |
过程中修掉一个自身 bug:guard 【1d】初版用 ls | grep -v '^README$' 取结果,空结果时 grep 返回 1 → 被判成"服务器不可达(离线)"(假阴性:明明没锁却提示离线)。已改为远端 || true + __NOLOCKDIR__ 哨兵区分「无锁 / 目录缺失 / 不可达」三态。
四、红线遵守
- R7(禁批量写入):代码库 13 项逐条 add,未用
git add -A;未做任何 chown;未整目录覆盖。 - R8(中断在线用户须先知会):本单零重启、零停机 —— 只做 git 提交、建目录、
chmod、新增脚本。实测执行时服务器无在线实例(systemctl list-units "dsh-*.scope"为空)。 - 未 push:文档库与代码库均只做本机/服务器本地提交,推送仍待用户明确指令。
- 未改平台运行代码:本单零功能代码改动(只新增运维工具脚本)。
五、回滚
- 提交:
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。 - 锁:
rm -rf /opt/dsh/state/.op-lock+ 删scripts/op-lock.sh+ 去掉 guard 的【1d】段 +交接单/README §六改回"提案"。
六、遗留(未做,需另行决策)
- 交接单目录属主未统一 —— 目录与
README/T01/T03属主为197108:197121,只有T04是root:root。本单只授权chmod;chown属批量写(R7)→ 需单独确认。影响:700对该 uid 仍是可读的,未达成"真 root-only"。 - 本机代码镜像未同步 ——
D:\github\dsh_shenxianHEAD =0e141a4(含3567226)且自身有 10+ 项未提交 → 与服务器工作区双向分叉,merge --ff-only不可能。属"两仓内容取舍"决策,留待用户决定。 handoff-guard.sh未接 CI/cron —— 目前靠"开工前手动跑",未强制。- 服务器侧无操作审计 —— 本档只做互斥,不记录"谁在何时做了什么"。