fix(rectification): surface dropped probes and filter tools by the decision
Independent Staging Quality Gate / validate (push) Failing after 17m9s
Independent Staging Quality Gate / publish (push) Has been skipped

Silent unrenderable discriminators, a missing question-contract golden, and a always-on tool table were hiding fail-closed drops behind the prompt wall.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-28 20:31:15 +08:00
parent 69c3e94920
commit 63b4591aae
25 changed files with 856 additions and 274 deletions
@@ -2,12 +2,14 @@ import { NextResponse } from "next/server";
import { z } from "zod";
import { getRectificationV9Agent, type RectificationAgentAction } from "@/mastra/agentic-rectification";
import {
evidenceLedgerFingerprint,
loadV9CaseCompute,
loadV9CaseDossier,
persistV9DeterministicTurn,
RectificationToolServiceError,
transitionV9CaseStatus,
} from "@/lib/rectification-agentic/v9/tool-service";
import { decideFromDossier, rectificationFollowupCatalog } from "@/lib/rectification-agentic/v9/decision-from-dossier";
import { applyRectificationChoice } from "@/lib/rectification-agentic/v9/answer-choice";
import { mapRectificationRpcError } from "@/lib/rectification-agentic/v9/case-service";
import { CHOICE_ACTION, STOP_ACTION } from "@/lib/rectification-agentic/v9/choice-action";
@@ -28,7 +30,6 @@ import {
classifyRectificationTurnIntent,
optionIdForAnswerClass,
} from "@/lib/rectification-agentic/v9/turn-intent-classifier";
import { decideFromDossier, rectificationFollowupCatalog } from "@/lib/rectification-agentic/v9/decision-from-dossier";
import { persistServerOwnedFocus, openQuestionFromPersistedFocus } from "@/lib/rectification-agentic/v9/server-focus";
import { buildMethodFollowupPlan } from "@/lib/rectification-agentic/v9/method-followup";
@@ -580,16 +581,26 @@ export async function POST(request: Request) {
signal: request.signal,
timeContext,
generationModel: selectedModel.model,
buildAgent: (turnId, skillPackage, attemptId) => Promise.resolve(
getRectificationV9Agent(selectedModel, {
buildAgent: async (turnId, skillPackage, attemptId) => {
let decision;
try {
const dossier = await loadV9CaseDossier(accounting as never, userId, caseId);
decision = decideFromDossier(dossier, {
currentEvidenceFingerprint: evidenceLedgerFingerprint(dossier.evidence),
});
} catch {
decision = undefined;
}
return getRectificationV9Agent(selectedModel, {
userId,
caseId,
turnId,
attemptId,
userMessage: action === "message" ? parsed.data.message ?? null : null,
accounting: accounting as never,
}, skillPackage),
),
decision,
}, skillPackage);
},
});
if (!result.ok) {
@@ -12,6 +12,7 @@ import {
type V9CaseDossier,
} from "@/lib/rectification-agentic/v9/tool-service";
import { choiceCardFromCaseDossier, decideFromDossier, overlayPublicDecision } from "@/lib/rectification-agentic/v9/interview-state";
import { projectCurrentQuestion } from "@/lib/rectification-agentic/v9/turn-decision";
import { previousInferenceFromReceipt } from "@/lib/rectification-agentic/v9/inference-adapter";
import { publicDecisionFields } from "@/lib/rectification-agentic/core/rectification-decision";
@@ -116,6 +117,7 @@ function dossierResponse(
evidence: dossier.evidence,
latest_result: dossier.latestResult ? overlayPublicDecision(dossier.latestResult, decision) : null,
interview: publicDecisionFields(decision),
current_question: projectCurrentQuestion(dossier.conversationSummary.activeFocus),
choice_card: choiceCardFromCaseDossier(dossier),
};
}