Skip to content

Releases

v0.39.0 — 看门狗硬结算:到点必落账

Choose a tag to compare

@shenhuanageshei shenhuanageshei released this 22 Oct 09:14

[0.39.0] — 2026-10-22

一句话(人话):以前「看门狗」到点只是朝子代理喊一声「停」,然后继续干等——平台不理它,任务就永远不落账(实测有一轮会诊跑到 88.8 分钟,最后靠人手动停)。这版把「到点」变成「到点必落账」:到点先喊停,再等 60 秒;还不回就强制结算,并如实写「它没响应,可能还在后台跑」。

【计数行】:node --test 678/678(基线 660 + 本批 18:consult 11→15 · silence-watchdog 17→19 · 新增 settle-deadline 9 · 新增 escalate 3)。

一、为什么做(人话)

会诊 / eng_coder / escalate 的超时,一直只做一件事:ctrl.abort()。但「发了中止」不等于「对方停了」——平台子代理完全可以既不 resolve 也不 reject。旧代码随后是一句裸 await run.result,于是整轮永远不结算:会诊的 pending 计数不归零、其余模型已经回来的回复也交付不出去;账本里留下 10 条只有 started、没有结算的记录,#108 更是跑满 88.8 分钟直到人工 stop。

二、你会看到什么

· 预算到点后最多再等 60 秒,然后就落账——不再出现「看门狗明明 30 分钟,任务却跑了一个多小时」。
· 强制结算的文案会写明「子代理未响应 abort · 插件无法终止· 它可能仍在后台运行」——不再声称「已终止」。
· 同轮其它模型的真实回复照常交付(先到者赢,不被强制结算挤掉);会被强制结算的那一路显示「无回复 / 超时」。

三、改了什么(技术面)

位置 改动
lib/settle-deadline.mjs(新) 宽限截止叶子模块:FORCED_SETTLE_GRACE_MS=60000 · createForcedSettle(未武装永不决议 / 武装幂等 / disarm 幂等 / unref)· raceForced(判据取 race 胜者;非 thenable 走强制分支的 fail-safe)· FORCED_SETTLE_NOTE
lib/consult.mjs · lib/eng.mjs · lib/escalate.mjs 五个等待点全部 await raceForced(...);六个既有中止回调各恰一次 armAfterAbort()(不新增中止写点);finally 统一 disarm(),强制路径只 fire-and-forget dispose
lib/consult.mjs 账本 settled 事件加性字段 forced:true(仅强制路径)
lib/eng.mjs · lib/escalate.mjs 同步路径强制分支改用诚实文案,旧的「超限任务被终止」只留在非强制分支(AC-2:非强制逐字不动)
test/ 新增 settle-deadline(9) 与 escalate(3);consult 的批 42 腿拆成四个独立用例(AC-1 / AC-3 多模型 / AC-12 / AC-5);silence-watchdog +2;4 条恒真断言改为观测真实事实;两条「退化后挂死」的腿加上界

四、过程与诚实清单

· 设计评审 2 轮(FAIL → PASS):轮 1 抓出 1 个 🔴(escalate 与 eng 同步零行为级验收 + 锚 A-1 在零调用点时空洞成立)与 3 🟡 / 5 🔵,九条全改;轮 2 通过并签发 design token。
· 分歧审计(只读子代理 + %TEMP% 变异实证)另抓出 5 条:强制分支文案自相矛盾(F1)· 锚 A-4 未达成(三条 AC 挤在同一个 test())· 导出面超 FR-1 · §6.2 判据与实现不同形 · 三条中止面不武装。前两条进代码修复轮,后三条写进设计档。
· 首轮交付红了一条:会诊夹具 TIMEOUT=7ms 比快行回复 10ms 还短,两个看门狗都在真实时钟上先到点 ⇒ 断言到 2。定位为夹具缺陷(把 7 改成 60 即全绿、实现一字不改),修复轮把四条腿统一成「先 clearTimeout 再手动点火」。
· 交付代码评审 VERDICT: PASS(0 🔴 / 1 🟡 / 2 🔵):两条 🔵(同步路径 spawn 失败漏 disarm() · 后台 catch 信封漏 forcedNote())已由主代理按评估的「评审后小修」权限补上;🟡 即本条目(CHANGELOG 收口)。
· 同期 docs 提交(上一 tag 以来、无代码变更):平台兼容性矩阵(v0.33.0 为 DSH peer 断点)· tag 补打交接记录。
· 如实边界:① 平台没有终止子代理的接口——强制结算只保证「落账」,不保证「真的停了」,文案已如实写明;② 宿主 job_kill / consult_stop / 父 signal 三条中止面不武装宽限(设计档 §九 已登记),它们只负责中止、不负责结算;③ 宽限固定 60s,不做用户可配(D1)。

真机验证(2026-10-22 22:00 前后 · 受控)

  • 手法:临时把 consultTimeoutMs 设为 30000,只起 1 个模型并指示它先用 run_code 睡 600s(人为制造「abort 之后不 settle」的形态)。
  • 实测:台账 started → settled = 90,007 ms(30s 预算 + 60s 宽限),settled 事件带 forced:true,digest 文案含「未响应 abort」且不含「被终止」。
  • 验证后配置已还原 1800000;纪要见 docs/consult-minutes/2026-10-22-consult-126-minutes.md。
  • 边界不变:平台没有终止子代理的接口,本机制只保证「落账」,不保证「真停」。