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/ 知识文件,按口径入库)
This commit is contained in:
admin committed 2026-10-10 23:13:22 +08:00
1 parent 30b46dbd0c
commit c1b5e4d966
735 files changed
+153192 -2415

No files matched your search

@@ -0,0 +1,89 @@
# 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` 戳)⇒ 不会高频刷盘。
@@ -0,0 +1,104 @@
# S12 收尾核对(await-verify → 判定)· 2026-10-03
- **执行会话**:`[协作]-[机制排查与修复]-S12 收尾核对转 done`
- **执行时间**:2026-10-03 11:14–11:2x
- **域锁**:`ai1net-dsh-server/目标-本机协作-3e3182`(已抢到,收尾已释放)
- **一句话结论**:⚠️ **状态判据本轮判不出来** —— 真体检**又被跳过**(原因=`busy`,**不是**节流);
节点 **S12 维持 `await-verify`**,⛔ 未标 done。
## 1. 结论为什么不是 done(先说卡在哪一条)
- 节点 S12 的第二条判据是「**下一次真体检**的 `体检报告.md` 里,那 9 条 id 不出现在 notes/issues 段」。
- 本轮现跑了 `collabd.py --once`(⛔ 未带 `--supervise`),命令 **rc=0**,但落盘文件
`tmp/supervise-inbox/体检报告.md` 的 **mtime 仍是 `2026-10-02 20:50:22`** —— **内容没被刷新**。
- ⇒ **本轮没有新的体检读数**。而磁盘上那份是**清理动作之前**(20:50 早于 22:0x)的旧读数,
它**仍然把 `5e335e01` 列在 issues 段**、把另外 8 条列在 notes 段。
- ⇒ 现在若把节点标 done,等于**与磁盘上那份报告直接矛盾**。按判据纪律 ⇒ **不标 done**。
## 2. 跳过原因=`busy`(**不是** 300 s 节流戳)
判据来自 `collabd.py::health()` 第 727–729 行:`out = {"skipped": V["busy"], ...}` + `if V["busy"]: return out`
—— 只要 `busy` 为真就直接早退,**连节流判断都走不到**。本轮把两个因子分别实测:
- **`V.busy` = `True`**(实测打印)。根因=`fetch()` 取到 **1 条 working 会话**:
`a80f300d-bdca-41a0-a17d-edda4fffcb77`「分析定时任务创建会话机制」(cwd 命中本工作区)。
辅助读数:`busy_(d)=True`、`_all_sessions_idle()=False`。
- **节流戳不是原因**:`state.health_at = 1790935400.37`,年龄 **61,945 s ≈ 17.2 h**,
远大于 `health_every = 300` ⇒ 若 `busy` 为假,**这一轮就会落盘**。
⇒ 结论:**只要还有任一 working 会话,体检就恒被跳过**。这与 S12 报告 §7.2 预判的病灶同源,
但**真因是 `busy`(不是「本自动化会话在跑」本身)** —— 本轮实测是**另一条** working 会话顶上的。
⛔ 本轮**未处置**该 working 会话:按本机铁律,⛔ 不得对宿主在跑的会话做 `load`/接管、改其配置或进程。
## 3. 计数判据:9 条逐条现读(全部保持停用,⛔ 无回归)
直连只读(`mode=ro` + `busy_timeout=10000`)逐条回读四元组,**9/9 全为 `('PAUSED','once',None,None)`**:
- `a50a1791`[协作]-[会话协作自检]-S6 建齐三类会话
- `3872e203`[协作]-[机制排查与修复]-S5 修主会话可响应
- `73f138ce`[协作]-[机制排查与修复]-S8 常驻投递载体(重派·锁已清)
- `5c77eedc`[协作]-[机制排查与修复]-S9 投递目标忙判据复核与放行验证
- `9ec39dac`[协作]-[机制排查与修复]-S9 投递目标忙判据(含 S8 常驻复核)
- `5e335e01`[协作]-[机制排查与修复]-哑火判据与排期清理
- `4e7b8401`[协作]-[机制排查与修复]-投递链路真因接续
- `a2982f2e`[协作]-[机制排查与修复]-清理跑完的一次性排期
- `9a06e9b8`[跟进]-机制排查与修复-队列跟进
⚠️ 另核一条**旧报告里出现过、但不在本次 9 条清单内**的 id:`87d55715`(S7 全量验收 V1–V7)——
现读数同为 `PAUSED`,也**不在**任何 ACTIVE 集合里。
- **`PRAGMA integrity_check` = `ok`**(只读跑,未做任何写操作)
- **总行数 148**(S12 清理当时是 141 ⇒ 增的 7 行是清理之后新建的排期,⛔ 不是"删了又补")
## 4. 关于「计数从 0 变成 4」——不是回归,是新增
判据 `ONCE_ACTIVE_NO_NEXT`(`deleted_at IS NULL ∧ status='ACTIVE' ∧ schedule_type='once' ∧ next_run_at IS NULL`)
现读数 = **4**(S12 清理后当时读数是 0)。逐条查 `created_at`,**4 条全部晚于清理动作时刻**:
1. `b6ce8822` v1原型重跑-③段 —— 建于 **2026-10-02 23:41:16**
2. `99f803b0` [跟进]-队列上报(固定席位·不分类别)—— 建于 **2026-10-02 23:47:12**
3. `056c427a` [协作]-③段-v1原型重跑 —— 建于 **2026-10-02 23:47:31**
4. `00bf17bd` [协作]-[目标检查]-ai1net-dsh-server-第2棒 —— 建于 **2026-10-03 11:06:03**
⇒ 结论:**S12 那 9 条一条都没复活**;这 4 条是清理之后由后续工作新建的排期(其中第 4 条就是本轮目标检查排期),
**不属于 S12 的清理范围**,⛔ 本轮不处置(那是「跑完之后再清」的新一轮,不是回归)。
## 5. 只读模拟(⛔ 仅作旁证,**不当作过**)
为确认「一旦不 busy 会不会翻红」,在**内存里**把 `V["busy"]` 置 `False` 跑了一次 `health()`,**⛔ 未落盘、未改任何库**:
- `issues` = **`[]`**(空)
- `notes` = 3 条,全部是**新排期**:`b6ce8822`(延迟 19 分钟跑完)、`99f803b0`(17 分钟)、`056c427a`(24 分钟)
- 目标 9 条 + `87d55715` 共 10 个 id:**逐条「不在候选集」** ✅
结构性原因(读源码确认,非推断):`fetch()` 第 466–467 行的候选 SQL 是
`where status='ACTIVE' and (deleted_at is null or deleted_at='')` ⇒ **`PAUSED` 的行在数据源层就进不了 `d["due"]`**,
因此它们**不可能**出现在 `issues`/`notes` 任何一段。
⚠️ **但这仍不算判据过**:判据原文要求「**体检报告**确认」,而磁盘上那份报告**没被刷新**。
模拟是旁证,⛔ 不替代真读数(否则就成了"自己判自己过")。
## 6. 节点处置与解锁条件
- **S12 维持 `status = await-verify`**,⛔ 未标 done、未退 `todo`(活本身干完了,只是**门禁读数**没拿到)。
- **解锁只需要一件事**:在**无 working 会话**的窗口跑一次 `collabd.py --once`
(判据:`V.busy=False` ∧ `_all_sessions_idle()=True`),让 `体检报告.md` 真正刷新。
届时若 `issues`/`notes` 不含那 9 条 ⇒ 直接置 done(第一条判据与第四条模拟读数均已就位)。
- ⛔ 本轮**未改** `collabd.py`、⛔ 未改任何排期状态、⛔ 未碰 `queue.json`/`queue.md`/`NEXT.md`(派生产物)。
## 7. 台账同步
- `tasks.json` 的 `S12` **本来就已是 `done`**(由 `[主会话]-记录常驻起法` 于 10-02 写入,artifact 指向清理报告)。
本轮**沿用 `done`** —— 台账语义是「活干完了吗」(活确实干完,9/9 现读为 PAUSED);
更严的「读数门禁」由**任务图节点的 `await-verify`** 承担。两者**分工不同,不是矛盾**。
- 本轮**只更新 artifact 指针**指向这份核对报告(⛔ 按机制硬约束带 `--artifact`,缺了会被 rc=3 拒收)。
## 8. 结论(给检查会话读)
- 目标「检查会话协作是否运行正常 + 协作机制问题排查与修复」**仍不可改成已完成** ——
任务图仍有 1 个 `status != done` 的节点(S12=`await-verify`),按 `目标执行状态.md §一.3` 三路取并集,
**任一路没完就是没完**。
- ⛔ 本轮**未替检查会话**改「目标生命周期」(那是检查会话的职责)。
(报告完 · 域锁已释放)
@@ -0,0 +1,142 @@
# 目标执行状态
> 🔴 **本文件=检查会话判断目标状态的唯一依据**(用户 2026-10-03 10:5x 要求逐字:
> 「目标执行情况也要有文档,这样检查会话**直接根据文档判断目标状态**,避免检查会话到处找信息」)。
> ⛔ 检查会话**不许再去工作区里翻文件**找目标状态 —— 读本文件 + `tasks.json` 就够了。
- **目标标题**:检查会话协作是否运行正常 + 协作机制问题排查与修复
- **目标简称**:本机协作
- **目标生命周期**:**已完成**(2026-10-03 12:18 由 `[检查]-[目标检查]-ai1net-dsh-server-第4棒` 判定并写入)
- **本文件由谁更新**:**目标检查会话**(`[检查]-[目标检查]-…`)在核对完成后改「目标生命周期」并更新本文档
- **最后实测时间**:2026-10-03 12:18(所有读数均为**现测**,⛔ 不是转述)
## 一、怎么用这份文档(检查会话照此判断,别自己另立口径)
1. 先读 `tmp/supervise-inbox/tasks.json`(队列四态台账)—— 那是「活干完了吗」。
2. 再读**本文档** —— 那是「目标达成了吗」。
3. **⛔ 两者都不许跳**。三路取并集,**任一路"没完"就是没完**:
- 台账里有 `pending`/`running`/`blocked` 的件;
- 任务图(`交付物/任务图-会话协作自检.json`)里还有 `status != done` 的节点;
- **本文档第二节里还有任何一条判据没过**。
4. 全部满足 ⇒ 才可把目标生命周期改成「已完成」,并在本文档把「结论」那一行更新掉。
## 二、验收判据(逐条,⛔ 判据值是中文写法:`过|…`/`🔴 不过|…`)
### V1 协作程序常驻一直运行
- **结论:过**
- **实测**:`supervise-heartbeat.json` → `pid=38988`、`round` 持续上涨(10 s/轮)、`ts_h=2026-10-03 10:35:21`。
- **判据**:pid 活 **∧** 心跳新鲜(<90 s)—— 与 `selftest.py::t_supervise_ensure` 同一口径。
### V2 队列与检查会话链路
- **结论:过**
- **实测**:`tasks.json` 读数 `S5=done(带 artifact)`、`S12=done(带 artifact)`;
`queue_pending()=0`(真源 `tasks.json` 四态口径);闸②`_all_sessions_idle()=True`、闸④`ws_pending_schedules()=[]`、闸③ 走 `queue-empty`。
- ⚠️ **旧判据「跟进会话链接得住(零条活着 / 今日投递成功 0 次)」已作废** —— 唤醒/跟进/队列投递
**整套退役**(用户 2026-10-03 定案),那条判据**永远不可能满足**。⇒ 本条改为校验**现行链路**。
### V3 协作会话在台账里留有产物文档
- **结论:过**
- **实测**:`S5.artifact` 指向 `references/architecture.md §2.3.0f`;`S12.artifact` 指向 `机制排查与修复/S12_清理报告_20261002.md`。
- **判据**:每条 `done` **必须**有 `artifact`。⇒ 机制侧已加硬约束:`--report --state done` **缺 `--artifact` 直接拒收(rc=3)**。
### V4 看板可服务
- **结论:过**
- **实测**:`netstat` → `127.0.0.1:8788` **LISTENING**(pid 41764);`/board.json` → HTTP 200、`ts=2026-10-03 10:52:35`。
- **判据**:能起得来 + 回环 HTTP 200(⛔ 不看页面像不像,看接口读数)。
### V5 机制自测全绿
- **结论:过**
- **实测**:`selftest.py` → **PASS 55 / FAIL 0**。
- ⚠️ **基线是 FAIL 1**(`技能侧零项目串` 那条,已于 2026-10-03 上午修掉:域键锚点词表三处对齐 + 结构性豁免)。
⇒ 判据写成「**FAIL 0**」,⛔ 不写「与基线持平」—— 那种写法会让真红也通过。
### V6 协作程序格能显示"检查程序在运行"
- **结论:过**
- **实测**:`/board.json` → `runtime.check = {"n":0,"label":"无检查在跑"}`。
**端到端验过**:临时把一条检查会话置 `working` ⇒ 线上 `runtime.check.n=1`、`label=有结果检查在运行`;还原后回 `n=0`。
- **判据**:`runtime.check` 字段在位 + 与真库 `working` 检查会话数**一致**(不许恒绿)。
- ⚠️ **旧判据「跟进会话角色落地(名册 11 条)」已作废** —— 跟进会话整套退役。
### V7 检查会话按规范命名、且**不进协作会话区**
- **结论:过**
- ⚠️ **本条已于 2026-10-03 11:1x 重写** —— 上一版写的是「按 `[协作]-[…]` 命名、判 `worker`、画进协作会话区」,
**已被用户明确纠正**(逐字:「检查会话不是协作会话,不应该出现在看板协作会话区域中;
它属于协作程序的会话,可以放在协作程序框图中展示」)⇒ 旧写法**作废**。
- **实测(现行口径)**:
- 排期名=**`[检查]-[结果检查]-<工作区>-第N棒`**(角色词是 `检查`,⛔ 不是 `协作`;第二段仍带方括号)。
- `parse_session_name()` ⇒ **`role=check / topic=结果检查 / ok=True`**;旧式光杆名(`结果检查-…`)也判 `check`。
- `is_main_side_session()` ⇒ **False**(⛔ 不算主侧 ⇒ 不进协作会话那一排)。
- 线上 `/board.json`:**`sessions_checks` 里有它、`role=检查会话`**;协作会话区域**不含**它。
- **判据**:`role=check` + `topic` 非空 + **两侧解析零漂移** +
⛔ 协作会话排的判据**显式排除**检查会话(前端也挡一次)。
- ⚠️ **旧判据「开工建齐三类(唤醒/协作/跟进)」已作废** —— 会话类别已收敛(主会话/协作会话/**检查会话**)。
### V8 协作程序在线状态读数**不是假读数**
- **结论:过**
- **实测(线上 `/board.json`)**:`runtime.prog.label=在线`、`up=true`、
`by=常驻 --supervise(round N)`、`heartbeat_age_min≈0.1`、`heartbeat_pid=48896`;
旧退役戳 `legacy_tick_age_min≈861.6` **单列且不参与判定**。
- **判据**:判据**读常驻心跳**(`logs/supervise-heartbeat.json`),
⛔ **不读** `_tick.stamp`/`collabd-once.stamp`(已退役投递机制的遗留,实测停在 2026-10-02 21:24)。
- ⚠️ **四态文案必须分清**(2026-10-03 11:35x 用户报障「已 849.6 分钟没轮」后确立):
**在线** / **已停·进程不在**(pid 没了)/ **没轮(进程还在)**(活着但卡住)/
**心跳读不到·判据已降级**(⛔ 不提进程 —— 提了就是编)。
- ⚠️ **本机实况**:后台进程**活不过工具调用边界** ⇒ 长期载体必须是**会话后台任务**;
`Popen(DETACHED|NO_WINDOW)` 起的常驻实测**约 2 分钟就被回收**。
## 三、结论
- **8 条判据全部通过** ⇒ 目标「检查会话协作是否运行正常」这一部分**已经达成**。
- ✅ **2026-10-03 12:15 更新:任务图 12 个节点现已全部 `done`** —— 最后一个卡住的 `S12`
(`await-verify`)已由 `[协作]-[机制排查与修复]-S12解体检刷新` 以**真读数**转 `done`。
当时阻塞它的是**机制层真死锁**:`health()` 因 `busy` 早退 ⇒ 体检报告 mtime 停在 10-02 20:50:22
⇒ 判据第二条「体检报告确认」永远无法过。修法见 `S12_体检刷新解锁_20261003.md`。
- ✅✅ **2026-10-03 12:18 终判:目标生命周期 =「已完成」**(`[检查]-[目标检查]-ai1net-dsh-server-第4棒`)。
三路取并集**无一路「没完」**:
1. **台账 `tasks.json`**:S5/S12 均 `done` 且各带 `artifact` ⇒ 无 pending/running/blocked(**零僵尸件**)。
2. **任务图**:12 个节点全部 `status=done`(含最后一个卡住的 S12)。
3. **本文档 V1–V8**:全部「过」。
本棒**按 §一 的要求重跑了一遍 V1–V8**(⛔ 未沿用 10:52 的旧读数),现读数:
- **V1 过** —— 心跳 `pid=36868`、两次采样 `round 90→92`(10 s/轮)、`ts_h=12:18:25`(<90 s);
进程表 `Win32_Process` 独立佐证 pid 36868 **在**(起 2026-10-03 12:03:13,命令行=`collabd.py --supervise`)。
⚠️ **踩坑留档(P0-22 同族)**:先用「`OpenProcess` + `WaitForSingleObject`」判存活**读出 `DEAD`(假阴性)**,
与心跳新鲜**自相矛盾** ⇒ 改用进程表交叉验才定案。**判据冲突时必须找第二路,否则会把「判据假红」当成「机制真死」**。
- **V2 过** —— 同上(台账两件 done 带 artifact)。
- **V3 过** —— S5/S12 的 `artifact` 均非空。
- **V4 过** —— `netstat` → `127.0.0.1:8788` LISTENING(pid 7236);`/board.json` → HTTP 200(1.6 ms)。
- **V5 过** —— `selftest.py` → **PASS 60 / FAIL 0**(rc=0)⇒ 判据是「FAIL 0」,达标。
- **V6 过** —— `/board.json` → `runtime.check = {"n":1,"kinds":["目标检查"],"label":"有目标检查在运行"}`
(`n=1` **不是恒绿**:`n` 跟真库 `working` 检查会话数一致,此刻正是本棒自己在跑)。
- **V7 过** —— `sessions_checks` 现读 **3 条**检查会话,标题分别为
`[检查]-[目标检查]-ai1net-dsh-server-第3棒`/`第2棒`/`结果检查-ai1net-dsh-server-第1棒`,
`role=检查会话`(⛔ 不是 `协作会话`)⇒ 走检查会话区、**不进协作会话那一排**。
- **V8 过** —— `runtime.prog`:`label=在线`、`up=true`、`by=常驻 --supervise(round 89)`、
`heartbeat_age_min≈0.17`、`heartbeat_pid=36868`;旧退役戳 `legacy_tick_age_min≈893.5` **单列不参与判定**。
⇒ 故 `goal.json.acceptance_state` 的机读副本**保持 V1–V8 全「过|过」**(与本文档一致,无需改动),
并已回读确认 `lifecycle=已完成`(`lifecycle_at=2026-10-03T12:18:51`)。
- 🔴 **后续口径(不阻塞本目标)**:目标已标「已完成」后,本检查排期**不再有可派集合**
⇒ 无需再按本目标派协作棒;若日后出现新的「协作机制问题排查与修复」诉求,
**重新 declare 一个目标**(`goalctl.py declare --title … --topics … --yes`)再起排期,⛔ 别复用本目标。
## 四、旧判据的作废清单(⛔ 别再拿它们判)
| 旧判据 | 作废原因 |
|---|---|
| V2-跟进会话链接得住(零条活着/今日投递成功 0 次) | 唤醒/跟进/队列投递**整套退役**,永远不可能满足 |
| V6-跟进会话角色落地(名册 11 条) | 同上 |
| V7-开工建齐三类会话(唤醒/协作/跟进) | 会话类别已收敛为主/协作/**检查** |
| V7-旧版:检查会话按 `[协作]-` 命名、判 `worker`、进协作会话区 | 2026-10-03 11:1x **用户纠正**(逐字见上)⇒ 改 `[检查]` + `role=check` + 画进协作程序框 |
| 协作程序状态=「已 N 分钟没轮」(单一判据读 `_tick.stamp`) | 2026-10-03 11:35x 实测:那两个戳 **10-02 后无人写** ⇒ 报"849 分钟"=假读数 ⇒ 改读常驻心跳 + 四态 |
⚠️ 本清单**不是为了好看** —— 留着它们,目标状态就**永远判不出来**(同族红线:
「一条判据都没有 ⇒ 判不出来,⛔ 不许当成已完成」的反面:**有一条永远红的 ⇒ 也不许当成未完成**)。
@@ -0,0 +1,172 @@
==================================================================
协作机制 · 回归自测(每改一次必跑) 测试工作区:E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest
协作机制 · 回归自测(每改一次必跑) 测试工作区:E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest
==================================================================
✓ 命名:两级前缀解析(合规 / 缺级 / 接续会话 / 主控前缀) (9 项)
✓ 命名:看板与常驻程序**同一套角色判据**(⛔ 防两处漂移 —— 漂了就没人能发现换主会话) (8 项)
✓ 目标:无目标 ⇒ 拒绝启动 rc=3 (2 项)
✓ 目标:有待确认 ⇒ 拒绝启动 rc=4;--propose/--confirm 能走通 (2 项)
✓ 目标三态:『没有判据』⛔ 不等于『全过』(防『读不到被当成已完成』) (7 项)
✓ 验收判据认**真源的中文写法**(⛔ 别只喂英文 `pass` —— 那等于判据恒绿) (41 项)
✓ 两类检查会话是**两件事**:prompt 必须不同 + 闸④「本项目无待执行排期」 (18 项)
✓ 🔴🔴 闸⑥ 同类检查冷却期:两种情况 × 每类最多一条 ⇒ 不堆积(用户「不该有任何堆积」) (4 项)
✓ 检查会话的 prompt:**引用的命令必须真存在**(⛔ 引用不存在的命令 ⇒ 静默当成功) (7 项)
✓ 台账四态:running → blocked(带原因) → 解除后原因清掉 (3 项)
✓ 已停总闸:goal.run=paused ⇒ --once 只写一行、⛔ 不产告警(防『人为停掉被读成机制坏了』) (6 项)
✓ 投递:常驻程序(--once / --report)**零投递** (1 项)
✓ 投递:目标会话(**跟进会话**)在跑 ⇒ 必须延后(target-busy) (2 项)
✓ 投递:错名修复 —— `why` 透传(有候选但不活 ⇒ follow-not-live,⛔ 不再记 no-follow-session) (4 项)
✓ 投递:粗判第一条候选已哑、同类别另有活候选 ⇒ ⛔ 不许终局判 target-deaf(修『走不到精确重算』) (2 项)
✓ 投递:跨进程互斥锁存在且会被释放 (2 项)
✓ 投递:锁被**别的进程**持有时 ⇒ ⛔ 不投(`locked`) (1 项)
✓ 哑会话:诊断日志 ≥ 9.5 MiB ⇒ _deaf_sids() 判哑(只读 · 判据=读数、含边界) (4 项)
✓ 哑会话:投递命中已哑目标 ⇒ skipped=target-deaf(⛔ 不投 + 喊用户;⛔ 不记假绿) (2 项)
✓ 哑会话:**只认最新一天** —— 昨天撞过上限、今天已正常轮转 ⇒ ⛔ 不判哑(修『永久判哑』) (5 项)
✓ 投递(新):纯投影 --once ⛔ 不消费队列 (3 项)
✓ 投递(新):投不出去(no-token)⇒ ⛔ 不消费队列(防静默丢件) (4 项)
✓ 宿主卡住探针:只读尾部、测试环境零命中、⛔ 不误报 (6 项)
✓ 投递消费回查:投出去 ≠ 跑起来了 ⇒ 未消费必须升级为 NEED-USER (4 项)
✓ need_user:同句节流(⛔ 不每轮刷时间戳)+ 人写的「## 解除条件」两路都必须原样保留 (4 项)
✓ 投递忙判据:读宿主状态机日志的 busy=(⛔ 不再用 `status=='working'` 那档恒真的判据) (17 项)
✓ 🔴 `--tick` 已删:参数表/分支/钩子调用**三处皆无**,且投递段仍真删 (7 项)
✓ 对账:僵尸(台账 running 但没人跑)⇒ 标 blocked (1 项)
✓ 对账:幂等(连跑两次结论一致) (2 项)
✓ CLI:未知参数 ⇒ rc=2 且**不落常驻** (2 项)
✓ CLI:--where / --reqs 可跑且 rc=0 (2 项)
✓ 结构:关键名字/设施在位(防『误删常量』重演) (1 项)
✓ 结构:所有 subprocess 调用都带 creationflags(不显窗) (1 项)
✓ 结构:fatal 不再 exit 0(防『假绿』) (2 项)
✓ 结构:投递段**已真删**(⛔ 旧「投递方唯一」判据已于 2026-10-03 退役) (6 项)
✓ 主会话:**解析出来的**(不只是读登记)+ ⛔ 拒绝盲投(防『投错窗口』回潮) (26 项)
✓ 主会话:看板与投递**同一套判据**(⛔ 防两处漂移 —— 漂了就没人能发现换主会话) (2 项)
✓ 主会话:**退役角色不许当候选** —— 行为级(真造宿主库 + 真跑扫描,⛔ 不只测那个小函数) (5 项)
✓ 主会话:登记为 main 但**已哑** ⇒ ⛔ 不认它 + `--declare main` 是**换**不是「加」 (6 项)
✓ 结构:守护生命周期(优雅退出设施在位) (3 项)
✓ 归属判据:看板 ≡ 收尾确认(⛔ 防两处漂移;⛔ 不按 cwd 推断) (2 项)
✓ 看板:风格系统(三风格令牌在位 + 组件里零硬编码色) (2 项)
✓ 看板:验收摘要行 ⛔ 不许把『一条判据都没有』说成『无』(同族红线) (4 项)
✓ 看板:『未归类』不许被静默丢掉(同族红线:读到了就要说) (4 项)
✓ 看板:**同工作区但没归入本项目**的会话不许静默丢(⛔ 也不许把它算进本项目) (4 项)
✓ 归属:两处 `in_project` 判据**逐样本对账**(⛔ 漂了就静默漏管) (6 项)
✓ 会话退场:过期会话**收起但不删除**,且 ⛔ 不吃掉在跑的棒与主会话 (13 项)
✓ 看板:任务类别**来源**必须说得出口(declared / fallback) (6 项)
✓ 看板:多目标 tab(一格一个目标 ⇒ ⛔ 不是各画一份叠着) (28 项)
✓ 动手层:三条开工动作在位 + **判据不许恒红**(⛔ 恒红 = 没有判据) (10 项)
========================================================================
判据元体检 · E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\judge_probe.py
========================================================================
⚠️ 命中 2 处(⛔ 这些是**可疑写法**,⛔ 不等于一定是错):
🔴 self-recompute [self] 行 [1]
↳ 判据里用 `lambda` **自己重算**被检的算法 ⇒ 改被检对象它照样绿(今天 V4)
🔴 anchor-text-only [weak] 行 [2]
↳ 锚在「源码/文本里出现过某词」⇒ ⛔ 证明不了行为(今天 V6;判据元规则之一)
处置:逐条改判据(⛔ 别改规则表消警告 —— 那是把体温计砸了)
ⓘ 确认是误报就加进 `FALSE_POSITIVE`(⛔ 但要写清为什么,⛔ 不许默默加)
✓ 判据元体检工具在位 + 它的**元规则**也不是摆设(⛔ 防「靠记得」) (10 项)
✓ 红线 S:⛔ 严禁把「被监控对象所在工作区」当成「目标归属工作区」+ 归属核对进 env_check (13 项)
✓ 红线:⛔ 严禁用「排期/自动任务」当常驻载体 + 环境检查必须查工作区部署 (11 项)
✓ 沉淀纪律:**经验不许写成流水账**(体量有上限 + 判据要点不许丢) (5 项)
✓ 看板:版面纪律(小字描述只进 ?;指定删除的三处不得回来) (3 项)
✓ 技能侧零项目串(「技能就是技能,谁用产生的文件放在他自己那里」) (4 项)
✓ 常驻:存活判据=『pid 活 ∧ 心跳新鲜』+ 自愈接线在 + ⛔ 两条不起闸 (11 项)
✓ 元:本测试不碰生产(判据=**测试独有的痕迹**,⛔ 不拿「文件被写过」当证据) (2 项)
✓ 闸②:判『所有会话都结束』=与看板同款(status=='working')+排除观察者自己 (6 项)
✓ 检查会话:排期名**按两级前缀**(⛔ 否则看板认不出它是任务会话)+ 看板有『检查程序在跑』读数 (6 项)
✓ 检查会话:board ⇄ collabd 两侧解析**逐样本对账**(⛔ 这两侧已漂过三次) (6 项)
✓ 检查会话 prompt:⛔ 指向真源 + 给只读边界(否则被判『重复执行』白跑) (14 项)
⛔ 拒收:`--state done` **必须**带 `--artifact <产物文档>`。
理由:任务会话完成时**要写文档**,台账里要有该文档的说明 ——
否则检查会话读到 `done` 却**不知道去哪核实**(用户 2026-10-03:「避免检查会话到处找信息」)。
正确写法:--artifact "目标-未命名目标-35279e/S13_xxx_20261003.md"
(🔴 **必须落在目标目录里** —— 合同见 `DOC_CONTRACT_ROWS`;
⛔ 不许写回 `交付物/`、`docs/`、工作区根 ⇒ 那正是「到处找信息」的由来)
降级写法:若本轮确实没产出文档,**别报 done**,报 `--state blocked --reason "文档未写"`。
⛔ 拒收:`--state blocked` **必须**带 `--reason <卡在哪、卡在谁>`。
理由:不写"卡了"不说卡在哪 ⇒ 台账里的受阻**没法据此派活**。
正确写法:--reason "等 <谁> 回答 <什么>"
⚠️ 提醒:`--artifact` **不在目标目录内**(应在 `目标-未命名目标-35279e/` 下;合同:执行产物一律落目标目录,⛔ 否则下一个会话又要到处找)
OK 已上报:T3 (新) -> done
⛔ 拒收:`--state done` 的 `--artifact` **文件读不到**。
判据:`artifact_state()`(唯一事实源)⇒ state=gone
原因:**文件不存在**(试过:C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-j1eyqyy_\x\没有这个.md/C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-j1eyqyy_\x\没有这个.md)
试过的路径:C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-j1eyqyy_\x\没有这个.md
✅ 正确做法:**先把文档写出来**,再用**相对工作区**的路径报它,例如
--artifact "目标-未命名目标-35279e/S13_xxx_20261003.md"
⛔ 别报一个「打算写」或「写错目录」的路径 —— 下一个会话照它读会读空。
⚠️ 若确实写不了文档 ⇒ `--state blocked --reason "文档未写"`。
OK 已上报:T4 (新) -> blocked
✓ 台账纪律:`done` 必须带产物文档 + `blocked` 必须带原因(否则检查会话只能去翻) (6 项)
✓ 目标执行状态文档:字段在位 + 文件真存在 + 检查会话照它判(⛔ 不许再去翻) (10 项)
✓ 🔴 artifact 合同:产物要**真读得到** + 落点提示 + 机制侧预挑不可核实件 (10 项)
✓ 目标文件夹机制:按目标算目录 + 文档同源 + 派棒产物落点 + CLI 幂等 (10 项)
✓ 常驻程序在线判据:读**常驻心跳**(⛔ 不是退役旧戳)+ 四态文案 + pid 判据复用 (9 项)
✓ 闸④:排除**已过期的一次性**排期(⛔ 否则它永远卡住闸=自己锁死自己) (5 项)
✓ 看板 tab:**跨工作区**并列查看(⛔ 原本只认一个 INBOX,天生看不见别的目录) (12 项)
✓ 跨工作区 peer 格:⛔ **不得吃本工作区数据**(吃了=把本区执行情况挂到别人名下=说假话) (5 项)
✗ 跨工作区 tab:**有差异的字段必须逐个被视图取到**(⛔ 漏一个 ⇒ 静默沿用本区 ⇒ 几个 tab 看起来一样)
✗ 两块有差异的字段 12 个,**视图必须逐个取到**(⛔ 漏了会静默沿用本区):⛔ 漏了 ['ws_name']
✓ 每个 hook 都能真正跑起来(⛔ 不许一导入就崩) (9 项)
✓ 架构图:每条线的**两端都落在真实框上**(⛔ 不许线头悬空) (10 项)
✓ 目标完成 ⇒ 真的收工(⛔ 不许只改状态不关进程);阻碍 ⇒ 不关 (6 项)
✓ 跨区自愈:**只补进行中的区**(⛔ 已完成/阻碍/已收工的一律不拉) (9 项)
✓ 初始化脚本:**指向本区副本**(⛔ 不许再让用户跑技能目录那份) (5 项)
✓ 自指型判据:**必须被排除**(⛔ 否则 `goal_state()` 只能自己满足自己,永远锁死) (17 项)
✓ **单包自包含**(⛔ 只复制这一个技能到别的机器,排版/提报用户/去 AI 味都要能用) (9 项)
✓ 搬入的两块**不许被删掉/漂移**(⛔ 自决策口径 + 任务会话六阶段) (28 项)
✓ 包体卫生:**不许长回备份/缓存/零引用文件**,且**没有版本控制兜底**(⛔ 删了就是真删) (7 项)
✓ 告警文案:**必须说清后果**(⛔ 不许只说「缺了 A」) (3 项)
✗ 产物落点:**每个目标一个独立文件夹**(⛔ 代码与其他路径除外)|**报告型**
✓ 目标文件夹存在:目标-本机协作-c8154d(独立进程按 `goal.json` 算出,INBOX=E:\ProgramData\AIProject\ai1net-dsh-server\tmp\supervise-inbox)
✗ 产物型 md 都落在「目标-*/交付物」内(⛔ 代码/规则/归档除外);已在目标文件夹或交付物=130,散在别处=22 → ['接续入口_官方账号登录_20260927.md', '接续入口_手机接入_20260928.md', '接续包_IM与插件接入_20260924.md', '接续包_IM反向通道实现_20260926.md', '接续包_IM接入面收尾与插件对接答复_20260926.md']
ⓘ 报告型 ⇒ ⛔ 不计入 --verify 成败(存量问题,⛔ 与安装无关)
✓ 🔴🔴 `ensure_supervise` spawn 孙进程**必须传 `COLLABD_CONFIG`**(否则起后即退) (5 项)
✓ 🔴 钩子真接上了:工作区从 stdin.payload.cwd 取(⛔ 不是 DSH_WS_ROOT) (10 项)
✓ 🔴 T 表 §1.6:起不来先报错(10-04 用户原话「必须首先启动好在执行」) (6 项)
✓ 🔴 T 表:状态 → 我该做什么(2026-10-04 用户口述 · ⛔ 不许 AI 推断) (36 项)
✓ 📇 文档索引:改流程/改机制前**必读三篇**在第一屏 + 文档四条规则在位 (18 项)
✓ 🔴 红线:⛔ 说「会怎样」前必须取证那个后果(10-03 立 · ⛔ 10-04 又犯) (7 项)
✓ 🔴 常驻「活多久」的判据:**存活时长 = 发起会话的存活时长**(⛔ 禁编造「活不过当轮」当后果) (9 项)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture\ws\交付物\session-mechanism-副本备份-20261005-120934
② 删残留 r_stale.py
③ 覆盖 1 |补入 1
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
✅ 无漂移,⛔ 什么也不做(幂等)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture2\ws\交付物\session-mechanism-副本备份-20261005-120935
③ 覆盖 1 |补入 0
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
⛔ **白名单缺失**(副本历史里有过,现在没了):roots.env(⛔ `roots.env` 丢 ⇒ 副本会按位置推导去读写**别的仓库**)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture2\ws\交付物\session-mechanism-副本备份-20261005-120935_2
↺ 白名单兜底源=**历史备份** session-mechanism-副本备份-20261005-120935
③ 覆盖 0 |补入 0
④ 白名单兜底恢复 roots.env
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
✓ 副本同步:**残留/待补/待更新三类漂移都抓得到**,且白名单不被动(P0-51 的正解) (21 项)
✓ 副本同步:`roots.env` 白名单**只按文件名**判(⛔ 换副本不许靠「我记得跳过哪个」) (5 项)
✓ 🔴 各工作区自我建立常驻:**副本里也得找得到载体模板**(⛔ 写死包根=每区必红) (5 项)
✓ 🔴 看板渲染:**真跑 `renderProject()`**(⛔ 不是查字符串 —— 实发过 `acc is not defined`) (12 项)
✓ 🔴🔴 peer(跨工作区)格**也要认主会话**(⛔ 不许只看本看板的 `WS`) (5 项)
✓ 🔴 建目标时**顺手登记主会话**(用户原话:⛔ 不用每次会话都去声明) (8 项)
✓ 🔴🔴 keeper 生成 ps1 时 `--script` 必须填**本区发布物**(⛔ 不许照着当前这份抄) (5 项)
✓ 🔴🔴 常驻**自我繁殖**必须断:续命只许起**本区发布物**(用户「越创建越多」的真因) (6 项)
✓ 🔴🔴 一个工作区只能有一个常驻:**启动前必判 + 身份核验**(pid 会复用) (9 项)
------------------------------------------------------------------
合计:PASS 96 / FAIL 1(另有 1 条报告型,⛔ 不计入)
==================================================================
@@ -0,0 +1,171 @@
==================================================================
协作机制 · 回归自测(每改一次必跑) 测试工作区:E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest
协作机制 · 回归自测(每改一次必跑) 测试工作区:E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest
==================================================================
✓ 命名:两级前缀解析(合规 / 缺级 / 接续会话 / 主控前缀) (9 项)
✓ 命名:看板与常驻程序**同一套角色判据**(⛔ 防两处漂移 —— 漂了就没人能发现换主会话) (8 项)
✓ 目标:无目标 ⇒ 拒绝启动 rc=3 (2 项)
✓ 目标:有待确认 ⇒ 拒绝启动 rc=4;--propose/--confirm 能走通 (2 项)
✓ 目标三态:『没有判据』⛔ 不等于『全过』(防『读不到被当成已完成』) (7 项)
✓ 验收判据认**真源的中文写法**(⛔ 别只喂英文 `pass` —— 那等于判据恒绿) (41 项)
✓ 两类检查会话是**两件事**:prompt 必须不同 + 闸④「本项目无待执行排期」 (18 项)
✓ 🔴🔴 闸⑥ 同类检查冷却期:两种情况 × 每类最多一条 ⇒ 不堆积(用户「不该有任何堆积」) (4 项)
✓ 检查会话的 prompt:**引用的命令必须真存在**(⛔ 引用不存在的命令 ⇒ 静默当成功) (7 项)
✓ 台账四态:running → blocked(带原因) → 解除后原因清掉 (3 项)
✓ 已停总闸:goal.run=paused ⇒ --once 只写一行、⛔ 不产告警(防『人为停掉被读成机制坏了』) (6 项)
✓ 投递:常驻程序(--once / --report)**零投递** (1 项)
✓ 投递:目标会话(**跟进会话**)在跑 ⇒ 必须延后(target-busy) (2 项)
✓ 投递:错名修复 —— `why` 透传(有候选但不活 ⇒ follow-not-live,⛔ 不再记 no-follow-session) (4 项)
✓ 投递:粗判第一条候选已哑、同类别另有活候选 ⇒ ⛔ 不许终局判 target-deaf(修『走不到精确重算』) (2 项)
✓ 投递:跨进程互斥锁存在且会被释放 (2 项)
✓ 投递:锁被**别的进程**持有时 ⇒ ⛔ 不投(`locked`) (1 项)
✓ 哑会话:诊断日志 ≥ 9.5 MiB ⇒ _deaf_sids() 判哑(只读 · 判据=读数、含边界) (4 项)
✓ 哑会话:投递命中已哑目标 ⇒ skipped=target-deaf(⛔ 不投 + 喊用户;⛔ 不记假绿) (2 项)
✓ 哑会话:**只认最新一天** —— 昨天撞过上限、今天已正常轮转 ⇒ ⛔ 不判哑(修『永久判哑』) (5 项)
✓ 投递(新):纯投影 --once ⛔ 不消费队列 (3 项)
✓ 投递(新):投不出去(no-token)⇒ ⛔ 不消费队列(防静默丢件) (4 项)
✓ 宿主卡住探针:只读尾部、测试环境零命中、⛔ 不误报 (6 项)
✓ 投递消费回查:投出去 ≠ 跑起来了 ⇒ 未消费必须升级为 NEED-USER (4 项)
✓ need_user:同句节流(⛔ 不每轮刷时间戳)+ 人写的「## 解除条件」两路都必须原样保留 (4 项)
✓ 投递忙判据:读宿主状态机日志的 busy=(⛔ 不再用 `status=='working'` 那档恒真的判据) (17 项)
✓ 🔴 `--tick` 已删:参数表/分支/钩子调用**三处皆无**,且投递段仍真删 (7 项)
✓ 对账:僵尸(台账 running 但没人跑)⇒ 标 blocked (1 项)
✓ 对账:幂等(连跑两次结论一致) (2 项)
✓ CLI:未知参数 ⇒ rc=2 且**不落常驻** (2 项)
✓ CLI:--where / --reqs 可跑且 rc=0 (2 项)
✓ 结构:关键名字/设施在位(防『误删常量』重演) (1 项)
✓ 结构:所有 subprocess 调用都带 creationflags(不显窗) (1 项)
✓ 结构:fatal 不再 exit 0(防『假绿』) (2 项)
✓ 结构:投递段**已真删**(⛔ 旧「投递方唯一」判据已于 2026-10-03 退役) (6 项)
✓ 主会话:**解析出来的**(不只是读登记)+ ⛔ 拒绝盲投(防『投错窗口』回潮) (26 项)
✓ 主会话:看板与投递**同一套判据**(⛔ 防两处漂移 —— 漂了就没人能发现换主会话) (2 项)
✓ 主会话:**退役角色不许当候选** —— 行为级(真造宿主库 + 真跑扫描,⛔ 不只测那个小函数) (5 项)
✓ 主会话:登记为 main 但**已哑** ⇒ ⛔ 不认它 + `--declare main` 是**换**不是「加」 (6 项)
✓ 结构:守护生命周期(优雅退出设施在位) (3 项)
✓ 归属判据:看板 ≡ 收尾确认(⛔ 防两处漂移;⛔ 不按 cwd 推断) (2 项)
✓ 看板:风格系统(三风格令牌在位 + 组件里零硬编码色) (2 项)
✓ 看板:验收摘要行 ⛔ 不许把『一条判据都没有』说成『无』(同族红线) (4 项)
✓ 看板:『未归类』不许被静默丢掉(同族红线:读到了就要说) (4 项)
✓ 看板:**同工作区但没归入本项目**的会话不许静默丢(⛔ 也不许把它算进本项目) (4 项)
✓ 归属:两处 `in_project` 判据**逐样本对账**(⛔ 漂了就静默漏管) (6 项)
✓ 会话退场:过期会话**收起但不删除**,且 ⛔ 不吃掉在跑的棒与主会话 (13 项)
✓ 看板:任务类别**来源**必须说得出口(declared / fallback) (6 项)
✓ 看板:多目标 tab(一格一个目标 ⇒ ⛔ 不是各画一份叠着) (28 项)
✓ 动手层:三条开工动作在位 + **判据不许恒红**(⛔ 恒红 = 没有判据) (10 项)
========================================================================
判据元体检 · E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\judge_probe.py
========================================================================
⚠️ 命中 2 处(⛔ 这些是**可疑写法**,⛔ 不等于一定是错):
🔴 self-recompute [self] 行 [1]
↳ 判据里用 `lambda` **自己重算**被检的算法 ⇒ 改被检对象它照样绿(今天 V4)
🔴 anchor-text-only [weak] 行 [2]
↳ 锚在「源码/文本里出现过某词」⇒ ⛔ 证明不了行为(今天 V6;判据元规则之一)
处置:逐条改判据(⛔ 别改规则表消警告 —— 那是把体温计砸了)
ⓘ 确认是误报就加进 `FALSE_POSITIVE`(⛔ 但要写清为什么,⛔ 不许默默加)
✓ 判据元体检工具在位 + 它的**元规则**也不是摆设(⛔ 防「靠记得」) (10 项)
✓ 红线 S:⛔ 严禁把「被监控对象所在工作区」当成「目标归属工作区」+ 归属核对进 env_check (13 项)
✓ 红线:⛔ 严禁用「排期/自动任务」当常驻载体 + 环境检查必须查工作区部署 (11 项)
✓ 沉淀纪律:**经验不许写成流水账**(体量有上限 + 判据要点不许丢) (5 项)
✓ 看板:版面纪律(小字描述只进 ?;指定删除的三处不得回来) (3 项)
✓ 技能侧零项目串(「技能就是技能,谁用产生的文件放在他自己那里」) (4 项)
✓ 常驻:存活判据=『pid 活 ∧ 心跳新鲜』+ 自愈接线在 + ⛔ 两条不起闸 (11 项)
✓ 元:本测试不碰生产(判据=**测试独有的痕迹**,⛔ 不拿「文件被写过」当证据) (2 项)
✓ 闸②:判『所有会话都结束』=与看板同款(status=='working')+排除观察者自己 (6 项)
✓ 检查会话:排期名**按两级前缀**(⛔ 否则看板认不出它是任务会话)+ 看板有『检查程序在跑』读数 (6 项)
✓ 检查会话:board ⇄ collabd 两侧解析**逐样本对账**(⛔ 这两侧已漂过三次) (6 项)
✓ 检查会话 prompt:⛔ 指向真源 + 给只读边界(否则被判『重复执行』白跑) (14 项)
⛔ 拒收:`--state done` **必须**带 `--artifact <产物文档>`。
理由:任务会话完成时**要写文档**,台账里要有该文档的说明 ——
否则检查会话读到 `done` 却**不知道去哪核实**(用户 2026-10-03:「避免检查会话到处找信息」)。
正确写法:--artifact "目标-未命名目标-35279e/S13_xxx_20261003.md"
(🔴 **必须落在目标目录里** —— 合同见 `DOC_CONTRACT_ROWS`;
⛔ 不许写回 `交付物/`、`docs/`、工作区根 ⇒ 那正是「到处找信息」的由来)
降级写法:若本轮确实没产出文档,**别报 done**,报 `--state blocked --reason "文档未写"`。
⛔ 拒收:`--state blocked` **必须**带 `--reason <卡在哪、卡在谁>`。
理由:不写"卡了"不说卡在哪 ⇒ 台账里的受阻**没法据此派活**。
正确写法:--reason "等 <谁> 回答 <什么>"
⚠️ 提醒:`--artifact` **不在目标目录内**(应在 `目标-未命名目标-35279e/` 下;合同:执行产物一律落目标目录,⛔ 否则下一个会话又要到处找)
OK 已上报:T3 (新) -> done
⛔ 拒收:`--state done` 的 `--artifact` **文件读不到**。
判据:`artifact_state()`(唯一事实源)⇒ state=gone
原因:**文件不存在**(试过:C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-u133s56c\x\没有这个.md/C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-u133s56c\x\没有这个.md)
试过的路径:C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-u133s56c\x\没有这个.md
✅ 正确做法:**先把文档写出来**,再用**相对工作区**的路径报它,例如
--artifact "目标-未命名目标-35279e/S13_xxx_20261003.md"
⛔ 别报一个「打算写」或「写错目录」的路径 —— 下一个会话照它读会读空。
⚠️ 若确实写不了文档 ⇒ `--state blocked --reason "文档未写"`。
OK 已上报:T4 (新) -> blocked
✓ 台账纪律:`done` 必须带产物文档 + `blocked` 必须带原因(否则检查会话只能去翻) (6 项)
✓ 目标执行状态文档:字段在位 + 文件真存在 + 检查会话照它判(⛔ 不许再去翻) (10 项)
✓ 🔴 artifact 合同:产物要**真读得到** + 落点提示 + 机制侧预挑不可核实件 (10 项)
✓ 目标文件夹机制:按目标算目录 + 文档同源 + 派棒产物落点 + CLI 幂等 (10 项)
✓ 常驻程序在线判据:读**常驻心跳**(⛔ 不是退役旧戳)+ 四态文案 + pid 判据复用 (9 项)
✓ 闸④:排除**已过期的一次性**排期(⛔ 否则它永远卡住闸=自己锁死自己) (5 项)
✓ 看板 tab:**跨工作区**并列查看(⛔ 原本只认一个 INBOX,天生看不见别的目录) (12 项)
✓ 跨工作区 peer 格:⛔ **不得吃本工作区数据**(吃了=把本区执行情况挂到别人名下=说假话) (5 项)
✓ 跨工作区 tab:**有差异的字段必须逐个被视图取到**(⛔ 漏一个 ⇒ 静默沿用本区 ⇒ 几个 tab 看起来一样) (1 项)
✓ 每个 hook 都能真正跑起来(⛔ 不许一导入就崩) (9 项)
✓ 架构图:每条线的**两端都落在真实框上**(⛔ 不许线头悬空) (10 项)
✓ 目标完成 ⇒ 真的收工(⛔ 不许只改状态不关进程);阻碍 ⇒ 不关 (6 项)
✓ 跨区自愈:**只补进行中的区**(⛔ 已完成/阻碍/已收工的一律不拉) (9 项)
✓ 初始化脚本:**指向本区副本**(⛔ 不许再让用户跑技能目录那份) (5 项)
✓ 自指型判据:**必须被排除**(⛔ 否则 `goal_state()` 只能自己满足自己,永远锁死) (17 项)
✓ **单包自包含**(⛔ 只复制这一个技能到别的机器,排版/提报用户/去 AI 味都要能用) (9 项)
✓ 搬入的两块**不许被删掉/漂移**(⛔ 自决策口径 + 任务会话六阶段) (28 项)
✓ 包体卫生:**不许长回备份/缓存/零引用文件**,且**没有版本控制兜底**(⛔ 删了就是真删) (7 项)
✓ 告警文案:**必须说清后果**(⛔ 不许只说「缺了 A」) (3 项)
✗ 产物落点:**每个目标一个独立文件夹**(⛔ 代码与其他路径除外)|**报告型**
✓ 目标文件夹存在:目标-本机协作-c8154d(独立进程按 `goal.json` 算出,INBOX=E:\ProgramData\AIProject\ai1net-dsh-server\tmp\supervise-inbox)
✗ 产物型 md 都落在「目标-*/交付物」内(⛔ 代码/规则/归档除外);已在目标文件夹或交付物=130,散在别处=22 → ['接续入口_官方账号登录_20260927.md', '接续入口_手机接入_20260928.md', '接续包_IM与插件接入_20260924.md', '接续包_IM反向通道实现_20260926.md', '接续包_IM接入面收尾与插件对接答复_20260926.md']
ⓘ 报告型 ⇒ ⛔ 不计入 --verify 成败(存量问题,⛔ 与安装无关)
✓ 🔴🔴 `ensure_supervise` spawn 孙进程**必须传 `COLLABD_CONFIG`**(否则起后即退) (5 项)
✓ 🔴 钩子真接上了:工作区从 stdin.payload.cwd 取(⛔ 不是 DSH_WS_ROOT) (10 项)
✓ 🔴 T 表 §1.6:起不来先报错(10-04 用户原话「必须首先启动好在执行」) (6 项)
✓ 🔴 T 表:状态 → 我该做什么(2026-10-04 用户口述 · ⛔ 不许 AI 推断) (36 项)
✓ 📇 文档索引:改流程/改机制前**必读三篇**在第一屏 + 文档四条规则在位 (18 项)
✓ 🔴 红线:⛔ 说「会怎样」前必须取证那个后果(10-03 立 · ⛔ 10-04 又犯) (7 项)
✓ 🔴 常驻「活多久」的判据:**存活时长 = 发起会话的存活时长**(⛔ 禁编造「活不过当轮」当后果) (9 项)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture\ws\交付物\session-mechanism-副本备份-20261005-121006
② 删残留 r_stale.py
③ 覆盖 1 |补入 1
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
✅ 无漂移,⛔ 什么也不做(幂等)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture2\ws\交付物\session-mechanism-副本备份-20261005-121007
③ 覆盖 1 |补入 0
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
⛔ **白名单缺失**(副本历史里有过,现在没了):roots.env(⛔ `roots.env` 丢 ⇒ 副本会按位置推导去读写**别的仓库**)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture2\ws\交付物\session-mechanism-副本备份-20261005-121007_2
↺ 白名单兜底源=**历史备份** session-mechanism-副本备份-20261005-121007
③ 覆盖 0 |补入 0
④ 白名单兜底恢复 roots.env
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
✓ 副本同步:**残留/待补/待更新三类漂移都抓得到**,且白名单不被动(P0-51 的正解) (21 项)
✓ 副本同步:`roots.env` 白名单**只按文件名**判(⛔ 换副本不许靠「我记得跳过哪个」) (5 项)
✓ 🔴 各工作区自我建立常驻:**副本里也得找得到载体模板**(⛔ 写死包根=每区必红) (5 项)
✓ 🔴 看板渲染:**真跑 `renderProject()`**(⛔ 不是查字符串 —— 实发过 `acc is not defined`) (12 项)
✓ 🔴🔴 peer(跨工作区)格**也要认主会话**(⛔ 不许只看本看板的 `WS`) (5 项)
✓ 🔴 建目标时**顺手登记主会话**(用户原话:⛔ 不用每次会话都去声明) (8 项)
✓ 🔴🔴 keeper 生成 ps1 时 `--script` 必须填**本区发布物**(⛔ 不许照着当前这份抄) (5 项)
✓ 🔴🔴 常驻**自我繁殖**必须断:续命只许起**本区发布物**(用户「越创建越多」的真因) (6 项)
✓ 🔴🔴 一个工作区只能有一个常驻:**启动前必判 + 身份核验**(pid 会复用) (9 项)
------------------------------------------------------------------
合计:PASS 97 / FAIL 0(另有 1 条报告型,⛔ 不计入)
==================================================================
@@ -0,0 +1,172 @@
==================================================================
协作机制 · 回归自测(每改一次必跑) 测试工作区:E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest
协作机制 · 回归自测(每改一次必跑) 测试工作区:E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest
==================================================================
✓ 命名:两级前缀解析(合规 / 缺级 / 接续会话 / 主控前缀) (9 项)
✓ 命名:看板与常驻程序**同一套角色判据**(⛔ 防两处漂移 —— 漂了就没人能发现换主会话) (8 项)
✓ 目标:无目标 ⇒ 拒绝启动 rc=3 (2 项)
✓ 目标:有待确认 ⇒ 拒绝启动 rc=4;--propose/--confirm 能走通 (2 项)
✓ 目标三态:『没有判据』⛔ 不等于『全过』(防『读不到被当成已完成』) (7 项)
✓ 验收判据认**真源的中文写法**(⛔ 别只喂英文 `pass` —— 那等于判据恒绿) (41 项)
✓ 两类检查会话是**两件事**:prompt 必须不同 + 闸④「本项目无待执行排期」 (18 项)
✓ 🔴🔴 闸⑥ 同类检查冷却期:两种情况 × 每类最多一条 ⇒ 不堆积(用户「不该有任何堆积」) (4 项)
✓ 检查会话的 prompt:**引用的命令必须真存在**(⛔ 引用不存在的命令 ⇒ 静默当成功) (7 项)
✓ 台账四态:running → blocked(带原因) → 解除后原因清掉 (3 项)
✓ 已停总闸:goal.run=paused ⇒ --once 只写一行、⛔ 不产告警(防『人为停掉被读成机制坏了』) (6 项)
✓ 投递:常驻程序(--once / --report)**零投递** (1 项)
✓ 投递:目标会话(**跟进会话**)在跑 ⇒ 必须延后(target-busy) (2 项)
✓ 投递:错名修复 —— `why` 透传(有候选但不活 ⇒ follow-not-live,⛔ 不再记 no-follow-session) (4 项)
✓ 投递:粗判第一条候选已哑、同类别另有活候选 ⇒ ⛔ 不许终局判 target-deaf(修『走不到精确重算』) (2 项)
✓ 投递:跨进程互斥锁存在且会被释放 (2 项)
✓ 投递:锁被**别的进程**持有时 ⇒ ⛔ 不投(`locked`) (1 项)
✓ 哑会话:诊断日志 ≥ 9.5 MiB ⇒ _deaf_sids() 判哑(只读 · 判据=读数、含边界) (4 项)
✓ 哑会话:投递命中已哑目标 ⇒ skipped=target-deaf(⛔ 不投 + 喊用户;⛔ 不记假绿) (2 项)
✓ 哑会话:**只认最新一天** —— 昨天撞过上限、今天已正常轮转 ⇒ ⛔ 不判哑(修『永久判哑』) (5 项)
✓ 投递(新):纯投影 --once ⛔ 不消费队列 (3 项)
✓ 投递(新):投不出去(no-token)⇒ ⛔ 不消费队列(防静默丢件) (4 项)
✓ 宿主卡住探针:只读尾部、测试环境零命中、⛔ 不误报 (6 项)
✓ 投递消费回查:投出去 ≠ 跑起来了 ⇒ 未消费必须升级为 NEED-USER (4 项)
✓ need_user:同句节流(⛔ 不每轮刷时间戳)+ 人写的「## 解除条件」两路都必须原样保留 (4 项)
✓ 投递忙判据:读宿主状态机日志的 busy=(⛔ 不再用 `status=='working'` 那档恒真的判据) (17 项)
✓ 🔴 `--tick` 已删:参数表/分支/钩子调用**三处皆无**,且投递段仍真删 (7 项)
✓ 对账:僵尸(台账 running 但没人跑)⇒ 标 blocked (1 项)
✓ 对账:幂等(连跑两次结论一致) (2 项)
✓ CLI:未知参数 ⇒ rc=2 且**不落常驻** (2 项)
✓ CLI:--where / --reqs 可跑且 rc=0 (2 项)
✓ 结构:关键名字/设施在位(防『误删常量』重演) (1 项)
✓ 结构:所有 subprocess 调用都带 creationflags(不显窗) (1 项)
✓ 结构:fatal 不再 exit 0(防『假绿』) (2 项)
✓ 结构:投递段**已真删**(⛔ 旧「投递方唯一」判据已于 2026-10-03 退役) (6 项)
✓ 主会话:**解析出来的**(不只是读登记)+ ⛔ 拒绝盲投(防『投错窗口』回潮) (26 项)
✓ 主会话:看板与投递**同一套判据**(⛔ 防两处漂移 —— 漂了就没人能发现换主会话) (2 项)
✓ 主会话:**退役角色不许当候选** —— 行为级(真造宿主库 + 真跑扫描,⛔ 不只测那个小函数) (5 项)
✓ 主会话:登记为 main 但**已哑** ⇒ ⛔ 不认它 + `--declare main` 是**换**不是「加」 (6 项)
✓ 结构:守护生命周期(优雅退出设施在位) (3 项)
✓ 归属判据:看板 ≡ 收尾确认(⛔ 防两处漂移;⛔ 不按 cwd 推断) (2 项)
✓ 看板:风格系统(三风格令牌在位 + 组件里零硬编码色) (2 项)
✓ 看板:验收摘要行 ⛔ 不许把『一条判据都没有』说成『无』(同族红线) (4 项)
✓ 看板:『未归类』不许被静默丢掉(同族红线:读到了就要说) (4 项)
✓ 看板:**同工作区但没归入本项目**的会话不许静默丢(⛔ 也不许把它算进本项目) (4 项)
✓ 归属:两处 `in_project` 判据**逐样本对账**(⛔ 漂了就静默漏管) (6 项)
✓ 会话退场:过期会话**收起但不删除**,且 ⛔ 不吃掉在跑的棒与主会话 (13 项)
✓ 看板:任务类别**来源**必须说得出口(declared / fallback) (6 项)
✓ 看板:多目标 tab(一格一个目标 ⇒ ⛔ 不是各画一份叠着) (28 项)
✓ 动手层:三条开工动作在位 + **判据不许恒红**(⛔ 恒红 = 没有判据) (10 项)
========================================================================
判据元体检 · E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\judge_probe.py
========================================================================
⚠️ 命中 2 处(⛔ 这些是**可疑写法**,⛔ 不等于一定是错):
🔴 self-recompute [self] 行 [1]
↳ 判据里用 `lambda` **自己重算**被检的算法 ⇒ 改被检对象它照样绿(今天 V4)
🔴 anchor-text-only [weak] 行 [2]
↳ 锚在「源码/文本里出现过某词」⇒ ⛔ 证明不了行为(今天 V6;判据元规则之一)
处置:逐条改判据(⛔ 别改规则表消警告 —— 那是把体温计砸了)
ⓘ 确认是误报就加进 `FALSE_POSITIVE`(⛔ 但要写清为什么,⛔ 不许默默加)
✓ 判据元体检工具在位 + 它的**元规则**也不是摆设(⛔ 防「靠记得」) (10 项)
✓ 红线 S:⛔ 严禁把「被监控对象所在工作区」当成「目标归属工作区」+ 归属核对进 env_check (13 项)
✓ 红线:⛔ 严禁用「排期/自动任务」当常驻载体 + 环境检查必须查工作区部署 (11 项)
✓ 沉淀纪律:**经验不许写成流水账**(体量有上限 + 判据要点不许丢) (5 项)
✓ 看板:版面纪律(小字描述只进 ?;指定删除的三处不得回来) (3 项)
✓ 技能侧零项目串(「技能就是技能,谁用产生的文件放在他自己那里」) (4 项)
✓ 常驻:存活判据=『pid 活 ∧ 心跳新鲜』+ 自愈接线在 + ⛔ 两条不起闸 (11 项)
✓ 元:本测试不碰生产(判据=**测试独有的痕迹**,⛔ 不拿「文件被写过」当证据) (2 项)
✓ 闸②:判『所有会话都结束』=与看板同款(status=='working')+排除观察者自己 (6 项)
✓ 检查会话:排期名**按两级前缀**(⛔ 否则看板认不出它是任务会话)+ 看板有『检查程序在跑』读数 (6 项)
✓ 检查会话:board ⇄ collabd 两侧解析**逐样本对账**(⛔ 这两侧已漂过三次) (6 项)
✓ 检查会话 prompt:⛔ 指向真源 + 给只读边界(否则被判『重复执行』白跑) (14 项)
⛔ 拒收:`--state done` **必须**带 `--artifact <产物文档>`。
理由:任务会话完成时**要写文档**,台账里要有该文档的说明 ——
否则检查会话读到 `done` 却**不知道去哪核实**(用户 2026-10-03:「避免检查会话到处找信息」)。
正确写法:--artifact "目标-未命名目标-35279e/S13_xxx_20261003.md"
(🔴 **必须落在目标目录里** —— 合同见 `DOC_CONTRACT_ROWS`;
⛔ 不许写回 `交付物/`、`docs/`、工作区根 ⇒ 那正是「到处找信息」的由来)
降级写法:若本轮确实没产出文档,**别报 done**,报 `--state blocked --reason "文档未写"`。
⛔ 拒收:`--state blocked` **必须**带 `--reason <卡在哪、卡在谁>`。
理由:不写"卡了"不说卡在哪 ⇒ 台账里的受阻**没法据此派活**。
正确写法:--reason "等 <谁> 回答 <什么>"
⚠️ 提醒:`--artifact` **不在目标目录内**(应在 `目标-未命名目标-35279e/` 下;合同:执行产物一律落目标目录,⛔ 否则下一个会话又要到处找)
OK 已上报:T3 (新) -> done
⛔ 拒收:`--state done` 的 `--artifact` **文件读不到**。
判据:`artifact_state()`(唯一事实源)⇒ state=gone
原因:**文件不存在**(试过:C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-fkzbiiaf\x\没有这个.md/C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-fkzbiiaf\x\没有这个.md)
试过的路径:C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-fkzbiiaf\x\没有这个.md
✅ 正确做法:**先把文档写出来**,再用**相对工作区**的路径报它,例如
--artifact "目标-未命名目标-35279e/S13_xxx_20261003.md"
⛔ 别报一个「打算写」或「写错目录」的路径 —— 下一个会话照它读会读空。
⚠️ 若确实写不了文档 ⇒ `--state blocked --reason "文档未写"`。
OK 已上报:T4 (新) -> blocked
✓ 台账纪律:`done` 必须带产物文档 + `blocked` 必须带原因(否则检查会话只能去翻) (6 项)
✓ 目标执行状态文档:字段在位 + 文件真存在 + 检查会话照它判(⛔ 不许再去翻) (10 项)
✓ 🔴 artifact 合同:产物要**真读得到** + 落点提示 + 机制侧预挑不可核实件 (10 项)
✓ 目标文件夹机制:按目标算目录 + 文档同源 + 派棒产物落点 + CLI 幂等 (10 项)
✓ 常驻程序在线判据:读**常驻心跳**(⛔ 不是退役旧戳)+ 四态文案 + pid 判据复用 (9 项)
✓ 闸④:排除**已过期的一次性**排期(⛔ 否则它永远卡住闸=自己锁死自己) (5 项)
✓ 看板 tab:**跨工作区**并列查看(⛔ 原本只认一个 INBOX,天生看不见别的目录) (12 项)
✓ 跨工作区 peer 格:⛔ **不得吃本工作区数据**(吃了=把本区执行情况挂到别人名下=说假话) (5 项)
✗ 跨工作区 tab:**有差异的字段必须逐个被视图取到**(⛔ 漏一个 ⇒ 静默沿用本区 ⇒ 几个 tab 看起来一样)
✗ 两块有差异的字段 14 个,**视图必须逐个取到**(⛔ 漏了会静默沿用本区):⛔ 漏了 ['tab_hot', 'tab_i', 'ws_name']
✓ 每个 hook 都能真正跑起来(⛔ 不许一导入就崩) (9 项)
✓ 架构图:每条线的**两端都落在真实框上**(⛔ 不许线头悬空) (10 项)
✓ 目标完成 ⇒ 真的收工(⛔ 不许只改状态不关进程);阻碍 ⇒ 不关 (6 项)
✓ 跨区自愈:**只补进行中的区**(⛔ 已完成/阻碍/已收工的一律不拉) (9 项)
✓ 初始化脚本:**指向本区副本**(⛔ 不许再让用户跑技能目录那份) (5 项)
✓ 自指型判据:**必须被排除**(⛔ 否则 `goal_state()` 只能自己满足自己,永远锁死) (17 项)
✓ **单包自包含**(⛔ 只复制这一个技能到别的机器,排版/提报用户/去 AI 味都要能用) (9 项)
✓ 搬入的两块**不许被删掉/漂移**(⛔ 自决策口径 + 任务会话六阶段) (28 项)
✓ 包体卫生:**不许长回备份/缓存/零引用文件**,且**没有版本控制兜底**(⛔ 删了就是真删) (7 项)
✓ 告警文案:**必须说清后果**(⛔ 不许只说「缺了 A」) (3 项)
✗ 产物落点:**每个目标一个独立文件夹**(⛔ 代码与其他路径除外)|**报告型**
✓ 目标文件夹存在:目标-本机协作-c8154d(独立进程按 `goal.json` 算出,INBOX=E:\ProgramData\AIProject\ai1net-dsh-server\tmp\supervise-inbox)
✗ 产物型 md 都落在「目标-*/交付物」内(⛔ 代码/规则/归档除外);已在目标文件夹或交付物=130,散在别处=22 → ['接续入口_官方账号登录_20260927.md', '接续入口_手机接入_20260928.md', '接续包_IM与插件接入_20260924.md', '接续包_IM反向通道实现_20260926.md', '接续包_IM接入面收尾与插件对接答复_20260926.md']
ⓘ 报告型 ⇒ ⛔ 不计入 --verify 成败(存量问题,⛔ 与安装无关)
✓ 🔴🔴 `ensure_supervise` spawn 孙进程**必须传 `COLLABD_CONFIG`**(否则起后即退) (5 项)
✓ 🔴 钩子真接上了:工作区从 stdin.payload.cwd 取(⛔ 不是 DSH_WS_ROOT) (10 项)
✓ 🔴 T 表 §1.6:起不来先报错(10-04 用户原话「必须首先启动好在执行」) (6 项)
✓ 🔴 T 表:状态 → 我该做什么(2026-10-04 用户口述 · ⛔ 不许 AI 推断) (36 项)
✓ 📇 文档索引:改流程/改机制前**必读三篇**在第一屏 + 文档四条规则在位 (18 项)
✓ 🔴 红线:⛔ 说「会怎样」前必须取证那个后果(10-03 立 · ⛔ 10-04 又犯) (7 项)
✓ 🔴 常驻「活多久」的判据:**存活时长 = 发起会话的存活时长**(⛔ 禁编造「活不过当轮」当后果) (9 项)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture\ws\交付物\session-mechanism-副本备份-20261005-120639
② 删残留 r_stale.py
③ 覆盖 1 |补入 1
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
✅ 无漂移,⛔ 什么也不做(幂等)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture2\ws\交付物\session-mechanism-副本备份-20261005-120639
③ 覆盖 1 |补入 0
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
⛔ **白名单缺失**(副本历史里有过,现在没了):roots.env(⛔ `roots.env` 丢 ⇒ 副本会按位置推导去读写**别的仓库**)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture2\ws\交付物\session-mechanism-副本备份-20261005-120639_2
↺ 白名单兜底源=**历史备份** session-mechanism-副本备份-20261005-120639
③ 覆盖 0 |补入 0
④ 白名单兜底恢复 roots.env
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
✓ 副本同步:**残留/待补/待更新三类漂移都抓得到**,且白名单不被动(P0-51 的正解) (21 项)
✓ 副本同步:`roots.env` 白名单**只按文件名**判(⛔ 换副本不许靠「我记得跳过哪个」) (5 项)
✓ 🔴 各工作区自我建立常驻:**副本里也得找得到载体模板**(⛔ 写死包根=每区必红) (5 项)
✓ 🔴 看板渲染:**真跑 `renderProject()`**(⛔ 不是查字符串 —— 实发过 `acc is not defined`) (12 项)
✓ 🔴🔴 peer(跨工作区)格**也要认主会话**(⛔ 不许只看本看板的 `WS`) (5 项)
✓ 🔴 建目标时**顺手登记主会话**(用户原话:⛔ 不用每次会话都去声明) (8 项)
✓ 🔴🔴 keeper 生成 ps1 时 `--script` 必须填**本区发布物**(⛔ 不许照着当前这份抄) (5 项)
✓ 🔴🔴 常驻**自我繁殖**必须断:续命只许起**本区发布物**(用户「越创建越多」的真因) (6 项)
✓ 🔴🔴 一个工作区只能有一个常驻:**启动前必判 + 身份核验**(pid 会复用) (9 项)
------------------------------------------------------------------
合计:PASS 96 / FAIL 1(另有 1 条报告型,⛔ 不计入)
==================================================================
@@ -0,0 +1,179 @@
==================================================================
协作机制 · 回归自测(每改一次必跑) 测试工作区:E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest
协作机制 · 回归自测(每改一次必跑) 测试工作区:E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest
==================================================================
✓ 命名:两级前缀解析(合规 / 缺级 / 接续会话 / 主控前缀) (9 项)
✓ 命名:看板与常驻程序**同一套角色判据**(⛔ 防两处漂移 —— 漂了就没人能发现换主会话) (8 项)
✓ 目标:无目标 ⇒ 拒绝启动 rc=3 (2 项)
✓ 目标:有待确认 ⇒ 拒绝启动 rc=4;--propose/--confirm 能走通 (2 项)
✓ 目标三态:『没有判据』⛔ 不等于『全过』(防『读不到被当成已完成』) (7 项)
✓ 验收判据认**真源的中文写法**(⛔ 别只喂英文 `pass` —— 那等于判据恒绿) (41 项)
✓ 两类检查会话是**两件事**:prompt 必须不同 + 闸④「本项目无待执行排期」 (18 项)
✓ 🔴🔴 闸⑥ 同类检查冷却期:两种情况 × 每类最多一条 ⇒ 不堆积(用户「不该有任何堆积」) (4 项)
✓ 检查会话的 prompt:**引用的命令必须真存在**(⛔ 引用不存在的命令 ⇒ 静默当成功) (7 项)
✓ 台账四态:running → blocked(带原因) → 解除后原因清掉 (3 项)
✓ 已停总闸:goal.run=paused ⇒ --once 只写一行、⛔ 不产告警(防『人为停掉被读成机制坏了』) (6 项)
✓ 投递:常驻程序(--once / --report)**零投递** (1 项)
✓ 投递:目标会话(**跟进会话**)在跑 ⇒ 必须延后(target-busy) (2 项)
✓ 投递:错名修复 —— `why` 透传(有候选但不活 ⇒ follow-not-live,⛔ 不再记 no-follow-session) (4 项)
✓ 投递:粗判第一条候选已哑、同类别另有活候选 ⇒ ⛔ 不许终局判 target-deaf(修『走不到精确重算』) (2 项)
✓ 投递:跨进程互斥锁存在且会被释放 (2 项)
✓ 投递:锁被**别的进程**持有时 ⇒ ⛔ 不投(`locked`) (1 项)
✓ 哑会话:诊断日志 ≥ 9.5 MiB ⇒ _deaf_sids() 判哑(只读 · 判据=读数、含边界) (4 项)
✓ 哑会话:投递命中已哑目标 ⇒ skipped=target-deaf(⛔ 不投 + 喊用户;⛔ 不记假绿) (2 项)
✓ 哑会话:**只认最新一天** —— 昨天撞过上限、今天已正常轮转 ⇒ ⛔ 不判哑(修『永久判哑』) (5 项)
✓ 投递(新):纯投影 --once ⛔ 不消费队列 (3 项)
✓ 投递(新):投不出去(no-token)⇒ ⛔ 不消费队列(防静默丢件) (4 项)
✓ 宿主卡住探针:只读尾部、测试环境零命中、⛔ 不误报 (6 项)
✓ 投递消费回查:投出去 ≠ 跑起来了 ⇒ 未消费必须升级为 NEED-USER (4 项)
✓ need_user:同句节流(⛔ 不每轮刷时间戳)+ 人写的「## 解除条件」两路都必须原样保留 (4 项)
✓ 投递忙判据:读宿主状态机日志的 busy=(⛔ 不再用 `status=='working'` 那档恒真的判据) (17 项)
✓ 🔴 `--tick` 已删:参数表/分支/钩子调用**三处皆无**,且投递段仍真删 (7 项)
✓ 对账:僵尸(台账 running 但没人跑)⇒ 标 blocked (1 项)
✓ 对账:幂等(连跑两次结论一致) (2 项)
✓ CLI:未知参数 ⇒ rc=2 且**不落常驻** (2 项)
✓ CLI:--where / --reqs 可跑且 rc=0 (2 项)
✓ 结构:关键名字/设施在位(防『误删常量』重演) (1 项)
✓ 结构:所有 subprocess 调用都带 creationflags(不显窗) (1 项)
✓ 结构:fatal 不再 exit 0(防『假绿』) (2 项)
✓ 结构:投递段**已真删**(⛔ 旧「投递方唯一」判据已于 2026-10-03 退役) (6 项)
✓ 主会话:**解析出来的**(不只是读登记)+ ⛔ 拒绝盲投(防『投错窗口』回潮) (26 项)
✓ 主会话:看板与投递**同一套判据**(⛔ 防两处漂移 —— 漂了就没人能发现换主会话) (2 项)
✓ 主会话:**退役角色不许当候选** —— 行为级(真造宿主库 + 真跑扫描,⛔ 不只测那个小函数) (5 项)
✓ 主会话:登记为 main 但**已哑** ⇒ ⛔ 不认它 + `--declare main` 是**换**不是「加」 (6 项)
✓ 结构:守护生命周期(优雅退出设施在位) (3 项)
✓ 归属判据:看板 ≡ 收尾确认(⛔ 防两处漂移;⛔ 不按 cwd 推断) (2 项)
✓ 看板:风格系统(三风格令牌在位 + 组件里零硬编码色) (2 项)
✓ 看板:验收摘要行 ⛔ 不许把『一条判据都没有』说成『无』(同族红线) (4 项)
✓ 看板:『未归类』不许被静默丢掉(同族红线:读到了就要说) (4 项)
✓ 看板:**同工作区但没归入本项目**的会话不许静默丢(⛔ 也不许把它算进本项目) (4 项)
✓ 归属:两处 `in_project` 判据**逐样本对账**(⛔ 漂了就静默漏管) (6 项)
✓ 会话退场:过期会话**收起但不删除**,且 ⛔ 不吃掉在跑的棒与主会话 (13 项)
✓ 看板:任务类别**来源**必须说得出口(declared / fallback) (6 项)
✓ 看板:多目标 tab(一格一个目标 ⇒ ⛔ 不是各画一份叠着) (28 项)
✓ 动手层:三条开工动作在位 + **判据不许恒红**(⛔ 恒红 = 没有判据) (10 项)
========================================================================
判据元体检 · E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\judge_probe.py
========================================================================
⚠️ 命中 2 处(⛔ 这些是**可疑写法**,⛔ 不等于一定是错):
🔴 self-recompute [self] 行 [1]
↳ 判据里用 `lambda` **自己重算**被检的算法 ⇒ 改被检对象它照样绿(今天 V4)
🔴 anchor-text-only [weak] 行 [2]
↳ 锚在「源码/文本里出现过某词」⇒ ⛔ 证明不了行为(今天 V6;判据元规则之一)
处置:逐条改判据(⛔ 别改规则表消警告 —— 那是把体温计砸了)
ⓘ 确认是误报就加进 `FALSE_POSITIVE`(⛔ 但要写清为什么,⛔ 不许默默加)
✓ 判据元体检工具在位 + 它的**元规则**也不是摆设(⛔ 防「靠记得」) (10 项)
✓ 红线 S:⛔ 严禁把「被监控对象所在工作区」当成「目标归属工作区」+ 归属核对进 env_check (13 项)
✓ 红线:⛔ 严禁用「排期/自动任务」当常驻载体 + 环境检查必须查工作区部署 (11 项)
✓ 沉淀纪律:**经验不许写成流水账**(体量有上限 + 判据要点不许丢) (5 项)
✓ 看板:版面纪律(小字描述只进 ?;指定删除的三处不得回来) (3 项)
✓ 技能侧零项目串(「技能就是技能,谁用产生的文件放在他自己那里」) (4 项)
✓ 常驻:存活判据=『pid 活 ∧ 心跳新鲜』+ 自愈接线在 + ⛔ 两条不起闸 (11 项)
✓ 元:本测试不碰生产(判据=**测试独有的痕迹**,⛔ 不拿「文件被写过」当证据) (2 项)
✓ 闸②:判『所有会话都结束』=与看板同款(status=='working')+排除观察者自己 (6 项)
✓ 检查会话:排期名**按两级前缀**(⛔ 否则看板认不出它是任务会话)+ 看板有『检查程序在跑』读数 (6 项)
✓ 检查会话:board ⇄ collabd 两侧解析**逐样本对账**(⛔ 这两侧已漂过三次) (6 项)
✓ 检查会话 prompt:⛔ 指向真源 + 给只读边界(否则被判『重复执行』白跑) (14 项)
⛔ 拒收:`--state done` **必须**带 `--artifact <产物文档>`。
理由:任务会话完成时**要写文档**,台账里要有该文档的说明 ——
否则检查会话读到 `done` 却**不知道去哪核实**(用户 2026-10-03:「避免检查会话到处找信息」)。
正确写法:--artifact "目标-未命名目标-35279e/S13_xxx_20261003.md"
(🔴 **必须落在目标目录里** —— 合同见 `DOC_CONTRACT_ROWS`;
⛔ 不许写回 `交付物/`、`docs/`、工作区根 ⇒ 那正是「到处找信息」的由来)
降级写法:若本轮确实没产出文档,**别报 done**,报 `--state blocked --reason "文档未写"`。
⛔ 拒收:`--state blocked` **必须**带 `--reason <卡在哪、卡在谁>`。
理由:不写"卡了"不说卡在哪 ⇒ 台账里的受阻**没法据此派活**。
正确写法:--reason "等 <谁> 回答 <什么>"
⚠️ 提醒:`--artifact` **不在目标目录内**(应在 `目标-未命名目标-35279e/` 下;合同:执行产物一律落目标目录,⛔ 否则下一个会话又要到处找)
OK 已上报:T3 (新) -> done
⛔ 拒收:`--state done` 的 `--artifact` **文件读不到**。
判据:`artifact_state()`(唯一事实源)⇒ state=gone
原因:**文件不存在**(试过:C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-oijdsv56\x\没有这个.md/C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-oijdsv56\x\没有这个.md)
试过的路径:C:\Users\Administrator\AppData\Local\Temp\dsh-selftest-tasks-oijdsv56\x\没有这个.md
✅ 正确做法:**先把文档写出来**,再用**相对工作区**的路径报它,例如
--artifact "目标-未命名目标-35279e/S13_xxx_20261003.md"
⛔ 别报一个「打算写」或「写错目录」的路径 —— 下一个会话照它读会读空。
⚠️ 若确实写不了文档 ⇒ `--state blocked --reason "文档未写"`。
OK 已上报:T4 (新) -> blocked
✓ 台账纪律:`done` 必须带产物文档 + `blocked` 必须带原因(否则检查会话只能去翻) (6 项)
✓ 目标执行状态文档:字段在位 + 文件真存在 + 检查会话照它判(⛔ 不许再去翻) (10 项)
✓ 🔴 artifact 合同:产物要**真读得到** + 落点提示 + 机制侧预挑不可核实件 (10 项)
✓ 目标文件夹机制:按目标算目录 + 文档同源 + 派棒产物落点 + CLI 幂等 (10 项)
✓ 常驻程序在线判据:读**常驻心跳**(⛔ 不是退役旧戳)+ 四态文案 + pid 判据复用 (9 项)
✓ 闸④:排除**已过期的一次性**排期(⛔ 否则它永远卡住闸=自己锁死自己) (5 项)
✓ 看板 tab:**跨工作区**并列查看(⛔ 原本只认一个 INBOX,天生看不见别的目录) (12 项)
✓ 跨工作区 peer 格:⛔ **不得吃本工作区数据**(吃了=把本区执行情况挂到别人名下=说假话) (5 项)
✓ 跨工作区 tab:**有差异的字段必须逐个被视图取到**(⛔ 漏一个 ⇒ 静默沿用本区 ⇒ 几个 tab 看起来一样) (1 项)
✓ 每个 hook 都能真正跑起来(⛔ 不许一导入就崩) (9 项)
✓ 架构图:每条线的**两端都落在真实框上**(⛔ 不许线头悬空) (10 项)
✓ 目标完成 ⇒ 真的收工(⛔ 不许只改状态不关进程);阻碍 ⇒ 不关 (6 项)
✓ 跨区自愈:**只补进行中的区**(⛔ 已完成/阻碍/已收工的一律不拉) (9 项)
✓ 初始化脚本:**指向本区副本**(⛔ 不许再让用户跑技能目录那份) (5 项)
✓ 自指型判据:**必须被排除**(⛔ 否则 `goal_state()` 只能自己满足自己,永远锁死) (17 项)
✓ **单包自包含**(⛔ 只复制这一个技能到别的机器,排版/提报用户/去 AI 味都要能用) (9 项)
✓ 搬入的两块**不许被删掉/漂移**(⛔ 自决策口径 + 任务会话六阶段) (28 项)
✗ 包体卫生:**不许长回备份/缓存/零引用文件**,且**没有版本控制兜底**(⛔ 删了就是真删)
✗ ⛔ 包内无 `*.bak-*` 历史备份(本轮清掉 68 个 / 8.6 MB)
✓ ⛔ 无散落的 `.pyc`(⛔ 只能在 `__pycache__` 内;它跑一次就重生,不判存在)
✓ ⛔ `install.log` 不超 64 KB(运行日志,⛔ 不属能力件;本轮清掉 36 KB)
✓ ⛔ `assets/*.js` 无零引用文件(`_syntax_probe.js` 烂在包里 109 KB)
✓ ⛔ 无「见备份 X」式死证据引用(备份已删,注释不能再说)
✓ ⛔ `SKILL.md` 末行不超 **2 KB**(当年 55 KB = 全文 66%% ⇒ 它是**台账**不是日记;⚠️ 阈值 2026-10-04 由 1 KB 上调,⛔ 守的是「不许长成流水账」这个口径、不是 339 B 这个数)
✓ ⛔ `SKILL.md` 正文无超 2 KB 的行(⛔ 当年 L6 单行 55 KB = 全文 66%%;⛔ 已标作废的段与 description 豁免)
✓ ⚠️ 具体残留:[WindowsPath('E:/ProgramData/.workbuddy/skills/session-mechanism/assets/board.html.bak-V5-20261005-1206'), WindowsPath('E:/ProgramData/.workbuddy/skills/session-mechanism/scripts/selftest.py.bak-V5-20261005-1206')]
✓ 告警文案:**必须说清后果**(⛔ 不许只说「缺了 A」) (3 项)
✗ 产物落点:**每个目标一个独立文件夹**(⛔ 代码与其他路径除外)|**报告型**
✓ 目标文件夹存在:目标-本机协作-c8154d(独立进程按 `goal.json` 算出,INBOX=E:\ProgramData\AIProject\ai1net-dsh-server\tmp\supervise-inbox)
✗ 产物型 md 都落在「目标-*/交付物」内(⛔ 代码/规则/归档除外);已在目标文件夹或交付物=130,散在别处=22 → ['接续入口_官方账号登录_20260927.md', '接续入口_手机接入_20260928.md', '接续包_IM与插件接入_20260924.md', '接续包_IM反向通道实现_20260926.md', '接续包_IM接入面收尾与插件对接答复_20260926.md']
ⓘ 报告型 ⇒ ⛔ 不计入 --verify 成败(存量问题,⛔ 与安装无关)
✓ 🔴🔴 `ensure_supervise` spawn 孙进程**必须传 `COLLABD_CONFIG`**(否则起后即退) (5 项)
✓ 🔴 钩子真接上了:工作区从 stdin.payload.cwd 取(⛔ 不是 DSH_WS_ROOT) (10 项)
✓ 🔴 T 表 §1.6:起不来先报错(10-04 用户原话「必须首先启动好在执行」) (6 项)
✓ 🔴 T 表:状态 → 我该做什么(2026-10-04 用户口述 · ⛔ 不许 AI 推断) (36 项)
✓ 📇 文档索引:改流程/改机制前**必读三篇**在第一屏 + 文档四条规则在位 (18 项)
✓ 🔴 红线:⛔ 说「会怎样」前必须取证那个后果(10-03 立 · ⛔ 10-04 又犯) (7 项)
✓ 🔴 常驻「活多久」的判据:**存活时长 = 发起会话的存活时长**(⛔ 禁编造「活不过当轮」当后果) (9 项)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture\ws\交付物\session-mechanism-副本备份-20261005-120826
② 删残留 r_stale.py
③ 覆盖 1 |补入 1
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
✅ 无漂移,⛔ 什么也不做(幂等)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture2\ws\交付物\session-mechanism-副本备份-20261005-120826
③ 覆盖 1 |补入 0
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
⛔ **白名单缺失**(副本历史里有过,现在没了):roots.env(⛔ `roots.env` 丢 ⇒ 副本会按位置推导去读写**别的仓库**)
① 已备份 ⇒ E:\ProgramData\AIProject\ai1net-dsh-server\tmp\selftest\mirror_fixture2\ws\交付物\session-mechanism-副本备份-20261005-120826_2
↺ 白名单兜底源=**历史备份** session-mechanism-副本备份-20261005-120826
③ 覆盖 0 |补入 0
④ 白名单兜底恢复 roots.env
⑤ 复核:应共享 4,逐字不一致 = 0 ✅
副本额外 = (无)✅
✅ 同步完成。⛔ 还没完 —— **必须**接着跑:
1. 副本 selftest(须 FAIL 0):python <副本>/scripts/selftest.py
2. env_check(看 deploy 段):python <副本>/scripts/hooks/_env.py <工作区>
✓ 副本同步:**残留/待补/待更新三类漂移都抓得到**,且白名单不被动(P0-51 的正解) (21 项)
✓ 副本同步:`roots.env` 白名单**只按文件名**判(⛔ 换副本不许靠「我记得跳过哪个」) (5 项)
✓ 🔴 各工作区自我建立常驻:**副本里也得找得到载体模板**(⛔ 写死包根=每区必红) (5 项)
✓ 🔴 看板渲染:**真跑 `renderProject()`**(⛔ 不是查字符串 —— 实发过 `acc is not defined`) (12 项)
✓ 🔴🔴 peer(跨工作区)格**也要认主会话**(⛔ 不许只看本看板的 `WS`) (5 项)
✓ 🔴 建目标时**顺手登记主会话**(用户原话:⛔ 不用每次会话都去声明) (8 项)
✓ 🔴🔴 keeper 生成 ps1 时 `--script` 必须填**本区发布物**(⛔ 不许照着当前这份抄) (5 项)
✓ 🔴🔴 常驻**自我繁殖**必须断:续命只许起**本区发布物**(用户「越创建越多」的真因) (6 项)
✓ 🔴🔴 一个工作区只能有一个常驻:**启动前必判 + 身份核验**(pid 会复用) (9 项)
------------------------------------------------------------------
合计:PASS 96 / FAIL 1(另有 1 条报告型,⛔ 不计入)
==================================================================
@@ -0,0 +1,66 @@
# 目标执行状态
> 🔴 本文件=**检查会话判断目标状态的唯一依据**(⛔ 别再去工作区翻文件)。
> 由**目标检查会话**(`[协作]-[目标检查]-…`)在核对后更新。
**目标**:清理过时概念 + 常驻稳定 + 执行/检查会话正常创建 + 多工作区独立运行
**类别**:会话协作自检 / 机制排查与修复 / 概念清理 / 常驻稳定 / 会话创建 / 多区独立
**本节最近更新**:2026-10-05 12:35(目标检查会话 第7棒:三路取并集复核完成 ⇒ V1–V6 全过,台账空、任务图全 done、无僵尸件 ⇒ **lifecycle 已改判「已完成」**,常驻随之优雅退出)|上一轮:2026-10-05 12:1x(执行会话 V5 转绿第 1 棒)
## 二、验收判据(值是中文写法:`过|…`/`🔴 不过|…`)
### V1 两区常驻都在跑
**结论**:过
- **实测**:本棒现读两个心跳文件 + 进程级核对 —— ai1net-dsh-server `supervise-heartbeat.json` = pid 30560 / ts_h `2026-10-05 11:31:55` / round 121 / interval 10.0;vibe-product 同名文件 = pid 60596 / ts_h `2026-10-05 11:31:55` / round 93 / interval 30.0;`tasklist /FI "PID eq …"` 两条均返回 `pythonw.exe` 且该 pid 在列(30560 → 45,780 K,60596 → 9,496 K)⇒ 判据「pid 活 ∧ 心跳新鲜」两区都成立。
### V2 执行会话能创建
**结论**:过
- **实测**:本棒在 `workbuddy.db` 的 `sessions` 表回读 —— `[协作]-[概念清理]-术语收敛第1棒` id `98fb7c55…` / status `completed` / created_at `2026-10-05 10:38:10`,是排期名(`[执行]`/`[协作]` 两级前缀)且已入库 ⇒ 排期 → 宿主拉起 → 会话入库这一段通。
### V3 检查会话能创建
**结论**:过
- **实测**:本棒现读三处 —— ① `tmp/supervise-inbox/check-agent.json` 有本轮登记条目:`round=5`、`name=[检查]-[目标检查]-ai1net-dsh-server-第5棒`、`reason=queue-empty`、`kind=目标检查`、`at=2026-10-05T11:24:25`、`fire_at=11:25:55`、`queue_pending=0`、`idle_min=20.2`;② `sessions` 表回读该检查会话 id `2cca68dd-4d45-40fd-a203-d25f0a23b4ab` / title 同名 / status `completed` / created_at `2026-10-05 11:26:24`(= fire_at 后 29 s 拉起)/ updated_at `11:28:10`;③ `collabd.parse_session_name("[检查]-[目标检查]-ai1net-dsh-server-第5棒")` = `{"role":"check","topic":"目标检查","ok":true,"form":"prefix"}`,且 `is_check_agent()` 对它返 `True`、对本棒标题返 `False` ⇒ 检查角色解析与协作角色解析互不串。
⚠️ 一处如实记录的差异:`check-agent.json` 的 `id` 字段是 `6c79dc0a-ee45-48dd-841d-5cb7c96d581a`,该值在 `sessions` 表**查不到**;它在 `automations` 表里是 `[检查]-[目标检查]-ai1net-dsh-server-第5棒` 这条**排期的 id** ⇒ 该字段登记的是排期 id,不是会话 id(不影响「链路通」这一结论,但字段语义与字段名不符,已记为待澄清项)。
⚠️ 另一处:本棒自己(`eefdc322-65dc-4cad-8b58-aafe08a214cc` / title `[协作]-[会话协作自检]-复验V3V5V6并回写目标执行状态` / status `working` / created_at `2026-10-05 11:31:11` / `is_background_automation=1`)在 `tmp/supervise-inbox/` 下 `grep -rl eefdc322` **无登记条目** ⇒ 执行会话这一侧没有与检查会话同形的登记文件,检查会话的登记载体是 `check-agent.json`。
⚠️ 按判据要求未读 `tmp/supervise-inbox/queue.json`(已退役旧投递机制遗留、内容停在过期状态)。
### V4 看板显示当前目标
**结论**:过
- **实测**:本棒 `grep -o "本机协作" tmp/supervise-inbox/board.json | wc -l` = **4** 处命中,JSON 可解析 ⇒ 当前目标标题在看板上出现。另本棒对上的目标真源是 `tmp/supervise-inbox/goal.json`(`execution_doc=目标-本机协作-3e3182/目标执行状态.md`、`topics` 六项齐全)。
### V5 自测基线全绿
**结论**:过
- **实测**:本棒现跑 `E:/ProgramData/.workbuddy/skills/session-mechanism/scripts/selftest.py`,**rc=0**,合计行原文「**合计:PASS 97 / FAIL 0**(另有 1 条报告型,⛔ 不计入)」⇒ 判据「FAIL 0」**成立**。最终读数落盘 `目标-本机协作-c8154d/selftest-V5-最终读数-20261005.out`。
- 🔴 **执行对象已改正(这是上一棒 30 条 FAIL 的真因,属「判据口径错」不是部署缺陷)**:上一棒跑的是**工作区副本** `.workbuddy/collab/selftest.py`,而 `selftest.py` L56 `HERE = Path(__file__).resolve().parent` 按**技能包布局**取文件(`board.html` 取 `HERE.parent/assets/`、`judge_audit.py` 取 `HERE/`、文档索引取 `HERE.parent/references/`)⇒ 24 条 `FileNotFoundError` + 2 条「包内缺脚本」全部是**在错的目录跑一份要求包布局的用例**。本棒取证:`deploy_code.py` 的 `DEFAULT_FILES`(L37-44)**只含 6 个 `.py`**(`collabd.py`/`goalctl.py`/`collabctl.py`/`guard.py`/`session-rules-check.py`/`init_workspace.py`),**明确不含** `selftest.py`/`board.py`/`assets/`/`references/`;且 `grep -rn selftest` 在 `collabd.py`/`guard.py`/`hooks/` 里**只命中注释与文档字符串、零执行引用** ⇒ 工作区副本本就不该有它,跑它是口径错。判据的正确执行对象=**技能包那份**。
- 🔴 **修掉的真缺陷(1 条,与 10-03「几个 tab 看起来一样」同族)**:在技能包口径下 `rc=1`、`PASS 96 / FAIL 1`,红项=「跨工作区 tab:有差异的字段必须逐个被视图取到」,内层原文「⛔ 漏了 `['tab_hot', 'tab_i', 'ws_name']`」。逐字段取证后**分开处置**(⛔ 不是一律塞豁免):
1. `ws_name` =**真缺陷,已修**。`board.html` 的 `scopeView()`(L1680)原先未取该字段,而下游 `renderProject(d)` L660 读 **`d.ws_name`**(用户要求「明确写出所属工作区,不搞『自己就不标』特例」),`d` 在 L1738 = `scopeView(d, gs[GIDX])` 的产物 ⇒ 切到别的 tab 时**静默沿用本工作区的名字**,跨 tab 显示错。修法=`scopeView()` 补 `v.ws_name=g.ws_name||d.ws_name;`。
2. `tab_hot`/`tab_i` =**后端排序键,本就不该进视图,已归位**。二者由 `board.py` L1883-1887 在 `blocks.sort(key=…)` 里当场用掉;前端对 `tab_i` 的消费点 `grep -c` = **0**,`tab_hot` 仅出现在一句解释「排序由后端做」的注释里 ⇒ 要求视图去取一个它根本不渲染的东西是判据分类错。处置=并入判据 `_IDENT` 表(L4358 旁已写明取证依据),⛔ 未删用例、未改判定逻辑。
- ✅ **变异对照自检(证明判据不是恒绿,三段闭环)**:把 `v.ws_name=g.ws_name||d.ws_name;` **注释掉**(模拟 P0-57 同族的「看着改了、其实没生效」)⇒ 判据**变红** `rc=1`、`PASS 96 / FAIL 1`,且内层**精确点名**「⛔ 漏了 `['ws_name']`」;改回 ⇒ 判据**重新变绿** `rc=0`、`PASS 97 / FAIL 0`。⇒ 判据有牙、能抓住本次这类漏取,不是恒绿。
- ⚠️ **过程中被自测抓出来的一条附带真红(已处置)**:首修后复跑时新暴露「包体卫生:⛔ 包内无 `*.bak-*` 历史备份」红 —— 是**我自己**在包内建的 2 份备份撞上的。已 `mv` 移出包外到 `tmp/v5-bak-20261005-1206/`(保留可回退,⛔ 未删),包内 `find -name "*.bak-*"` 现为 **0**。这条同时印证「包无版本控制兜底 ⇒ 包内不许长备份」这条判据本身是有牙的。
- ⓘ 唯一剩余的 `✗` 是**报告型**「产物落点:每个目标一个独立文件夹」(报根目录 22 份接续包/接续入口类 md 未落进「目标-*/交付物」)—— 按判据原文它**不计入** `--verify` 成败,⛔ 本棒未动(属产物归档口径,需单独一棒)。
- **实测**:本棒现跑 `E:/ProgramData/AIProject/ai1net-dsh-server/.workbuddy/collab/selftest.py`,**rc=1**,末尾合计行原文「**合计:PASS 67 / FAIL 30**(另有 1 条报告型,⛔ 不计入)」⇒ FAIL 30 ≠ 0 ⇒ 判据「FAIL 0」**不成立**。完整输出落盘在 `tmp/selftest-V5-20261005-1132.out`(215 行)。
### V6 多工作区独立
**结论**:过
- **实测**:本棒逐工作区读心跳与目标 —— **ai1net-dsh-server**:pid 30560、`argv0=E:\ProgramData\AIProject\ai1net-dsh-server\.workbuddy\collab\collabd.py`、`started_h=2026-10-05 11:11:53`、round 121、interval 10.0、`queue_n=1`;`goal.json` 的 `lifecycle=进行中`。**vibe-product**:pid 60596、`argv0=E:\ProgramData\AIProject\vibe-product\.workbuddy\collab\collabd.py`、`started_h=2026-10-05 10:45:53`、round 93、interval 30.0、`queue_n=3`;`goal.json` 的 `lifecycle=已完成(机器可判部分)`。
- 独立性判据(结论:**成立**):两个常驻是**两个不同 pid、不同 `argv0`、不同 `started_h`、不同 `interval`、不同 `queue_n`** 的独立进程,各自只读各自工作区的 `goal.json`;本工作区的目标在 `2026-10-05 11:02` 换过标题与判据,而 vibe-product 的常驻**至今未重启**(`started_h` 仍是 10:45:53、round 从 11:31 的读数看持续递增)、其 `goal.json` 的 mtime 仍是 `2026-10-05 01:20` ⇒ **A 工作区的常驻与目标变动没有导致 B 工作区的任何读数变化**。
- ⚠️ 本机目前只有这两个工作区装了 `.workbuddy/collab`(`ls -d E:/ProgramData/AIProject/*/.workbuddy/collab` 只命中这两个)⇒ 结论的覆盖面就是这两个区,第三个区接入时需重跑一次。
## 三、结论
- **6 条全部「过」(V1/V2/V3/V4/V5/V6),0 条「🔴 不过」,0 条「未测」** ⇒ **6 过 / 0 不过 / 0 未测**。V5 于 2026-10-05 12:0x 由本棒转绿(修前 `rc=1`/`PASS 96 / FAIL 1`,修后 `rc=0`/`PASS 97 / FAIL 0`,变异对照已闭环)。
- **目标生命周期已改判「已完成」** —— 2026-10-05 12:35:11 由目标检查会话第 7 棒执行 `collabd.py --set-life 已完成`(`goal.json` 回读确认 `lifecycle=已完成`/`lifecycle_at=2026-10-05T12:35:11`/`lifecycle_by=[检查]-[目标检查]-ai1net-dsh-server-第7棒`),⛔ 不留「进行中」空转;常驻程序随之优雅退出(pid 58860)。
判据=**三路取并集全绿**:① 台账 `tmp/supervise-inbox/tasks.json` = `{"t":{"state":"done"}}`(⛔ 无 pending/running/blocked,**无僵尸件**);② 任务图 `交付物/任务图-会话协作自检.json` 12 个节点(S1–S12,含关键路径 9 个)**全部 `status=done`**;③ 本文档 V1–V6 **6 过 / 0 不过 / 0 未测**。⚠️ 域占用读数:`ai1net-dsh-anywhere` 由 `[协作]N9复测-2248` 持有(⛔ 与本判定无关,未动)。
- **报告型红项「产物落点:每个目标一个独立文件夹」经本棒拍板:不计入目标完成度**(依据=判据原文「不计入 `--verify` 成败」),故⛔ 不因它拦下 lifecycle;但它**仍是独立待办**,需要时另起一棒处理。
- **下一步**:① 目标已完成 ⛔ 不再派协作棒;② 若要继续,**新目标须在对话里重新 declare**(⛔ 不得从目录名/旧文档猜);③ 两条待澄清项仍挂着(`check-agent.json` 的 `id` 存的是排期 id 而非会话 id;执行会话在 `tmp/supervise-inbox/` 下无同形登记条目)—— ⛔ 属机制层口径,不自行改。
- **两条待澄清项(如实记录,未自行改)**:① `check-agent.json` 的 `id` 字段存的是排期 id 而非会话 id;② 执行会话在 `tmp/supervise-inbox/` 下无同形登记条目(检查会话有 `check-agent.json`,执行会话没有对应文件)。
- ✅ **真源归属已明确(本棒已修)**:`tmp/supervise-inbox/goal.json` 的 `execution_doc` 原指向旧目标 `目标-本机协作-3e3182/目标执行状态.md`(该目标已于 10-03 标「已完成」)⇒ 本棒已改指回 **`目标-本机协作-c8154d/目标执行状态.md`**,检查会话下一棒不会再读错文档。