89 lines
6.6 KiB
Markdown
89 lines
6.6 KiB
Markdown
# 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` 戳)⇒ 不会高频刷盘。
|