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
Staging gate 2558 failed because leftover tests still expected D9/D10 or leftover collect after the pool emptied. Discriminate sessions still deliver; dated precision cards still ask.
Co-authored-by: Cursor <cursoragent@cursor.com>
Stop domain-wheel collecting and age-band years in prompts. Ask until the training gate, then discriminate until convergence, then deliver a range plus a concrete follow-up. Reserve holdout only with four dated events.
Co-authored-by: Cursor <cursoragent@cursor.com>
When coverage still blocks adopt and no renderable discriminator remains, narrate the numeric range and persist a spoken collect instead of promising a time card that cannot be clicked. Recompute probe information gain on active candidates and drop zero-split probes explicitly.
Co-authored-by: Cursor <cursoragent@cursor.com>
Only sign-bound varga_style questions may omit a concrete period. Remaining-layer existence and quality probes now drop as yearless_ungrounded_contrast instead of scoring by group order.
Co-authored-by: Cursor <cursoragent@cursor.com>
Occupation answers were stored as career, so coverage never closed, yearless
cards never fired, and the decision layer suppressed an engine-allowed range.
Normalize occupation-collect writes, allow yearless cards once training is
open, offer a range when no distinguish card remains, and align the public
house table to the representative minute.
Co-authored-by: Cursor <cursoragent@cursor.com>
Spoken collect prompts lived only in GET current_question. The chat never
parsed that field, Agent projections returned null after evidence writes,
and active_focus followups collapsed the questionId. Render the parsed
prompt, keep choiceReady on real cards, and give collect focuses a stable
domain-scoped id.
Co-authored-by: Cursor <cursoragent@cursor.com>
A spoken no neither scored nor declined coverage, so relatives never closed and free-text turns left current_question null. Prefer a same-domain yearless scoring card before an unscoreable collect, resolve explicit collect denials as declined, and persist the next followup after an idle agent turn.
Co-authored-by: Cursor <cursoragent@cursor.com>
Collect focus was leaking discriminator probes into the agent prompt and
inheriting choice identity. Mark spoken questions, hide current_probe
unless a real choice card exists, strip fallback identity, log persist
failures, and align the decision probe with the plan including birthDate.
Co-authored-by: Cursor <cursoragent@cursor.com>
Decision and question ranking now share contrast option completion, so a
missing style card cannot deadlock the interview with a dead-end reply.
Co-authored-by: Cursor <cursoragent@cursor.com>