fix(rectification): keep compare requests valid after style cards (BUG-577–580)
Engine asked_probe_keys no longer include varga split hashes that 400 the scorer, failed compares become visible and retry, user stop can still deliver a range on a stale snapshot, and holdout no longer reasks domains already in the ledger. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -29,9 +29,13 @@ import {
|
||||
} from "../src/lib/rectification-agentic/v9/run-diagnostic.ts";
|
||||
import { applyHoldoutAnswer, buildInferenceState } from "../src/lib/rectification-agentic/core/build-state.ts";
|
||||
import { applyChoiceWithoutEvidence } from "../src/lib/rectification-agentic/v9/inference-adapter.ts";
|
||||
import { RECTIFICATION_TERMINATION_COPY } from "../src/lib/rectification-agentic/core/rectification-decision.ts";
|
||||
import { RECTIFICATION_TERMINATION_COPY, ADOPT_OUTCOMES } from "../src/lib/rectification-agentic/core/rectification-decision.ts";
|
||||
import { containsBoundarySemantics, RECTIFICATION_USER_COPY } from "../src/lib/rectification-agentic/user-copy.ts";
|
||||
import { parseV9CaseDossier, RectificationToolServiceError } from "../src/lib/rectification-agentic/v9/tool-service.ts";
|
||||
import {
|
||||
evidenceLedgerFingerprint,
|
||||
parseV9CaseDossier,
|
||||
RectificationToolServiceError,
|
||||
} from "../src/lib/rectification-agentic/v9/tool-service.ts";
|
||||
import {
|
||||
CASE_ID,
|
||||
EVIDENCE_ID,
|
||||
@@ -227,8 +231,20 @@ function rangeNarrationInference(leadSupport: number, trailSupport: number) {
|
||||
});
|
||||
}
|
||||
|
||||
function withCurrentEvidenceFingerprint(raw: ReturnType<typeof dossierFixture>) {
|
||||
const parsed = parseV9CaseDossier(raw);
|
||||
if (!parsed) return raw;
|
||||
const latest = raw.latest_result && typeof raw.latest_result === "object"
|
||||
? {
|
||||
...(raw.latest_result as Record<string, unknown>),
|
||||
evidence_ledger_fingerprint: evidenceLedgerFingerprint(parsed.evidence),
|
||||
}
|
||||
: raw.latest_result;
|
||||
return { ...raw, latest_result: latest };
|
||||
}
|
||||
|
||||
function rangeNarrationDossier(inference: ReturnType<typeof buildInferenceState>) {
|
||||
return dossierFixture({
|
||||
return withCurrentEvidenceFingerprint(dossierFixture({
|
||||
latestResult: candidateSnapshotFixture({
|
||||
decisionReceipt: { inference_state: inference },
|
||||
}),
|
||||
@@ -253,15 +269,16 @@ function rangeNarrationDossier(inference: ReturnType<typeof buildInferenceState>
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
function choiceDossier() {
|
||||
function choiceDossier(evidence?: ReturnType<typeof fourEventRows>) {
|
||||
const inference = inferenceState();
|
||||
const snapshot = candidateSnapshotFixture({
|
||||
decisionReceipt: { inference_state: inference },
|
||||
});
|
||||
return dossierFixture({
|
||||
return withCurrentEvidenceFingerprint(dossierFixture({
|
||||
...(evidence ? { evidence, evidenceCount: evidence.length } : {}),
|
||||
latestResult: snapshot,
|
||||
conversationSummary: conversationSummaryFixture({
|
||||
activeFocus: activeFocusFixture({
|
||||
@@ -284,7 +301,7 @@ function choiceDossier() {
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
function twoProbeInference() {
|
||||
@@ -392,7 +409,7 @@ function twoProbeDossier() {
|
||||
],
|
||||
},
|
||||
});
|
||||
return dossierFixture({
|
||||
return withCurrentEvidenceFingerprint(dossierFixture({
|
||||
evidenceCount: 5,
|
||||
evidence: fourEventRows(),
|
||||
latestResult: snapshot,
|
||||
@@ -428,7 +445,7 @@ function twoProbeDossier() {
|
||||
created_at: "2026-08-28T07:36:54.000Z",
|
||||
completed_at: "2026-08-28T07:37:34.000Z",
|
||||
}],
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
function familyCollectInference() {
|
||||
@@ -459,7 +476,7 @@ function familyCollectDossier() {
|
||||
evidence_collection_probes: [FAMILY_2021_COLLECT],
|
||||
},
|
||||
});
|
||||
return dossierFixture({
|
||||
return withCurrentEvidenceFingerprint(dossierFixture({
|
||||
evidenceCount: 5,
|
||||
evidence: fourEventRows(),
|
||||
latestResult: snapshot,
|
||||
@@ -486,7 +503,7 @@ function familyCollectDossier() {
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
function adoptionInference() {
|
||||
@@ -509,7 +526,7 @@ function adoptionInference() {
|
||||
|
||||
function adoptionDossier() {
|
||||
const inference = adoptionInference();
|
||||
return dossierFixture({
|
||||
return withCurrentEvidenceFingerprint(dossierFixture({
|
||||
evidenceCount: 6,
|
||||
evidence: [
|
||||
...fourEventRows(),
|
||||
@@ -566,7 +583,7 @@ function adoptionDossier() {
|
||||
},
|
||||
}),
|
||||
}),
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
function persistChoiceAccounting(
|
||||
@@ -1031,7 +1048,7 @@ test("keeps the applied answer when narration persistence fails", async () => {
|
||||
});
|
||||
|
||||
test("stop_and_review does not write an inference transition", async () => {
|
||||
const accounting = choiceAccounting();
|
||||
const accounting = persistChoiceAccounting(choiceDossier(fourEventRows()));
|
||||
const applied = await applyRectificationChoice(accounting.client, {
|
||||
userId: USER_ID,
|
||||
caseId: CASE_ID,
|
||||
@@ -1044,8 +1061,14 @@ test("stop_and_review does not write an inference transition", async () => {
|
||||
expectedRevision: inferenceState().revision,
|
||||
});
|
||||
assert.equal(applied.optionId, "stop");
|
||||
assert.match(applied.narration, /已记录你的选择/);
|
||||
assert.equal(applied.narration.split(RECTIFICATION_TERMINATION_COPY).length - 1, 1);
|
||||
assert.ok(ADOPT_OUTCOMES.has(applied.nextAction.session_outcome));
|
||||
assert.equal(applied.nextAction.can_adopt, true);
|
||||
assert.match(applied.narration, /05:\d{2}|目前范围|眼下更站得住的是/);
|
||||
assert.ok(
|
||||
applied.narration.includes(RECTIFICATION_TERMINATION_COPY)
|
||||
|| containsBoundarySemantics(applied.narration)
|
||||
|| /眼下更站得住的是/.test(applied.narration),
|
||||
);
|
||||
const persist = accounting.calls.find((call) => call.fn === "apply_agentic_rectification_choice_action");
|
||||
assert.equal(persist?.args.p_inference, null);
|
||||
assert.equal(persist?.args.p_focus_status, "skipped");
|
||||
@@ -1629,7 +1652,7 @@ function lastVerifyDossier() {
|
||||
],
|
||||
},
|
||||
});
|
||||
return dossierFixture({
|
||||
return withCurrentEvidenceFingerprint(dossierFixture({
|
||||
evidenceCount: 5,
|
||||
evidence: fourEventRows(),
|
||||
latestResult: snapshot,
|
||||
@@ -1665,7 +1688,7 @@ function lastVerifyDossier() {
|
||||
created_at: "2026-08-28T07:36:54.000Z",
|
||||
completed_at: "2026-08-28T07:37:34.000Z",
|
||||
}],
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
test("skipping the last post-adopt verify question closes with start_consultation", async () => {
|
||||
|
||||
Reference in New Issue
Block a user