Files
admin c1b5e4d966 chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次)
- .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…),
  目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪
- .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/)
- .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*)
- .gitignore 补:备份件(*.bak-*)
- 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

90 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# S12 体检刷新解锁 · 机制层最小修法 + 读数转 done
- **执行会话**:[协作]-[机制排查与修复]-S12解体检刷新(自动化 `b15bbc86`,12:05 一次性)
- **执行时间**:2026-10-03 12:06–12:15
- **域锁**:先抢 `ai1net-dsh-server/目标-本机协作-3e3182` 域锁;因落点属**机制层**(`session-mechanism/scripts/collabd.py`),按门禁**另抢全局独占执行锁**(两把均已释放)
- **改的文件**:`E:\ProgramData\.workbuddy\skills\session-mechanism\scripts\collabd.py`(备份 `collabd.py.bak-s12-health-20261003-120949`)
## 1. 一句话结论
✅ **真死锁已解**:体检报告从 `2026-10-02 20:50:22` 刷新到 `2026-10-03 12:10:13`,结果 `✅ 通过`;S12 两条判据**均以真读数通过**(非模拟)⇒ 任务图 S12 由 `await-verify` 转 `done`。
## 2. ⛔ 提示词的前提经实测**不成立**(这一条改变了修法)
原判:「任何会话来跑 `--once`,都会把自己算进 `health()` 的 `busy` 判定 ⇒ 永远早退」。
**实测(探针读数,`tmp/s12probe.py`)**:
1. `SELF_SID` = `e0fc9822-…`(本会话)**已被正确排除** —— `d["self_working"] = True`,
而 `d["working"]` 里**只有 `a80f300d`,没有自己**。
⇒ 排除逻辑在 `fetch()` 第 495–497 行**本来就生效**,「自己算进 busy」这个自锁**不存在**。
2. 真正让 `V["busy"]` 为真的是**另一个会话 `a80f300d`「分析定时任务创建会话机制」**,
且它**真在执行**:状态机日志末条 `12:04:31 busy=true`(3.9 分钟前),`_target_busy()=True`。
3. 节流**不是**原因:`health_at` 年龄 ≈ 17.2 h ≫ `health_every=300` ⇒ 若不 busy 本轮就会落盘。
⇒ 结论:**「排除调用方自身」这条修法解不开问题**(已经生效了);「等一个没会话的窗口」不可靠
(本工作区常驻协作会话长期活着,实测 4259 条状态机记录持续 `busy=true`)。必须改的是**早退本身**。
## 3. 结构性病根(读源码非推断)
`sessions.status` 取值域只有 `working / completed / error / archived` ——
**⛔ 没有「空闲」这一档**(`collabd.py` 1861–1882 行已实测记录:活着的会话跑完一轮、停在等下一轮时,
`status` 仍是 `working`)。
⇒ `busy_(d) = bool(d["locks"]) or bool(d["working"])` **只要工作区里存在任意一条活会话就恒为真**
⇒ `health()` 第 727–729 行 `if V["busy"]: return out` 每轮都早退
⇒ 体检报告永不刷新(实测跨 15.5 小时未动)
⇒ 依赖「体检报告确认」的验收判据(**S12 第二条**)永远无法过 ⇒ 这是**真死锁**,不是「等窗口」能解决的时序问题。
## 4. 修法(最小、⛔ 不动判据本身)
1. **`health()` 去掉 `busy` 早退**:`out = {"skipped": False, …}`,⛔ 删掉 `if V["busy"]: return out`。
- ⛔ **判据一条未动**:哑火 / 延迟(补跑)/ 关键件缺失 / 锁摩擦 / 并发 `IN_PROGRESS` 五项判据全部原样。
- 改的只是「**什么时候执行体检**」,⛔ 不是放宽判据。
2. **并发安全改由原子替换写盘保证**:临时文件 `体检报告.md.tmp` + `os.replace`(同目录、同卷 ⇒ 原子)。
- 理由:去掉早退后体检会在别的会话运行时也写,⛔ 不能再靠「忙时别写」这种时序运气躲半截文件。
- 与本机既有铁律一致(多进程共用小状态文件优先「原子替换 + 回读核对」,⛔ 别先上文件锁)。
3. **报告新增一行「执行时机」**:`有会话在跑也照跑(2026-10-03 起;⛔ 不再因 busy 早退)` / `空闲`
—— 让读报告的人**一眼看出这份是不是空闲窗口跑的**,⛔ 不让判据失去可追溯性。
## 5. 两条判据的真读数(`tmp/s12verify2.py` / `tmp/s12verify3.py`,只读 `mode=ro`)
### 5.1 判据一(计数):`deleted_at IS NULL ∧ ACTIVE ∧ once ∧ next_run_at IS NULL`
现读数 = **4**(期望 0)。逐条核 `created_at` ⇒ **4 条全部晚于清理动作(10-02 22:30)= 清理后新建**,
⛔ 不在 S12 清理范围,本轮不处置:
1. `b6ce8822` created 10-02 23:41:16「v1原型重跑-③段」
2. `99f803b0` created 10-02 23:47:12「[跟进]-队列上报(固定席位·不分类别)」
3. `056c427a` created 10-02 23:47:31「[协作]-③段-v1原型重跑」
4. `8305da51` created 10-03 11:50:50「[检查]-[目标检查]-ai1net-dsh-server-第3棒」(本棒自己那条)
**目标 9 条逐条回读四元组 = 9/9 全 `(PAUSED, once, None, None)`** ✅
(`3872e203` / `45d4e2d4` / `4e7b8401` / `5c77eedc` / `5e335e01` / `73f138ce` / `9a06e9b8` / `9ec39dac` / `a2982f2e`)
参照 `87d55715`(S7)= `(PAUSED, once, 1790909520000, None)` ✅
`PRAGMA integrity_check` = **ok**;周期排期 ACTIVE **3**(=基线,未误伤);总行数 150(141→150 增的是清理后新建排期,⛔ 不是删了又补)。
### 5.2 判据二(状态):**体检报告**(本轮真刷新,⛔ 非模拟)
- mtime = **2026-10-03 12:10:13**(改前 2026-10-02 20:50:22)
- 结果行 = `## 结果:✅ 通过`,issues = **无异常**
- notes(补跑 · ⛔ 不是哑火)3 条:`b6ce8822` 延迟 19 分钟 / `99f803b0` 延迟 17 分钟 / `056c427a` 延迟 24 分钟
- **10 个 id(目标 9 条 + `87d55715`)逐个 grep 报告全文 = 全部不出现** ✅
- 旧报告里那条红项 `5e335e01`(曾被列为哑火)**在新报告中不再出现** ✅
- 结构性旁证(读源码):`fetch()` 候选 SQL 为 `where status='ACTIVE'` ⇒ `PAUSED` 行在数据源层就进不了
`d["due"]` ⇒ 结构上不可能出现在 issues/notes(与实测一致)
## 6. 本轮未做 / 未碰
- ⛔ 未改任何排期状态(全程只读 `mode=ro`),⛔ 未用 `automation_update`
- ⛔ 未碰 `a80f300d`(宿主在跑的会话:⛔ 不 load、不改配置、不抢 `writer_occupied`)
- ⛔ 未手改 `queue.json` / `queue.md` / `NEXT.md`(collabd 派生产物)
- ⛔ 未做文件级 `cp` / `mv` 碰 `workbuddy.db`(WAL 三件套铁律)
- 任务图 `交付物/任务图-会话协作自检.json` 在域目录外,但本棒持有**全局独占执行锁** ⇒ 合规改动,非硬闯
## 7. 判读这条修法时要注意的两点
1. **不是「放宽判据」**:判据(五项)一字未改,改的是执行时机。报告里显式写明执行时机,读者可判断可信度。
2. **副作用(已知、可接受)**:体检现在会在有会话运行时写 `体检报告.md`。落盘走 `os.replace` 原子替换,
⛔ 不会出现半截文件;且 `health_every=300` 的节流**仍在**(`health_at` 戳)⇒ 不会高频刷盘。