session-mechanism:闸④ 不再被周期排期卡死 + --report 漏 id 当场拒收

① 闸④ 收窄 recurring(用户选 A 案)
   改 ws_pending_schedules():schedule_type='recurring' 的行一律不算「待执行」,
   once 的过期排除与拦截照旧。
   症状=周期排期永远有下一次 ⇒ 拿「在册 + 没跑过」判它恒真 ⇒ 闸④ 恒拦
   ⇒ 目标检查会话一条都建不出来(aigc-idea-impression 被「AI变现日报 每日 06:00」
   挡了一整天,日志每 20 秒重复「还有 1 条待执行排期 ⇒ 不建」)。
   变异对照:同一工作区、同一时刻,旧版返回 ['AI变现日报 · 每日自动生成']、新版返回 []。

② --report 拒收闸(用户选 B 案)
   --report 后面必须跟真的需求 id;id 为空或以 -- 开头 ⇒ 打用法行 + 退出码 2,台账一字不写。
   症状=漏 id 时 _arg("--report") 取到的是下一个 token(--state)
   ⇒ 台账多一条键名写坏的记录,还被算进队列计数(本区 queue_n 2→3;vibe-product 也有一条)。
   变异对照:把闸删掉 ⇒ 同一条命令 rc=0 且真写出 "--state";加回去 ⇒ rc=2 且台账为空。

自检:闸④ 用例 5 → 6 项;新增「拒收闸」用例 6 项(含正例对照,防「未找到部署配置 ⇒ 拒跑」
把 rc=2 混成假绿);全量 PASS 110 / FAIL 0。

文档:references/pitfalls.md —— P0-65 补 recurring 口径(含实测症状与反例库);
新增 P0-96(漏写 --report id 的静默污染 + 判据自身两处假绿坑)。
This commit is contained in:
admin committed 2026-10-12 09:50:10 +08:00
1 parent e12e985808
commit 24040ee171
3 files changed
+156 -3

No files matched your search

+35
View File
@@ -2000,6 +2000,18 @@ INBOX = '…\ai1net-dsh-server\tmp\supervise-inbox'
⇒ 它会**永远**把闸④ 卡住 ⇒ 本工作区**再也建不出检查会话**(静默、无报错)。
✅ 两种"不会再触发"都判:**(a)** `next_run_at` 已过 15 分钟宽限;**(b)** `next_run_at` 被清成 NULL。
⚠️ **只对 `once` 生效**(`recurring` 永远会再触发,⛔ 不按过期排除)。
- 🔴🔴 **2026-10-12 补:`recurring`(周期排期)整体不算"待执行"**(用户当日选 A 案,已改 `collabd.py`)。
**症状**:周期排期**永远有下一次** ⇒ 拿"在册 + `last_run_at` 为空"去判它**恒真** ⇒ 闸④ **恒拦**
⇒ **目标检查会话一条都建不出来**。
**实测**(`aigc-idea-impression`,10-11 → 10-12):被「AI变现日报 · 每日自动生成」(`FREQ=DAILY;BYHOUR=6`)
挡了整整一天,常驻日志每 20 秒重复一行「目标检查:⚠️ 本工作区还有 1 条待执行排期 ⇒ 不建」;
后果是**执行轮有人干、核目标那一步没人干**。
**为什么排除是合理的**:闸④ 要防的是「**马上要开工**时重复派活」;周期排期是按日历重复的,
**不表示有人正要干这件活** —— 它到点自己开一条会话,检查会话顶多多跑一轮,代价远小于"永远不核目标"。
**边界**:只排除 `recurring`,`once` 的拦截照留;只动**本工作区**(`_same_ws` 已命中)⇒ 别的工作区不受影响。
**自检**:`selftest.py` 用例「闸④:排除**已过期的一次性**排期」现为 **6 项**(新增第 ⑤ 项验 `recurring` 排除)。
⚠️ 变更前先跑**变异对照**:同一工作区、同一时刻,旧版 `ws_pending_schedules()` 返回
`['AI变现日报 · 每日自动生成']`,新版返回 `[]` —— 证明是这次改动在起作用,不是"本来就空"。
- **实测取证(2026-10-05 只读)**:闸④ 对 `selftest` 工作区跳过 **11 条**、`vibe-product` 跳过 **1 条**,
全部是 `next_run_at=NULL(已消费)` 这一类 —— 正是 (b)。若不跳过,这两个工作区**各自永远卡死**。
- 🔴 **已知隐患(未修,待拍板)**:工作区判据是 **子串匹配** `p.lower() in _s.lower()`(第 ~4464 行),
@@ -3726,3 +3738,26 @@ var r = el.getBoundingClientRect();
> **改判据的核心动作不是"换个更对的比法",是"再破坏一次看它会不会喊"。**
> 变异对照不做 ⇒ 你的"修复"很可能只是把**假红**换成了**恒绿**。
---
## P0-96 🔴🔴 **漏写 `--report` 的需求 id ⇒ 静默往台账写一条坏记录,还会被算进队列计数**(★ 2026-10-12 实测,本区 + `vibe-product` 都中过)
- **它长什么样**:收报写成 `--report --state done --artifact …`(**漏了 id**)——
看着像正常命令,实际 `_arg("--report")` 取到的是**下一个 token**,也就是 `--state`。
- **后果(两层,第二层更狠)**:
① 台账 `tasks.json` 里多出一条**键名写坏**的记录(键=`"--state"`)——
命令回显是「OK 已上报」,**零报错**;
② 它**被算进队列计数**(本区实测 `queue_n` 2 → 3;`vibe-product` 的 `q_sig` 里也有一条 `--state=done`)。
若落成 `running`/`blocked` 态 ⇒ 闸① 误判「有活在跑」⇒ 去建结果检查会话 ⇒ 查一个不存在的东西。
- **✅ 已修**(2026-10-12 用户选 B 案):`--report` 分支加**拒收闸** ——
id 为空或以 `--` 开头 ⇒ 打用法行 + **退出码 2**,台账**一个字都不写**。
- **变异对照(做过的,不是推理)**:把拒收闸从副本里删掉 ⇒ 同一条命令 **rc=0** 且台账真写出 `"--state"`;加回去 ⇒ **rc=2** 且台账为空。
- **判据自身的坑(两处,都会造成假绿)**:
① **正例探针⛔不能指向真工作区** —— 我当场就是这么往真台账里敲进一条 `ZZZ-假id`(`running`)的,只能手工撤回;
⇒ 一律 `COLLABD_WORKSPACE=<临时目录>` 起子进程。
② **临时工作区必须自带 `collabd.config.json`** —— 否则 `collabd.py` 先「未找到部署配置 ⇒ 拒跑」并返回 **rc=2** ⇒
负例断言**因为错的理由**变绿。⇒ 夹具现造最小配置,并加一条**正例**(形态正确的 id ⇒ rc=0)当对照。
- **留痕口径**:本次**只加拒收闸**,既有坏行**不动**(用户选 B 案=台账留痕优先)。
- 🔴 **写工具的红线**:**凡是"看着成功、其实写坏了"的通道,优先加"当场拒收"** ——
报错比静默污染便宜得多;静默污染要等到有人去读那条记录才发现,而那时原因已经不在现场了。