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
@@ -4693,6 +4693,14 @@ def ws_pending_schedules(exclude: str = "") -> list:
② `cwds` 命中本工作区(⛔ 两种斜杠形态都试 —— 同 `_all_sessions_idle` 的教训:
只试一种 ⇒ 匹配 0 行 ⇒ **恒判"没排期"⇒ 闸失效**);
③ **还没跑过**(`last_run_at is null or last_run_at=0`)—— 跑过的一次性排期**不再算**。
🔴🔴 **2026-10-12 收窄:`recurring`(周期排期)一律不算"待执行"**(用户当日选 A 案)。
· 症状:周期排期**永远有下一次** ⇒ 拿"在册 + 没跑过"去判它**恒真** ⇒ 闸④ 恒拦
⇒ **目标检查会话一条都建不出来**(本区 10-11 → 10-12 实测:被「AI变现日报 每日 06:00」
挡了整整一天,日志每 20 秒重复一行「还有 1 条待执行排期 ⇒ 不建」)。
· 反例库(为什么可以排除):闸④ 要防的是「**马上要开工**时重复派活」——
周期排期是按日历重复的,**不表示有人正要干这件活**;它到点会自己开一条会话,
检查会话顶多多跑一轮,代价比"永远不核目标"轻得多。
· 边界:只排除本工作区(`_same_ws` 已在上面命中)⇒ 别的工作区不受影响。
⚠️ `next_run_at` **故意不看**:⛔ 一条 `next_run_at` 已过期但仍 ACTIVE 的一次性排期
(实测本工作区有 3 条,其中 2 条 `next_run_at=None`)**仍然会被人点开**(`automation_update` 手动起)
⇒ 用 `next_run_at` 当"待执行"会漏。判据取「**在册 + 没跑过**」这个更宽的口径。
@@ -4716,6 +4724,7 @@ def ws_pending_schedules(exclude: str = "") -> list:
# ⛔ 宽限期内**仍算待执行**(那正是"马上要开"的情形,闸④ 该拦)。
_STALE_MS = 15 * 60 * 1000
_now_ms = int(time.time() * 1000)
_rec = [] # 本轮跳过的周期排期(只为记一条日志,⛔ 不进 out)
for _nm, _cd, _st, _na in rows:
_s = str(_cd or "").strip()
if not _s:
@@ -4734,6 +4743,13 @@ def ws_pending_schedules(exclude: str = "") -> list:
# 📌 风险登记:若存在"建了但 `next_run_at` 就是 NULL"的 `once` 排期,会被误排除;
# 但 `create_check_schedule()` 的**硬规则第一条**就是 `next_run_at` 必须
# 是有限数值 ⇒ 机制自己建的排期不会命中该风险。
# 🔴🔴 2026-10-12(用户选 A 案):**周期排期不算"待执行"**
# —— 它永远有下一次,拿"在册 + 没跑过"判它恒真 ⇒ 闸④ 恒拦 ⇒
# 目标检查会话一条都建不出来(本区被「AI变现日报 每日 06:00」挡了一整天)。
# 依据与反例库见函数 docstring;⛔ 只排除 `recurring`,`once` 的拦截照留。
if str(_st or "").lower() == "recurring":
_rec.append(str(_nm))
continue
if str(_st or "").lower() == "once":
_gone = (not _na) # (b) 已被消费 ⇒ 到点时间被清空
if not _gone:
@@ -4746,6 +4762,9 @@ def ws_pending_schedules(exclude: str = "") -> list:
% _nm)
continue
out.append(str(_nm))
if _rec:
log("闸④:跳过周期排期(`recurring` 会反复触发 ⇒ 不算『有人正要干这件活』)|%s"
% _rec[:3])
except Exception as e:
log("ws_pending_schedules 读库失败(⇒ 按有排期处理,不建) %s" % e)
return ["<读不到排期表>"]
@@ -6510,6 +6529,22 @@ def main() -> int:
def _arg(k, dv=""):
return sys.argv[sys.argv.index(k) + 1] if (k in sys.argv and sys.argv.index(k) + 1 < len(sys.argv)) else dv
# ── 🔴🔴 拒收闸(2026-10-12 用户选 B 案):`--report` 后面**必须跟一个真的需求 id** ──
# 症状(实测):写成 `--report --state done --artifact …`(**漏了 id**)⇒
# `_arg("--report")` 取到的是**下一个 token**(实为 `--state`)⇒
# 台账里多出一条**键名写坏**的记录,还会**被算进队列计数**
# (本区实测 `queue_n` 2 → 3;`vibe-product` 也有一条同型)。
# ⇒ 这类污染是静默的:命令看着像成功、台账看着像有记录,事后极难发现。
# ⇒ 处置=**当面报错 + 给用法行 + 退出码 2**,⛔ 不写台账。
_rid = _arg("--report")
if (not _rid) or _rid.startswith("--"):
print("✗ `--report` 后面必须跟**需求 id**(漏写会往台账写一条键名写坏的记录,"
"还会被算进队列计数)。\n"
" 用法:--report <需求id> --state pending|running|done|blocked "
"[--by 会话名] [--artifact 产物] [--reason 原因] [--line 线]\n"
" 实得:--report %s" % (_rid or "<空>"))
return 2
rc = task_report(_arg("--report"), _arg("--state", "running"), _arg("--by"),
_arg("--artifact"), _arg("--reason"), _arg("--line"))
if rc == 0: # 上报**只写台账**(⛔ 不投递)——