Archived
fix(loop-engine): 配方 submit 抛错不再让回合崩,重做闸也认配方的写
两处,缺一不可 —— 它们合起来是一个必然发生的无限热循环: ① 配方那一路的 `raiseAcceptance` 从前是**裸着**调的。而 `engine.advance` 不捕获、 `task-service.tick` 也不捕获(且 `addConsumption` 排在 advance 之后,一步都不记)、 `task-advancer` 只写 stderr 就 break,任务留在 `running` —— 下一个 interval 再来一遍: 不烧预算、不换状态、界面纹丝不动。:1738 模型判齐那处早就包着 try/catch, 注释白纸黑字写着理由「推进器会一遍遍重来,每遍再撞一次同一道门」。 现在同款:拒绝 + 留痕 + status running。 ② 而它**必然**抛:重做闸(2026-08-23)判「打回之后台账动过没有」只认 `kind:'action'`, 那是模型 write/drop 的痕;配方的写留痕是 `observation` + `detail.auto` + `detail.ledger`。 于是配方改了台账闸也看不见 → 抛。软化那一段靠 `refusedBefore`(模型路径 catch 写的痕), 配方路径从前没有 catch,那条痕永远不写 —— **这堵墙对配方是永远开不了的**。 3 测(拒回 running / 拒过一次再提就放行 / 配方的写解得开闸),两处各做过变异验证。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LKMZDwMbyKzjw6Hembwvet
This commit is contained in:
@@ -1533,7 +1533,17 @@ export function createTurnRunner(deps: TurnRunnerDeps): LoopEngineService {
|
||||
for (const [at, entry] of window.entries()) if (entry.title.startsWith(REDO_MARK)) lastRedo = at;
|
||||
if (lastRedo >= 0) {
|
||||
const after = window.slice(lastRedo + 1);
|
||||
const revised = after.some((e) => e.kind === 'action' && typeof e.detail?.['ledger'] === 'string');
|
||||
/*
|
||||
* **配方写下的那一笔也算「改过台账」**(2026-08-29 终审 C3)。
|
||||
* `kind: 'action'` 只有模型的 write / drop 才写;配方的写留痕是
|
||||
* `kind: 'observation'` + `detail.auto` + `detail.ledger`(见 auto-runner 的 project 分支)。
|
||||
* 只认 action 的话,一个全 auto 的放行步在被打回之后**改了台账这道闸也看不见** ——
|
||||
* 每一拍都抛,而下面那条软化路(`refusedBefore`)靠的是模型路径 catch 里写的痕,
|
||||
* 配方路径从前没有 catch,那条痕永远不写:**这堵墙对配方是永远开不了的**。
|
||||
*/
|
||||
const revised = after.some(
|
||||
(e) => (e.kind === 'action' || typeof e.detail?.['auto'] === 'string') && typeof e.detail?.['ledger'] === 'string',
|
||||
);
|
||||
const refusedBefore = after.some((e) => e.kind === 'result' && e.title.includes(REFUSE_MARK));
|
||||
if (!revised && !refusedBefore) {
|
||||
throw new Error(
|
||||
@@ -1992,8 +2002,27 @@ export function createTurnRunner(deps: TurnRunnerDeps): LoopEngineService {
|
||||
return { runtime: stateRuntime, enabled: stateEnabled, navigation: { kind: 'converged' }, status: 'awaiting' };
|
||||
}
|
||||
if (auto.submit !== undefined) {
|
||||
const raised = await raiseAcceptance(taskId, stateRuntime, auto.submit.rationale);
|
||||
return { ...raised, enabled: stateEnabled, navigation: { kind: 'converged' }, status: 'awaiting' };
|
||||
/*
|
||||
* **抛了不能让回合崩**(2026-08-29 终审 C3)—— 与 :1738 模型判齐那处同一条理由,
|
||||
* 那儿的注释白纸黑字写着:「推进器会一遍遍重来,每遍再撞一次同一道门」。
|
||||
* 而这一处从前是**裸着**的:`engine.advance` 不捕获、`task-service.tick` 也不捕获
|
||||
* 且 `addConsumption` 排在 advance 之后(一步都不记)、`task-advancer` 只写 stderr 就 break,
|
||||
* 任务留在 `running` —— 下一个 interval 再来一遍:**无限热循环,不烧预算、不换状态、界面纹丝不动**。
|
||||
* 处置与模型路径一致:拒绝 + 留痕(那条痕同时是重做闸的解锁凭据)+ 这一拍到此为止。
|
||||
*/
|
||||
try {
|
||||
const raised = await raiseAcceptance(taskId, stateRuntime, auto.submit.rationale);
|
||||
return { ...raised, enabled: stateEnabled, navigation: { kind: 'converged' }, status: 'awaiting' };
|
||||
} catch (error) {
|
||||
const reason = error instanceof Error ? error.message : String(error);
|
||||
await deps.memory.append({
|
||||
taskId,
|
||||
kind: 'result',
|
||||
title: `提交放行被拒:${reason}`,
|
||||
detail: { auto: current.item, hint: '配方的 submit 没过落地预检 —— 按理由补齐必交付物或修正台账,下一拍再提交' },
|
||||
});
|
||||
return { runtime: stateRuntime, enabled: stateEnabled, navigation: { kind: 'converged' }, status: 'running' };
|
||||
}
|
||||
}
|
||||
if (auto.issuedCardId !== undefined) {
|
||||
/* 卡发出去了 = 这一步真动过世界 —— 标 worldTouched,自动收步那道门才诚实 */
|
||||
|
||||
Reference in New Issue
Block a user