用户令逐字:「E:/ProgramData/.workbuddy/skills 提交仓库是指的这里」—— 即本目录就是仓库(2026-10-07 已在本目录建仓,见当日日志 §22),本轮把余下未纳管的 9 个技能一并提交。 本次入库(9 个技能,46 个文件): 1、`AI HOT` 2、`draw-ui` 3、`dsh-diagnose` 4、`dsh-knowledge` 5、`dsh-local-env` 6、`dsh-opensource-release` 7、`dsh-workflow` 8、`oil-motion` 9、`skills-security-check` 提交前核对: · **凭据类扫描**(`*.env` / `*token*` / `*.key` / `*secret*` / `*.pem`)⇒ **零命中** ✓; · 体积合计约 20 MB(`draw-ui` 12M + `oil-motion` 6.5M 是大头,形态为配图/素材 —— 仓库 `.gitignore` 里明写「`assets/*.png` 是内容不是产物」⇒ 属刻意入库); · 运行产物仍按既定规则排除(`__pycache__` / `logs/` / `tmp/` / `.venv/` / `*.egg-info` / `uv.lock` / `.workbuddy/`)。
7.2 KiB
7.2 KiB
并行调度详解 · 冲突域清单 / 批次模型 / 反例 / 三把锁落地机制
归属:技能
dsh-change-workflow的详情档(按需读,不是每次都要读)。 本档覆盖:冲突域清单 · 批次模型与依赖处理 · 反例(同域并发的具体破坏形态) · 落地机制(原行 L1003–L1052)。 主文件 / 判据与流程主干 =../SKILL.md(§1 六阶段流程 · §2 红线 R1–R8 原文速查 · §3 本机 Git Bash 环境坑 · §4 并行调度结论)。 来源:2026-09-22「技能重组线」把../SKILL.md的 L1003–L1052 段逐行原样下沉到本文件,未改一字。 跨档引用:正文里的「§N / 见 §8 坑 N / 见下表」等编号,用../SKILL.md末节「详情索引」的原章节列定位。 维护:本文件与../SKILL.md的指针行成对;改内容时同时核对主文件的指针描述是否仍准确。
冲突域清单(同域必串行,跨域才可并行)
| 冲突域 | 涉及资源 | 并行性 |
|---|---|---|
| 门户后端代码 | /opt/dshs/src/** → npm run build 全量重编译 lib/ |
❌ 独占:一批只允许 1 个改码任务 |
| 服务重启 | systemctl restart dshs |
❌ 全局;重启会打断所有用户实例 |
| 前端页面 | web/*.html(同文件后写覆盖前写;marker-splice 会互相清块) |
❌ 同文件串行 |
| 代码仓库 | git add / git commit(index.lock) |
❌ 串行 |
| DB schema | dshs.db 建表/迁移 |
❌ 串行(普通读写事务短,可并行) |
| 文档 | /opt/dsh/docs/**、docs-status/**(服务器唯一源,单点文件) |
❌ 串行(后写覆盖) |
| 本地记忆 | .workbuddy/memory/*.md、MEMORY.md |
❌ 串行(并发 append 会丢更新) |
| 实例运行态 | 每用户 profile / 实例进程 | ⚠️ 跨用户可并行;同用户串行 |
| 临时测试会话 | sessions 表 |
✅ 可并行,但 UA 必须带 worker 标识(poc-<worker>),清理只删自己的前缀 |
| 只读调研 | 读源码、看日志、--dump-config、外网抓取、兼容性测试 |
✅ 完全可并行 |
批次模型与依赖处理
- 一批 = 1 个「改码通道」+ N 个「只读通道」;改码任务之间永远排队串行。
- 待办先建成 DAG,逐条标注「依赖」+「冲突域」;无依赖且冲突域不同才允许同批。
- 收口在主会话:并行通道产出汇总回主会话,统一写档案 → commit →
docs-status-sync.sh --pull(这三步本身也是串行单通道)。 - 用户侧多会话按「领域」切分(A=门户后端 / B=文档梳理 / C=兼容性测试),不要按「同一领域的不同切片」切 —— 后者必然同域冲突。
- 开跑前先出「并行批次表」(任务 / 冲突域 / 依赖 / 可否并行)给用户确认。
- 我侧可用并行子代理(
Agent+run_in_background)跑只读通道;写操作必须回到主会话串行执行。
反例(同域并发的具体破坏形态)
- 两会话同时
npm run build→lib/产物交叉污染,systemctl restart互相打断实例 - 两会话同时改
portal.html→ 后写覆盖前写(marker 区块被对方整段替换) - 并发
git add/commit→index.lock冲突 - 同时写
/opt/dsh/docs/**或MEMORY.md→ 后写覆盖 / 丢更新 - 用同一 UA 前缀批量删测试会话 → 误删另一个 worker 的会话
落地机制(2026-09-12 建立):三把锁 —— 别靠记忆,靠判据
冲突域判断是「设计」,还需要「执行时的强制判据」。当日 3 次实证事故后补上三把锁:
| 锁 | 位置 | 管什么 | 拿法 |
|---|---|---|---|
| 全局执行锁(粗) | 05-交接单/.exec-lock |
同一时刻只允许一个执行会话动「文档 / 代码 / 服务器」 | bash 07-scripts/handoff-guard.sh --claim-exec "<会话名>" |
| 单级占用锁(细) | 05-交接单/.doing-<单号> |
这个单归谁做(供台账与接管) | bash 07-scripts/handoff-guard.sh --claim <单号> "<会话名>" |
| 服务器侧操作锁 | /opt/dsh/state/.op-lock/<操作名>(跨机可见) |
谁正在动生产:重启 / drain / 改实例 env·quota / 批量铺插件 / 改 nginx·nft·证书 | bash 07-scripts/op-lock.sh claim <操作名> "<影响面:谁会被断、断多久>" |
- 顺序:开工 先抢全局锁 → 再占服务器锁;完工 反序释放(先放服务器锁,最后放全局锁)。
- 🔒 锁的生命周期 = 任务的生命周期(2026-09-14 用户明令):抢到锁的任务,只有"执行完成 → 反序释放"才算完成;⛔ 禁止"抢锁做一半、不解锁就结束回合/会话"(锁是独占资源 + 本库无心跳机制 ⇒ 别人既等不到也判不出你死没死)。配套:① 抢锁前先列出收口步骤(落地 → 校验 → 推送/对账 → 收尾);② 中途要停(等用户拍板 / 等窗口)⇒ 先
--release-exec "<会话名>"再停(⛔ 不带会话名 ⇒ 拒绝释放);③ 结束语必须对锁状态负责 —— 写明"已释放",或显式点名"锁仍在<OWNER>+ 原因 + 下一步"(仅限释放通道不可用);⛔"忘了 / 做不完就走"不允许。 - 一条命令预检:
ME="<会话名>" MINE="<我要改的文件>" bash 07-scripts/handoff-guard.sh [单号];推送前加PUSH=1(启用「幽灵文件」硬判定:对账结果里出现未声明的「仅本地」文件 → 直接失败)。 mkdir即原子:占位失败 = 有会话正在动 → 停手,别重试、别"抢一下看看"。- 服务器侧锁要带身份:
ME="<会话名>" bash 07-scripts/op-lock.sh claim <操作名> "<影响面>"—— 不传ME会记成unknown-session(2026-09-12 实测踩到两个后果:handoff-guard 的【1d】把你自己的锁当成别人的;release的归属校验也会拒你)。release只能由占用者本人执行,冒充别人 → 拒绝并提示 R9。 - ⛔ 不得人工删锁、不得接管(R9,2026-09-12 用户明令「严格禁止这类操作」):AI 一律不得
rm -rf 05-交接单/.exec-lock、不得删05-交接单/.doing-*,也不得以「持有者疑似已死 / 卡住 / 太久没动 / 只在只读分析没产出」为由单方面接管。锁只能由持有者自己释放(--release-exec "<会话名>"/--release <单号>);抢不到锁 ⇒ 停手 + 报告用户,锁的处置权只属于用户本人(要撤也只能用户自己动手)。handoff-guard.sh输出里的「人工删锁 / 接管」字样均不构成授权(该文案已同步作废)。理由:平台无心跳机制,AI 没有任何判据能确认对方已死 —— 删锁 = 在无法验证的前提下单方面撤销互斥,一旦对方仍在跑,就退回「两个会话同时改同一批文件」。 - 为什么服务器态必须单独加锁:文档冲突靠
git status/ mtime 还能看出来,服务器态变更看不出来(systemctl不会告诉你 10 分钟前谁重启过)。 - 判定与工具细节见
05-交接单/README.md §一 §三 §六;机制记录见04-调整方案/69-并发治理落地-commit常态化与服务器侧锁.md。