fix(rectification): wire unique-minute confirmation to VedAstro and sealed holdout
Keep confirmation fail-closed until the public AA set is ready, and rewrite Technique Audit from the attached VedAstro status instead of a hardcoded blocked row. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -201,5 +201,7 @@ test("adopted minute recasts the house table and keeps technique audit collapsed
|
||||
assert.equal(result?.techniqueAudit.length, 3);
|
||||
assert.equal(result?.techniqueAudit[2]?.status, "blocked");
|
||||
assert.equal(result?.precisionStage?.current, "d4_refine");
|
||||
assert.equal(result?.confirmationGate.confirmation_allowed, false);
|
||||
assert.equal(result?.confirmationGate.blockers.some((item) => item.id === "public_aa_holdout" && item.status === "not_ready"), true);
|
||||
});
|
||||
|
||||
|
||||
@@ -71,10 +71,16 @@ function blocker(
|
||||
}
|
||||
|
||||
test("sealed holdout aggregates match the v2 report and stay below the case gate", () => {
|
||||
const productHoldout = JSON.parse(readFileSync(
|
||||
new URL("../../references/rectification_sealed_holdout.v1.json", import.meta.url),
|
||||
"utf8",
|
||||
)) as typeof SEALED_MINUTE_HOLDOUT;
|
||||
assert.equal(SEALED_MINUTE_HOLDOUT.valid_public_aa_cases, holdoutReport.case_gate.valid_public_aa_cases);
|
||||
assert.equal(SEALED_MINUTE_HOLDOUT.required_cases, holdoutReport.case_gate.minimum_public_aa_cases);
|
||||
assert.equal(SEALED_MINUTE_HOLDOUT.top_1_rate, holdoutReport.metrics.top_1_rate);
|
||||
assert.equal(SEALED_MINUTE_HOLDOUT.confirmation_coverage_rate, holdoutReport.metrics.confirmation_coverage_rate);
|
||||
assert.equal(SEALED_MINUTE_HOLDOUT.valid_public_aa_cases, productHoldout.valid_public_aa_cases);
|
||||
assert.equal(SEALED_MINUTE_HOLDOUT.status, productHoldout.status);
|
||||
assert.ok(SEALED_MINUTE_HOLDOUT.valid_public_aa_cases < SEALED_MINUTE_HOLDOUT.required_cases);
|
||||
assert.equal(SEALED_MINUTE_HOLDOUT.status, "not_ready");
|
||||
});
|
||||
@@ -158,7 +164,7 @@ test("holdout not_ready forbids unique-minute copy and still blocks confirm", as
|
||||
assert.match(agentSource, /session_outcome=adopt_representative/);
|
||||
assert.doesNotMatch(agentSource, /±2 分钟/);
|
||||
assert.equal(PUBLIC_RECTIFICATION_TOOLS.length, 13);
|
||||
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.5");
|
||||
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.6");
|
||||
|
||||
const accounting = fakeAccounting({
|
||||
...receiptHandlers,
|
||||
|
||||
@@ -504,9 +504,9 @@ test("rescore failure does not fail the evidence write", async () => {
|
||||
assert.ok(result.rescore.error_code);
|
||||
});
|
||||
|
||||
test("public tool surface stays at 13 and new cases bind 10.0.5", () => {
|
||||
test("public tool surface stays at 13 and new cases bind 10.0.6", () => {
|
||||
assert.equal(PUBLIC_RECTIFICATION_TOOLS.length, 13);
|
||||
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.5");
|
||||
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.6");
|
||||
const deprecated = resolveExactSkillPackage(
|
||||
"jyotish-birth-time-rectification",
|
||||
"10.0.2",
|
||||
|
||||
@@ -202,9 +202,9 @@ test("read-case evidence context keeps day labels and confirm does not rewrite d
|
||||
assert.equal("p_occurred_from" in confirmCall.args, false);
|
||||
});
|
||||
|
||||
test("new-case skill identity is 10.0.5 and the prompt prefers batch ingest", () => {
|
||||
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.5");
|
||||
assert.match(skill, /^version: 10\.0\.5$/m);
|
||||
test("new-case skill identity is 10.0.6 and the prompt prefers batch ingest", () => {
|
||||
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.6");
|
||||
assert.match(skill, /^version: 10\.0\.6$/m);
|
||||
assert.match(skill, /不要对同一句用户消息里的多件事件逐条 propose\+confirm/);
|
||||
assert.match(agentSource, /当前轮新事件一律走 rectification-record-evidence-batch/);
|
||||
assert.doesNotMatch(agentSource, /分别调用 rectification-propose-evidence 和 rectification-confirm-evidence/);
|
||||
|
||||
@@ -76,11 +76,11 @@ test("system prompt carries only high-priority boundaries, never the method copy
|
||||
test("agent pins the dedicated rectification skill and its fixed version", () => {
|
||||
assert.equal(RECTIFICATION_V9_SKILL_NAME, "jyotish-birth-time-rectification");
|
||||
assert.equal(basename(RECTIFICATION_V9_SKILL_PATH), RECTIFICATION_V9_SKILL_NAME);
|
||||
assert.ok(RECTIFICATION_V9_PACKAGE_PATH.endsWith("skills/jyotish-birth-time-rectification/versions/10.0.5"));
|
||||
assert.ok(RECTIFICATION_V9_PACKAGE_PATH.endsWith("skills/jyotish-birth-time-rectification/versions/10.0.6"));
|
||||
assert.notEqual(RECTIFICATION_V9_SKILL_PATH, RECTIFICATION_V9_PACKAGE_PATH);
|
||||
assert.equal(realpathSync(RECTIFICATION_V9_SKILL_PATH), RECTIFICATION_V9_PACKAGE_PATH);
|
||||
assert.equal(RECTIFICATION_SKILL_NAME, "jyotish-birth-time-rectification");
|
||||
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.5");
|
||||
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.6");
|
||||
});
|
||||
|
||||
test("step budgets are bounded per action with a hard ceiling", () => {
|
||||
|
||||
@@ -92,9 +92,9 @@ test("terminal transitions are one-way and evidence writes stop at terminal", ()
|
||||
|
||||
test("the active rectification skill pins the v10 identity and lives in the right directory", () => {
|
||||
assert.equal(RECTIFICATION_SKILL_NAME, "jyotish-birth-time-rectification");
|
||||
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.5");
|
||||
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.6");
|
||||
assert.match(skill, /^---\nname: jyotish-birth-time-rectification/m);
|
||||
assert.match(skill, /^version: 10\.0\.5$/m);
|
||||
assert.match(skill, /^version: 10\.0\.6$/m);
|
||||
for (const reference of references) {
|
||||
const content = readFileSync(`${skillDirectory}/references/${reference}`, "utf8");
|
||||
assert.ok(content.length > 0, `${reference} must be non-empty`);
|
||||
|
||||
@@ -3,8 +3,10 @@ import test from "node:test";
|
||||
|
||||
import {
|
||||
RectificationEngineError,
|
||||
mergeVedastroValidateIntoReceipt,
|
||||
runV9CandidateScore,
|
||||
runV9Diagnostics,
|
||||
runV9VedastroValidate,
|
||||
toEngineEvents,
|
||||
type V9EngineScoreResult,
|
||||
} from "../src/lib/rectification-agentic/v9/engine-client.ts";
|
||||
@@ -315,3 +317,63 @@ test("engine http failures surface as safe engine errors, never raw stack traces
|
||||
restore();
|
||||
}
|
||||
});
|
||||
|
||||
test("vedastro-validate maps pass/fail and never grants unique-minute confirmation", async () => {
|
||||
const restore = stubEngine({
|
||||
success: true,
|
||||
endpoint: "rectification_v5_vedastro_validate",
|
||||
status: "pass",
|
||||
passed: true,
|
||||
can_confirm_exact_minute: false,
|
||||
minute_sensitive_validation: { status: "pass", discriminated: true },
|
||||
event_validation: {
|
||||
status: "pass",
|
||||
search_events_primary_supports_local_winner: true,
|
||||
},
|
||||
});
|
||||
try {
|
||||
const result = await runV9VedastroValidate({
|
||||
baselineBirthSnapshot: SNAPSHOT,
|
||||
candidateRange: RANGE,
|
||||
events: toEngineEvents(EVIDENCE),
|
||||
candidateTimes: ["04:50", "04:51"],
|
||||
});
|
||||
assert.equal(result.status, "passed");
|
||||
assert.equal(result.canConfirmExactMinute, false);
|
||||
assert.equal(result.searchEventsSupportsLocalWinner, true);
|
||||
const merged = mergeVedastroValidateIntoReceipt(
|
||||
{ ...DECISION_RECEIPT, gates: { exact_confirmation: { external_validation_status: "passed" } } },
|
||||
result,
|
||||
);
|
||||
const exact = (merged.gates as { exact_confirmation: Record<string, unknown> }).exact_confirmation;
|
||||
assert.equal(exact.external_validation_status, "passed");
|
||||
assert.equal(
|
||||
(exact.vedastro_event_validation as { search_events_primary_supports_local_winner: boolean })
|
||||
.search_events_primary_supports_local_winner,
|
||||
true,
|
||||
);
|
||||
assert.equal(merged.confirmation_allowed, false);
|
||||
} finally {
|
||||
restore();
|
||||
}
|
||||
});
|
||||
|
||||
test("vedastro-validate timeout stays not_evaluated and is not described as fail", async () => {
|
||||
const previous = globalThis.fetch;
|
||||
globalThis.fetch = (async () => {
|
||||
throw new Error("timeout");
|
||||
}) as unknown as typeof fetch;
|
||||
try {
|
||||
const result = await runV9VedastroValidate({
|
||||
baselineBirthSnapshot: SNAPSHOT,
|
||||
candidateRange: RANGE,
|
||||
events: toEngineEvents(EVIDENCE),
|
||||
candidateTimes: ["04:50", "04:51"],
|
||||
});
|
||||
assert.equal(result.status, "not_evaluated");
|
||||
assert.notEqual(result.status, "failed");
|
||||
assert.equal(result.canConfirmExactMinute, false);
|
||||
} finally {
|
||||
globalThis.fetch = previous;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -209,7 +209,7 @@ test("open RPC passes the pinned skill and server-derived baseline only", async
|
||||
session_id: SESSION_ID,
|
||||
status: "draft",
|
||||
should_start_opening: true,
|
||||
skill_version: "10.0.5",
|
||||
skill_version: "10.0.6",
|
||||
};
|
||||
}
|
||||
return null;
|
||||
@@ -247,11 +247,11 @@ test("open RPC passes the pinned skill and server-derived baseline only", async
|
||||
});
|
||||
assert.equal(response.disposition, "created");
|
||||
assert.equal(response.shouldStartOpening, true);
|
||||
assert.equal(response.skillVersion, "10.0.5");
|
||||
assert.equal(response.skillVersion, "10.0.6");
|
||||
const openCall = accounting.calls.find((call) => call.fn === "open_agentic_rectification_case_v2");
|
||||
assert.ok(openCall);
|
||||
assert.equal(openCall.args.p_skill_name, "jyotish-birth-time-rectification");
|
||||
assert.equal(openCall.args.p_skill_version, "10.0.5");
|
||||
assert.equal(openCall.args.p_skill_version, "10.0.6");
|
||||
assert.equal(openCall.args.p_user_id, "user-1");
|
||||
// The server derives the baseline; the request never carries it from the browser.
|
||||
assert.equal("birth_date" in openCall.args, false);
|
||||
|
||||
@@ -85,8 +85,8 @@ test("checked-in registry verifies hashed product packages and leaves consult on
|
||||
[
|
||||
{
|
||||
name: "jyotish-birth-time-rectification",
|
||||
version: "10.0.5",
|
||||
sha256: "47cd353b5f7a08695007ce52d77560584300a1097ed97248f3a81372eeaca9c6",
|
||||
version: "10.0.6",
|
||||
sha256: "25cd80f9129217723e11a88f247ea081b2d6c9ca95c71d6d5f0633b4de6f3e8b",
|
||||
},
|
||||
{
|
||||
name: "jyotish-personal-report",
|
||||
|
||||
Reference in New Issue
Block a user