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
Move-only (TASK-rectification-code-split-20260926 T2/T4). No behavior, API,
copy, DB, Skill, billing or scoring change.
- route.ts: 1077 -> 152 lines; POST 927 -> 114. It builds the Supabase
clients (so the setup-failure mapping stays here) and assembles:
agent-route-request.ts (auth / product / schema / flag / Case-Session
binding), agent-route-typed-message.ts (declared-window reply, typed-answer
preflight, unfocused classification), agent-route-structured-choice.ts,
agent-route-agent-turn.ts (opening / read-only / typed agent stream and its
exit gate), agent-route-billing.ts, agent-route-support.ts (schema, one-shot
NDJSON reply, context types).
- The four mutable preflight lets (expectedWrite, collectIntent,
writeClassified, classifierDiagnostic) that crossed branches are one
turnState object; values and flow unchanged.
- Tests: whole-source contracts read tests/rectification-agent-route-surface.ts;
the typed fast-path slice is rebuilt from the new files; billing,
declared-window and structured-choice slices now call the handlers
(billing in a child process because feature-pricing imports server-only),
each with 原值/新值/原因. Route growth caps added.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
- D2: each intent-classifier attempt is capped at 10 s (same session model,
thinking untouched); a hang takes the existing retry -> classifier_unavailable
path. Success is timed too (RectificationClassifierDiagnostic).
- D3: a typed message builds the NDJSON stream first; the first line is
turn.progress "received", then the classifier and deterministic replies run
inside the stream. Preflight rejections become turn.rejected (old status,
code, message) and the client handles them like the old HTTP rejection.
Stage lines 收到,正在对照你的档案… / 正在记下这件事… / 正在重新对照盘面… /
正在准备下一个问题… are driven by existing tool events and engine calls, are
transient (live row only) and never persisted. VOICE / DESIGN updated.
- D4: RectificationRunDiagnostic records per-step start/end, provider token
usage incl. reasoning tokens, classifier timing and per-engine-call
durations (AsyncLocalStorage scope per turn); RectificationTurnDiagnostic
for deterministic turns. No user text, birth data or model text.
- D5: /v5/versions memo (30 s, complete identities only, per transport); the
exit gate skips its second persistNextInterviewIfIdle when the run's own
call found the next focus already active (provably identical).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8