import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; import { scoreAndPersistCurrentEvidence } from "../src/lib/rectification-agentic/v9/score-persist.ts"; import { buildProductCaseInferenceState } from "../src/lib/rectification-agentic/v9/product-inference.ts"; import { buildCaseInferenceState } from "../src/lib/rectification-agentic/v9/inference-adapter.ts"; import { asInferenceState } from "../src/lib/rectification-agentic/core/compose-receipt.ts"; import { rangeDeliveryForSnapshot } from "../src/lib/rectification-agentic/v9/divergence-panel.ts"; import { productDeliveryForDomain } from "../src/lib/rectification-agentic/v9/product-delivery.ts"; import { parseV9CaseDossier } from "../src/lib/rectification-agentic/v9/tool-service.ts"; import { dossierResponse } from "../src/lib/rectification-agentic/v9/case-dossier-response.ts"; import { decideFromDossier } from "../src/lib/rectification-agentic/v9/decision-from-dossier.ts"; import { latestResultToolProjection } from "../src/mastra/rectification-v9-tools.ts"; import { parseRectificationCandidateResult } from "../src/lib/rectification-candidate-result.ts"; import { deliveryTurnNarration, nonConvergingRangeNarration } from "../src/lib/rectification-agentic/user-copy.ts"; import { buildGoldenLatest } from "./rectification-grounding-support.ts"; import { runV9CandidateScore } from "../src/lib/rectification-agentic/v9/engine-client.ts"; import { refinementFromDecisionReceipt } from "../src/lib/rectification-agentic/v9/refinement-packet.ts"; import { CASE_ID, USER_ID, TURN_ID, computeFixture, dossierFixture, fakeAccounting } from "./rectification-v9-test-support.ts"; // Unmodified real native API captures for a public AA case; persistence doubles // below are not SQL, Skill-upgrade history or six-question calibration evidence. const golden = JSON.parse(readFileSync(new URL("./fixtures/varga-api-response.golden.json", import.meta.url), "utf8")); const req = golden.request; const range = { start_time: req.start_time, end_time: req.end_time, candidate_intervals: golden.response.decision_receipt.candidate_intervals }; const snapshot = { birth_date: req.birth_date, reported_birth_time: "09:09", active_birth_time: null, birth_time_source: "approximate", latitude: req.lat, longitude: req.lon, timezone_id: "America/Los_Angeles", timezone_offset: req.tz }; for (const domain of [null, "marriage", "career", "general", "report", "other"] as const) { for (const scanFails of [false, true]) { test(`production rescore keeps persisted opt-in delivery boundary: ${domain ?? "legacy-null"}${scanFails ? " with failed scan" : ""}`, async (t) => { const keys = ["RECTIFICATION_ALGORITHM_VERSION", "RECTIFICATION_DECISION_POLICY_VERSION", "RECTIFICATION_SEGMENT_ORDER"]; const saved = keys.map(key => [key, process.env[key]] as const); process.env.RECTIFICATION_ALGORITHM_VERSION = golden.response.algorithm_version; process.env.RECTIFICATION_DECISION_POLICY_VERSION = golden.response.decision_policy_version; process.env.RECTIFICATION_SEGMENT_ORDER = "on"; t.after(() => { for (const [key, value] of saved) { if (value === undefined) delete process.env[key]; else process.env[key] = value; } }); const requests: string[] = []; t.mock.method(globalThis, "fetch", async (endpoint: unknown) => { requests.push(String(endpoint)); if (String(endpoint).includes("varga-segments")) { assert.ok(domain, "nullable history must not trigger a product segment scan"); if (scanFails) throw new Error("controlled optional scan failure"); return Response.json(golden.scan); } return Response.json(golden.response); }); const raw = dossierFixture({ candidateRange: range, latestResult: null, evidence: req.events.map((event: Record) => ({ id: event.id, source_turn_id: TURN_ID, subject: "self", event_kind: event.event_kind, domain: event.domain, occurred_from: event.date_start, occurred_to: event.date_end, date_precision: event.precision, summary: event.summary, status: "confirmed", supersedes_evidence_id: null, created_at: "2026-09-30T00:00:00Z", })) }); Object.assign(raw.case, { rectification_domain: domain }); const accounting = fakeAccounting({ get_agentic_rectification_case_dossier: () => raw, get_agentic_rectification_case_compute: () => ({ ...computeFixture({ baselineBirthSnapshot: snapshot }), candidate_range: range }), persist_agentic_rectification_candidate_v2: (_fn, args) => ({ ...golden.response.decision_receipt, result_id: args.p_engine_result_id, candidates: args.p_candidates, algorithm_version: args.p_algorithm_version, decision_policy_version: args.p_decision_policy_version, decision_receipt: args.p_decision_receipt, }), }); const scored = await scoreAndPersistCurrentEvidence({ accounting: accounting.client, userId: USER_ID, caseId: CASE_ID, keepAnswers: false }); const inference = asInferenceState(scored.decisionReceipt.inference_state); assert.ok(inference); const packet = rangeDeliveryForSnapshot({ decisionReceipt: scored.decisionReceipt, candidateRange: range }); assert.ok(scored.score.candidates.some(candidate => candidate.rawScore !== undefined && candidate.signature), "raw native audit remains available"); if (!domain) { assert.equal(inference.segment_summary, undefined); assert.equal(inference.segment_targets, undefined); assert.equal(inference.segment_minutes, undefined); assert.equal(packet.segment_summary, null, "freshly scored legacy packet does not render a new product card"); assert.equal(requests.filter(endpoint => endpoint.includes("varga-segments")).length, 0); } else { const targets = domain === "marriage" ? ["D1", "D9"] : domain === "career" ? ["D1", "D10"] : ["D1", "D9", "D10"]; assert.deepEqual(inference.segment_targets, targets); assert.ok(inference.segment_summary); assert.deepEqual(packet.segment_summary?.targets, targets); assert.equal(requests.filter(endpoint => endpoint.includes("varga-segments")).length, 1); } const persist = accounting.calls.find(call => call.fn === "persist_agentic_rectification_candidate_v2"); assert.ok(persist); const savedReceipt = persist.args.p_decision_receipt as Record; assert.deepEqual(savedReceipt.inference_state, scored.decisionReceipt.inference_state); assert.deepEqual(savedReceipt.product_delivery ?? null, productDeliveryForDomain(domain)); assert.deepEqual(packet.product_delivery, productDeliveryForDomain(domain)); const identityGolden = await buildGoldenLatest(); const reloadRaw = dossierFixture({ candidateRange: range, latestResult: { ...identityGolden.latest, candidates: persist.args.p_candidates, representative_time: scored.score.representativeTime, decision_receipt: savedReceipt } }); Object.assign(reloadRaw.case, { rectification_domain: domain }); const reloaded = parseV9CaseDossier(reloadRaw)!; const decision = decideFromDossier(reloaded); const tools = latestResultToolProjection(reloaded.latestResult as never, decision, productDeliveryForDomain(domain)); const publicDossier = dossierResponse(reloaded, [], { status: "verified", requiresSkillAdoption: false } as never, { liveIdentity: { algorithmVersion: identityGolden.scored.algorithmVersion, policyVersion: identityGolden.scored.policyVersion } }); const parsed = parseRectificationCandidateResult(publicDossier.latest_result); assert.ok(parsed); assert.deepEqual(parsed.rangeDelivery?.product_delivery, productDeliveryForDomain(domain)); assert.deepEqual(tools.product_delivery, productDeliveryForDomain(domain)); if (domain && scanFails) { assert.equal(inference.segment_summary?.scan_complete, false); assert.equal(inference.segment_summary?.no_rectification_needed, false); assert.equal(inference.segment_summary?.adoption_minute, null); assert.equal(parsed.rangeDelivery?.segment_summary?.scan_complete, false); const report = tools.skill_verification_report as { markdown: string; segment_summary: { scan_complete: boolean } }; assert.equal(report.segment_summary.scan_complete, false); assert.match(report.markdown, /完整窗口扫描暂不可用|完整扫描缺失/); assert.match(parsed.verificationReportMarkdown!, /只供引擎诊断/); assert.doesNotMatch(deliveryTurnNarration(decision) + nonConvergingRangeNarration(decision) + report.markdown, /目前范围|最可能|眼下更像|盘型一致,不用校正/); } }); } } test("legacy inference clears optional segment carryover without changing frozen minute convergence", async (t) => { t.mock.method(globalThis, "fetch", async () => Response.json(golden.response)); const score = await runV9CandidateScore({ baselineBirthSnapshot: snapshot, candidateRange: range, events: req.events }); const input = { range, candidates: score.candidates, evidence: [], probes: refinementFromDecisionReceipt(score.decisionReceipt).discriminating_event_probes }; const legacy = buildProductCaseInferenceState(input, null); const withoutMetadata = buildCaseInferenceState({ ...input, candidates: input.candidates.map(candidate => { const minuteCandidate = { ...candidate }; delete minuteCandidate.rawScore; delete minuteCandidate.signature; return minuteCandidate; }) }); assert.deepEqual(legacy, withoutMetadata, "minute prior/posterior, holdout, stops and original probes remain unchanged"); const dirtyPrevious = { ...legacy, segment_targets: ["D1", "D9", "D10"] as const, segment_minutes: golden.scan.minutes, segment_order_enabled: true, segment_scan_complete: true }; const restored = buildProductCaseInferenceState({ ...input, previous: dirtyPrevious }, null); assert.equal(restored.segment_summary, undefined); assert.equal(restored.segment_targets, undefined); assert.equal(restored.segment_minutes, undefined); });