fix(web): persist rectification C/D answers on an append-only inference ledger
Engine result rows stay immutable. Choice answers append transitions, and reads overlay the latest revision instead of patching the cached receipt. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -456,10 +456,26 @@ test("a failed opening does not let the next turn skip the server Skill load gat
|
||||
});
|
||||
|
||||
test("same evidence + range fingerprints reuse the cached candidate snapshot", async () => {
|
||||
const inputReceipt = {
|
||||
receipt_version: "candidate-decision-receipt-v2",
|
||||
policy_version: "rectification-candidate-policy-v2",
|
||||
selection_allowed: true,
|
||||
acceptance_allowed: true,
|
||||
confirmation_allowed: false,
|
||||
representative_candidate_id: null,
|
||||
overall_confidence: "medium",
|
||||
inference_state: { revision: 1, candidates: [{ id: "05:02", posterior_score: 10 }] },
|
||||
};
|
||||
const composedReceipt = {
|
||||
...inputReceipt,
|
||||
inference_state: { revision: 2, candidates: [{ id: "05:02", posterior_score: 18 }] },
|
||||
decision_state_fingerprint: "a".repeat(64),
|
||||
};
|
||||
const accounting = fakeAccounting({
|
||||
persist_agentic_rectification_candidate_v2: () => ({
|
||||
...candidateSnapshotFixture(),
|
||||
cached: true,
|
||||
decision_receipt: composedReceipt,
|
||||
}),
|
||||
});
|
||||
const cached = await persistV9Candidate(accounting.client, USER_ID, CASE_ID, {
|
||||
@@ -472,15 +488,7 @@ test("same evidence + range fingerprints reuse the cached candidate snapshot", a
|
||||
eventContractVersion: "rectification-event-contract-v2",
|
||||
policyVersion: "rectification-candidate-policy-v2",
|
||||
candidates: [{ candidateId: CANDIDATE_ID, rank: 1, time: "05:02", relativeSupport: 58, tiedMinuteCount: 2 }],
|
||||
decisionReceipt: {
|
||||
receipt_version: "candidate-decision-receipt-v2",
|
||||
policy_version: "rectification-candidate-policy-v2",
|
||||
selection_allowed: true,
|
||||
acceptance_allowed: true,
|
||||
confirmation_allowed: false,
|
||||
representative_candidate_id: null,
|
||||
overall_confidence: "medium",
|
||||
},
|
||||
decisionReceipt: inputReceipt,
|
||||
executionLedger: [{ method: "d1-rashi", status: "executed" }],
|
||||
});
|
||||
assert.equal(cached.cached, true);
|
||||
@@ -491,12 +499,20 @@ test("same evidence + range fingerprints reuse the cached candidate snapshot", a
|
||||
assert.equal(call.args.p_skill_version, "9.0.0");
|
||||
assert.equal(call.args.p_event_contract_version, "rectification-event-contract-v2");
|
||||
assert.equal(call.args.p_decision_policy_version, "rectification-candidate-policy-v2");
|
||||
assert.deepEqual(call.args.p_decision_receipt, cached.decisionReceipt);
|
||||
assert.deepEqual(call.args.p_decision_receipt, inputReceipt);
|
||||
assert.notDeepEqual(cached.decisionReceipt, inputReceipt);
|
||||
assert.deepEqual(cached.decisionReceipt, composedReceipt);
|
||||
assert.equal(
|
||||
(cached.decisionReceipt.inference_state as { revision?: number }).revision,
|
||||
2,
|
||||
);
|
||||
assert.equal(cached.decisionReceipt.decision_state_fingerprint, "a".repeat(64));
|
||||
assert.deepEqual(call.args.p_execution_ledger, cached.executionLedger);
|
||||
assert.equal("p_selection_allowed" in call.args, false);
|
||||
assert.equal("p_confirmation_allowed" in call.args, false);
|
||||
assert.equal("p_representative_time" in call.args, false);
|
||||
assert.equal("p_margin_percent" in call.args, false);
|
||||
assert.equal("p_decision_state_fingerprint" in call.args, false);
|
||||
});
|
||||
|
||||
test("accept-candidate requires a server-persisted result; no tool means no minute", async () => {
|
||||
|
||||
Reference in New Issue
Block a user