Files
Jyotisha/frontend/tests/rectification-agent-route-fixtures.ts
T
Jesse_ChenandClaude Opus 5.5 eb773f1299 refactor(rectification): split POST /api/rectification/agent into branch handlers
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
2026-09-26 19:40:07 +08:00

72 lines
2.5 KiB
TypeScript

/**
* A verified route context for calling the branch handlers split out of
* POST /api/rectification/agent (TASK-rectification-code-split-20260926)
* directly, with a recording persistence client instead of Supabase.
*/
import type {
RectificationAgentRequest,
RectificationAgentRouteContext,
} from "../src/lib/rectification-agentic/v9/agent-route-support.ts";
export const ROUTE_CASE_ID = "44444444-4444-4444-8444-444444444444";
export const ROUTE_SESSION_ID = "33333333-3333-4333-8333-333333333333";
export const ROUTE_REQUEST_ID = "55555555-5555-4555-8555-555555555555";
export const ROUTE_TURN_ID = "66666666-6666-4666-8666-666666666666";
export type RecordedRpc = Readonly<{ fn: string; args: Record<string, unknown> }>;
export function routeContextFixture(
data: Partial<RectificationAgentRequest>,
rpcData: (fn: string) => unknown = () => ({ turn_id: ROUTE_TURN_ID, idempotent: false }),
) {
const rpcCalls: RecordedRpc[] = [];
const accounting = {
rpc: async (fn: string, args: Record<string, unknown> = {}) => {
rpcCalls.push({ fn, args });
return { data: rpcData(fn), error: null };
},
from: () => {
throw new Error("no table access expected");
},
};
const request: RectificationAgentRequest = {
caseId: ROUTE_CASE_ID,
sessionId: ROUTE_SESSION_ID,
requestId: ROUTE_REQUEST_ID,
action: "message",
...data,
};
const context = {
request: new Request("https://staging.jyotisha.chat/api/rectification/agent", { method: "POST" }),
turnStartedAt: Date.now(),
supabase: {},
accounting,
userId: "77777777-7777-4777-8777-777777777777",
parsed: { data: request },
caseId: request.caseId,
sessionId: request.sessionId,
requestId: request.requestId,
action: request.action,
isStructuredChoice: request.action === "answer_choice"
|| request.action === "stop_and_review"
|| request.action === "skip_probe",
caseStatus: "collecting_evidence",
skillVersion: "",
chatSession: {
id: request.sessionId,
session_type: "birth_time_rectification",
model_id: "model-a",
model_config_version: 1,
agentic_rectification_case_id: request.caseId,
},
} as unknown as RectificationAgentRouteContext;
return { context, rpcCalls };
}
export async function ndjsonEvents(response: Response): Promise<Array<Record<string, unknown>>> {
return (await response.text())
.split("\n")
.filter((line) => line.trim())
.map((line) => JSON.parse(line) as Record<string, unknown>);
}