refactor(rectification): split runV9AgentTurn into prepare / attempt / retry / finish

Move-only (TASK-rectification-code-split-20260926 T3/T4). No behavior,
receipt, billing, Skill or scoring change.

- agent-run.ts: 1400 -> 135 lines; runV9AgentTurn 1046 -> 25 lines, no
  nested functions. It keeps the public types, the budget constants and the
  phase order: agent-run-prepare.ts (reliability, session, year re-ask, Skill
  identity, delivered guard, reserve, turn row / replay),
  agent-run-retry.ts (attempt loop), agent-run-attempt.ts (the old nested
  streamAttempt), agent-run-finish.ts (billing settle, receipts, interview,
  finalize), agent-run-support.ts (outcome types, retry classification, turn
  receipt writers), agent-run-messages.ts (buildAgentMessages /
  buildOpeningBrief, re-exported).
- One token changed with the move: the attempt passes its own
  `previousErrorCode` argument to buildAgentMessages instead of reading the
  enclosing `lastAttemptError`; the loop passes that same value (clears the
  old unused-parameter warning).
- Tests: whole-source contracts read tests/rectification-agent-run-surface.ts;
  behavioral runV9AgentTurn tests unchanged. agent-run growth caps added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
This commit is contained in:
Jesse_Chen
2026-09-26 19:52:51 +08:00
co-authored by Claude Opus 5.5
parent eb773f1299
commit a00c40d4b8
25 changed files with 1665 additions and 1332 deletions
@@ -1,5 +1,4 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import { OPEN_ENGINE_CAPABILITY_CEILING } from "./rectification-v9-test-support.ts";
@@ -34,6 +33,7 @@ import {
} from "./rectification-v9-test-support.ts";
import { rectificationChatSurface } from "./rectification-chat-surface.ts";
import { rectificationAgentRouteSurface, rectificationTypedMessageFastPath } from "./rectification-agent-route-surface.ts";
import { rectificationAgentRunSurface } from "./rectification-agent-run-surface.ts";
const STYLE_OPTIONS = [
{ label: "明确发生且时间吻合", answer_class: "yes" as const },
@@ -828,7 +828,8 @@ test("idle persist on the covered-domain accident delivers adopt and writes no f
});
test("agent-run still writes the exhaustion gate when idle persist returns terminalNote", () => {
const agent = readFileSync(new URL("../src/lib/rectification-agentic/v9/agent-run.ts", import.meta.url), "utf8");
// 原值: 读 lib/rectification-agentic/v9/agent-run.ts 单文件。新值: rectificationAgentRunSurface(agent-run.ts + 拆出的 agent-run-*.ts,见 rectification-agent-run-surface.ts)。原因: TASK-rectification-code-split-20260926 只搬不改,整文件断言跟着代码走;切片断言另行改写。
const agent = rectificationAgentRunSurface;
// 原值: 读 rectification-agentic-chat.tsx 单文件。新值: rectificationChatSurface(容器 + 拆出的 hook / 参数函数 / 块,见 rectification-chat-surface.ts)。原因: TASK-rectification-code-split-20260926 只搬不改,整文件断言跟着代码走;切片断言另行改为调用函数。
const chat = rectificationChatSurface;
assert.match(agent, /interviewIdle\.terminalNote && interviewIdle\.hostNarration/);