Files
Jyotisha/frontend/tests/rectification-varga-segments-20260930.test.ts
T
66f087b588 feat(rectification): submit varga-resolution implementation for review
Review-only snapshot for BUG-1115 through BUG-1117; not merge-ready. New opening and append-turn PostgreSQL permission failures remain blocked. Persisted joint replay has zero completed questions; segment ordering remains off by default. The existing offline replay JSON is retained stale and unchanged after a denied overwrite, including its CRLF line endings. Browser/provider validation and final serial gates remain pending. No deployment, role permission changes, or staging/main push.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-01 08:04:04 +08:00

165 lines
11 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import { applyProbeOutcome } from "../src/lib/rectification-agentic/core/apply-probe-outcome.ts";
import { rawMinuteWeights, summarizeSegmentWeights, confidenceTier, targetChartsForDomain, buildSegmentSummary } from "../src/lib/rectification-agentic/core/segment-summary.ts";
import { segmentInformationGain } from "../src/lib/rectification-agentic/core/segment-probe-order.ts";
import type { ConflictProbe, AnswerClass } from "../src/lib/rectification-agentic/core/types.ts";
import { buildInferenceState, nextProbe, applyAnswerToState } from "../src/lib/rectification-agentic/core/build-state.ts";
import { buildCaseInferenceState } from "../src/lib/rectification-agentic/v9/inference-adapter.ts";
import type { DiscriminatingEventProbe } from "../src/lib/rectification-agentic/v9/refinement-packet.ts";
import { asInferenceState } from "../src/lib/rectification-agentic/core/compose-receipt.ts";
import { parseSegmentSummary, type TargetChart } from "../src/lib/rectification-agentic/core/segment-summary.ts";
const fixture = JSON.parse(fs.readFileSync(new URL("./fixtures/varga-segment-v5-golden.json", import.meta.url), "utf8"));
for (const record of fixture.records) {
test(`v5 raw segment parity ${record.case_id} ±${record.radius} ${record.chart}`, () => {
const weights = rawMinuteWeights(record.posterior_rows.map((row: { time: string; score: number; cluster_times: string[] }) => ({ ...row, eliminated: record.eliminated.includes(row.time) })));
const { tied, ...summary } = summarizeSegmentWeights(weights, record.segments, record.offsets, 0);
assert.equal(typeof tied, "boolean");
assert.deepEqual(summary, record.expected_summary);
});
test(`v5 production inference raw assembly ${record.case_id} ±${record.radius} ${record.chart}`, () => {
const probes: ConflictProbe[] = record.probes.map((probe: ConflictProbe & { user_meaning: string }) => ({ ...probe, id: probe.semantic_key, question: probe.user_meaning }));
const start = Object.entries(record.offsets).find(([, offset]) => offset === -record.radius)![0];
const end = Object.entries(record.offsets).find(([, offset]) => offset === record.radius)![0];
const origin = Number(start.slice(0, 2)) * 60 + Number(start.slice(3));
const minutes = Array.from({ length: 2 * record.radius + 1 }, (_, offset) => {
const clock = (origin + offset) % 1440;
return { time: `${String(Math.floor(clock / 60)).padStart(2, "0")}:${String(clock % 60).padStart(2, "0")}`, offset,
signs: { [record.chart]: record.segments.find((segment: { start: number; end: number }) =>
segment.start <= offset - record.radius && offset - record.radius <= segment.end).key[0] } };
});
const state = buildInferenceState({ range_start: start, range_end: end,
candidates: record.rows.map((row: { time: string; score: number; cluster_times: string[] }) => ({
id: row.time, time: row.time, relative_support: row.score * 3, raw_score: row.score, cluster_times: row.cluster_times,
})), events: [], probes,
answered_probes: probes.slice(0, 6).flatMap((probe) => {
const answer = record.answers[probe.semantic_key] as AnswerClass | null;
return answer ? [{ probe_id: probe.id, semantic_key: probe.semantic_key, candidate_split_hash: probe.candidate_split_hash,
answer_class: answer, classified_from: "choice" as const }] : [];
}), segment_minutes: minutes, segment_targets: [record.chart as TargetChart], segment_scan_complete: true,
});
for (const row of record.posterior_rows) {
const candidate = state.candidates.find((candidate) => candidate.time === row.time)!;
assert.equal(Number(candidate.raw_posterior_score!.toFixed(4)), Number(row.score.toFixed(4)));
assert.equal(candidate.raw_eliminated, record.eliminated.includes(row.time));
}
const chart = state.segment_summary!.charts[0]!;
for (const key of ["shares", "top_share", "top_segment", "alive_segments"] as const) {
assert.deepEqual(chart[key], record.expected_summary[key]);
}
assert.ok(parseSegmentSummary(state.segment_summary));
if (start <= end) {
assert.deepEqual(asInferenceState(JSON.parse(JSON.stringify(state)))?.segment_summary, state.segment_summary);
const tampered = structuredClone(state);
(tampered.segment_summary!.charts[0] as { top_share: number }).top_share = 0.123456;
const parsed = asInferenceState(tampered);
assert.ok(parsed);
assert.equal(parsed.segment_summary, undefined);
assert.deepEqual(parsed.candidates, state.candidates);
}
let sequential = buildCaseInferenceState({ range: { start_time: start, end_time: end },
candidates: record.rows.map((row: { time: string; score: number; cluster_times: string[] }) => ({
candidateId: row.time, time: row.time, relativeSupport: row.score * 3, rawScore: row.score, clusterTimes: row.cluster_times,
})), evidence: [], probes: record.probes as DiscriminatingEventProbe[],
segmentMinutes: minutes, segmentTargets: [record.chart as TargetChart], segmentScanComplete: true, segmentOrderEnabled: true,
});
const asked: string[] = [];
const unanswered = new Set<string>();
for (let round = 0; round < 6; round++) {
const live = { ...sequential, probes: sequential.probes.filter((probe) => !unanswered.has(probe.id)) };
const probe = nextProbe(live);
if (!probe) break;
asked.push(probe.semantic_key);
const answer = record.answers[probe.semantic_key] as AnswerClass | null;
if (answer) sequential = applyAnswerToState(sequential, probe.id, answer);
else unanswered.add(probe.id);
}
assert.deepEqual(asked, record.expected_order);
});
test(`v5 sequential segment question parity ${record.case_id} ±${record.radius} ${record.chart}`, () => {
let scores: Record<string, number> = Object.fromEntries(record.rows.map((row: { time: string; score: number }) => [row.time, row.score]));
let conflicts: Record<string, number> = {};
const eliminated = new Set<string>();
const remaining: ConflictProbe[] = record.probes.map((probe: ConflictProbe) => ({ ...probe, id: probe.semantic_key, choice_kind: undefined }));
const asked: string[] = [];
for (let round = 0; round < 6 && remaining.length; round++) {
const weights = rawMinuteWeights(record.rows.map((row: { time: string; cluster_times: string[] }) => ({ ...row, score: scores[row.time]!, eliminated: eliminated.has(row.time) })));
const ranked = remaining.map((probe, index) => ({ index, gain: segmentInformationGain(probe, weights, record.segments, record.offsets) }))
.sort((a, b) => b.gain - a.gain || a.index - b.index);
const probe = remaining.splice(ranked[0]!.index, 1)[0]!;
asked.push(probe.semantic_key);
const answer = record.answers[probe.semantic_key];
if (!answer) continue;
const updated = applyProbeOutcome(scores, probe, answer, { eliminatedIds: eliminated, strongConflictCounts: conflicts });
scores = { ...updated.scores }; conflicts = { ...updated.strong_conflict_counts };
updated.eliminated_ids.forEach((id) => eliminated.add(id));
}
assert.deepEqual(asked, record.expected_order);
});
}
test("malformed optional chart metadata never erases the frozen historical inference", () => {
const historical = buildInferenceState({ range_start: "12:00", range_end: "12:02", events: [], probes: [],
candidates: [{ id: "12:00", time: "12:00", relative_support: 60 }, { id: "12:02", time: "12:02", relative_support: 50 }] });
for (const patch of [{ signature: "invalid" }, { raw_prior_score: NaN }, { raw_posterior_score: Infinity },
{ cluster_times: ["not-a-clock"] }, { raw_eliminated: "false" }]) {
const malformed = structuredClone(historical);
Object.assign(malformed.candidates[0]!, patch);
const parsed = asInferenceState(malformed);
assert.ok(parsed);
assert.equal(parsed.segment_summary, undefined);
assert.equal(parsed.candidates[0]!.posterior_score, historical.candidates[0]!.posterior_score);
assert.deepEqual(parsed.answered_probes, historical.answered_probes);
assert.equal(parsed.candidates[0]!.raw_prior_score, undefined);
assert.equal(parsed.candidates[0]!.cluster_times, undefined);
}
});
test("segment alternatives retain unrounded leaders and positive masses below display precision", () => {
// Fictional numerical boundary, not an engine calibration fixture.
for (const scores of [[100, 100.0001], [7.999999, 1e-7]]) {
const summary = buildSegmentSummary({ targets: ["D1"], windowMinutes: 2, scanComplete: true,
minutes: [{ offset: 0, time: "09:00", signs: { D1: 1 } }, { offset: 1, time: "09:01", signs: { D1: 2 } }],
candidates: [{ time: "09:00", score: scores[0]! }, { time: "09:01", score: scores[1]! }] });
const chart = summary.charts[0]!;
assert.equal(chart.top_segment, scores[1]! > scores[0]! ? 1 : 0);
assert.equal(chart.tied, false);
assert.deepEqual(chart.alternatives, [chart.sign === 2 ? 1 : 2]);
assert.equal(chart.alive_segments, 2);
assert.ok(parseSegmentSummary(summary));
if (chart.top_segment === 1) assert.deepEqual(chart.shares, [0.5, 0.5]);
else assert.equal(chart.shares[1], 0);
}
});
test("confidence tiers follow calibrated boundaries only", () => {
for (const width of [21, 61, 121]) {
assert.equal(confidenceTier("D1", width, 0.1, true), "certain");
assert.equal(confidenceTier("D1", width, 0.6, false), "credible");
assert.equal(confidenceTier("D1", width, 0.5, false), width === 21 ? "tentative" : "indistinct");
assert.equal(confidenceTier("D1", width, 0.49, false), "indistinct");
assert.equal(confidenceTier("D9", width, 0.9, false), width > 61 ? "blocked" : "credible");
assert.equal(confidenceTier("D10", width, 0.5, false), width > 61 ? "blocked" : width === 21 ? "tentative" : "indistinct");
}
});
test("seven domains never add uncalibrated charts", () => {
for (const domain of ["relationship", "career", "health", "family", "relocation", "finance", "education"]) {
assert.deepEqual(targetChartsForDomain(domain), domain === "relationship" ? ["D1", "D9"] : domain === "career" ? ["D1", "D10"] : ["D1", "D9", "D10"]);
}
});
test("equal segment masses choose earliest and expose tie; adoption stays in delivery", () => {
const summary = buildSegmentSummary({ targets: ["D1"], windowMinutes: 3, scanComplete: true,
minutes: [{ offset: 0, time: "23:59", date: "2000-01-01", signs: { D1: 1 } }, { offset: 1, time: "00:00", date: "2000-01-02", signs: { D1: 2 } }, { offset: 2, time: "00:01", date: "2000-01-02", signs: { D1: 2 } }],
candidates: [{ time: "23:59", score: 10 }, { time: "00:01", score: 10 }], deliveredOffsets: [[1, 2]],
});
assert.equal(summary.charts[0]!.top_segment, 0);
assert.equal(summary.charts[0]!.tied, true);
assert.equal(summary.adoption_minute?.date, "2000-01-02");
assert.equal(summary.adoption_minute?.offset, 1);
assert.equal(summary.no_rectification_needed, false);
});