fix(engine): 那面「打不回」的旗在容器里被扔了 —— 手写字段清单第三次丢值,改成整包转交

用户:「评审放行与落账确认这一步的验收卡怎么还有重做??你没改上吗?」——
库里的卡确实没有那面旗:装配层算对了、release 转对了、契约也声明了,而**容器那个显式对象**
只转它点到名的那几样,`redoable` 没被点名就在这最后一关静默落地(编译不报、运行时无声)。

同一处已经吃过三次:①fields 写死成 [](验收报告只能看不能改)②blocks 漏一行(卡面块恒空)
③这次。那几行旁边就写着两条「少写一行就静默落地」的警告 —— 措辞治不了的结构治:
context 三样拆出去、**其余整包转交**,以后端口新增可选字段不改这里也到得了。
断言钉在最末端:试跑观测面的卡带上 redoable,e2e 断言「一路到了卡上」。

同批修另一种时序的卡死(同一夜第二次,停掉了一整个 e2e 案例):
**决策卡的回传不发事件、只调 wake**,而 wake 只翻停着的单子 —— 卡刚发出那一刻这一拍还在
running,它空转了一次;随后这一拍把任务 park 回 awaiting,再没有第三样东西会来叫
(实测:卡 02:06:13.250 发出、219ms 后被答,这一拍 .636 才收尾,停到 20 分钟超时)。
修:配方发卡收尾前再看一眼刚发的那张卡还在不在等 —— 已经答了就照实说「还在跑」;
只认这一张卡,别的「等外部回音」照旧是等,不会空转成热循环。
假端口同批改老实:发出去的卡默认就在等(从前发完卡还回「一张待答的都没有」)。

验收:e2e w05 5/5 released、被拒 0,案例 0 四条断言全绿(不摆重做 / 对话区说了话 /
点名要的结论落下去了 / 只动被点名的行);两处变异验证;契约变更 api-report 已刷新。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
xcs
2026-09-01 02:36:53 +08:00
co-authored by Claude Fable 5
parent e474275b28
commit 3c563525f1
8 changed files with 159 additions and 24 deletions
@@ -2271,7 +2271,29 @@ export function createTurnRunner(deps: TurnRunnerDeps): LoopEngineService {
if (current.view !== undefined && current.view !== '') {
await showView(taskId, current.view, touched, current.view);
}
return { runtime: touched, enabled: stateEnabled, navigation: { kind: 'converged' }, status: 'awaiting' };
/*
* **人答得比这一拍收尾还快,就别报「等人」**(2026-09-01 实测两次撞停,第二次卡了一整例:
* 卡 02:06:13.250 发出、**219ms 后**就被答了,而这一拍 .636 才收尾)。
*
* 为什么会没人叫醒:**决策卡的回传不发事件,只调 `wake`** —— 而 `wake` 只翻停着的单子,
* 那一刻这一拍还在 `running`,它空转了一次;随后这一拍把任务 park 回 `awaiting-event`,
* 再没有第三样东西会来叫(工单回传那一路还有人事件兜底,决策卡这一路一样都没有)。
*
* 所以收尾前再看一眼**刚发的这张卡还在不在等**:已经答了就照实说「还在跑」,
* 推进器下一轮接着处理那份答复。**只认这一张卡** —— 别的「等外部回音」照旧是等,
* 不会因此空转成热循环。
*/
const stillPending = await deps.cards.unanswered(taskId);
const answeredAlready = !stillPending.some((c) => c.id === auto.issuedCardId);
if (answeredAlready) {
await deps.memory.append({
taskId,
kind: 'observation',
title: '这张卡刚发出去就被答了 —— 这一拍不算等人,接着跑',
detail: { cardId: auto.issuedCardId, item: current.item, internal: true },
});
}
return { runtime: touched, enabled: stateEnabled, navigation: { kind: 'converged' }, status: answeredAlready ? 'running' : 'awaiting' };
}
if (auto.wrote > 0 || auto.dropped > 0) {
/* 写过东西:重新求一遍 doneWhen —— 这一步可能已经办完了 */