fix(rectification): dedupe post-adopt verify and skip this probe only
Independent Staging Quality Gate / validate (push) Successful in 14m31s
Independent Staging Quality Gate / publish (push) Successful in 1m59s

Adopted reverse-verify repeated already-asked collect stems, treated 「这题跳过」 as stopping the case, and promised holdout/OOS checks that never ran. Collect spoken stems no longer prefix a year.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-04 21:51:59 +08:00
co-authored by Cursor
parent 6b038e6d0d
commit d4627a5019
36 changed files with 1065 additions and 91 deletions
@@ -18,7 +18,7 @@ import {
} from "@/lib/rectification-agentic/v9/answer-choice";
import { createAdoptNarrationWriter } from "@/lib/rectification-agentic/v9/adopt-narration-agent";
import { mapRectificationRpcError } from "@/lib/rectification-agentic/v9/case-service";
import { CHOICE_ACTION, STOP_ACTION } from "@/lib/rectification-agentic/v9/choice-action";
import { CHOICE_ACTION, SKIP_PROBE_ACTION, STOP_ACTION } from "@/lib/rectification-agentic/v9/choice-action";
import { runV9AgentTurn, type V9RunBilling } from "@/lib/rectification-agentic/v9/agent-run";
import { safePublicEvent } from "@/lib/rectification-agentic/v9/stream-mapping";
import { RECTIFICATION_SKILL_NAME, RECTIFICATION_SKILL_VERSION } from "@/lib/rectification-agentic/v9/case-status";
@@ -82,14 +82,14 @@ const agentRequestSchema = z.object({
caseId: z.string().uuid(),
sessionId: z.string().uuid(),
requestId: z.string().uuid(),
action: z.enum(["opening", "message", "read_only", "answer_choice", "stop_and_review"]),
action: z.enum(["opening", "message", "read_only", "answer_choice", "stop_and_review", "skip_probe"]),
message: z.string().trim().min(1).max(4000).optional(),
modelId: z.string().trim().min(1).max(64).optional(),
actionId: z.string().uuid().optional(),
focusId: z.string().uuid().optional(),
questionId: z.string().trim().min(1).max(200).optional(),
probeId: z.string().trim().min(1).max(200).nullable().optional(),
optionId: z.enum(["A", "B", "C", "D"]).optional(),
optionId: z.enum(["A", "B", "C", "D", "skip_probe"]).optional(),
expectedRevision: z.number().int().min(0).max(10_000).optional(),
origin: z.enum([
"typed",
@@ -300,11 +300,19 @@ export async function POST(request: Request) {
caseId,
sessionId,
actionId,
action: action === "stop_and_review" ? STOP_ACTION : CHOICE_ACTION,
action: action === "stop_and_review"
? STOP_ACTION
: action === "skip_probe"
? SKIP_PROBE_ACTION
: CHOICE_ACTION,
focusId,
questionId: parsed.data.questionId,
probeId: parsed.data.probeId ?? null,
optionId: action === "stop_and_review" ? "stop" : parsed.data.optionId!,
optionId: action === "stop_and_review"
? "stop"
: action === "skip_probe"
? "skip_probe"
: parsed.data.optionId!,
expectedRevision,
narrateAdopt,
});
@@ -327,6 +335,7 @@ export async function POST(request: Request) {
sourceQuote: applied.sourceQuote,
derivedContext: applied.derivedContext,
nextAction: applied.nextAction,
next_user_action: applied.nextUserAction,
nextInterviewPersisted: applied.nextInterviewPersisted,
nextChoiceReady: applied.nextChoiceReady,
});
@@ -600,7 +609,7 @@ export async function POST(request: Request) {
);
return response;
}
if (action === "answer_choice" || action === "stop_and_review") {
if (action === "answer_choice" || action === "stop_and_review" || action === "skip_probe") {
return NextResponse.json(
{ error: "选择题处理失败", message: "请稍后重试。" },
{ status: 500 },
@@ -14,7 +14,7 @@ import {
type ConversationFocusList,
type V9CaseDossier,
} from "@/lib/rectification-agentic/v9/tool-service";
import { choiceCardFromCaseDossier, decideFromDossier, overlayPublicDecision } from "@/lib/rectification-agentic/v9/interview-state";
import { choiceCardFromCaseDossier, decideFromDossier, overlayPublicDecision, nextUserActionFromDossier } from "@/lib/rectification-agentic/v9/interview-state";
import { projectCurrentQuestion } from "@/lib/rectification-agentic/v9/turn-decision";
import { attachQuestionsToTurns, attachOfferResultToTurns } from "@/lib/rectification-agentic/v9/turn-question";
import { previousInferenceFromReceipt } from "@/lib/rectification-agentic/v9/inference-adapter";
@@ -147,6 +147,7 @@ export function dossierResponse(
},
current_question: projectCurrentQuestion(dossier.conversationSummary.activeFocus),
choice_card: choiceCardFromCaseDossier(dossier),
next_user_action: nextUserActionFromDossier(dossier),
question_source: questionSourceFromFocusList(listed),
};
}