Files
Jyotisha/frontend/tests/rectification-adopted-chart-tiers.test.ts
T
Jesse_ChenandClaude Opus 5.5 8e901125a9 fix(rectification): judge chart reliability against the saved minute, not the result's head (BUG-1138 review)
A chart is reliable only when its tier is not blocked/indistinct and the saved
minute (provenance window_offset_minutes) sits in that chart's head segment, or
the chart never changes in the window; a missing offset is not reliable. The
saved minute does not move with later results, and D7 falls back to the D1 head
midpoint when heads do not intersect, so the tier alone could name a sign the
saved minute does not have.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-10-01 10:15:10 +08:00

140 lines
7.9 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
import { buildSegmentSummary, type SegmentMinute } from "../src/lib/rectification-agentic/core/segment-summary.ts";
import {
CASE_DOSSIER_RPC,
chartTiersFromDossier,
clearAdoptedChartTierCache,
loadAdoptedChartTiers,
segmentProvenance,
} from "../src/lib/rectification-adopted-chart-tiers.ts";
// Real native scan of a public Rodden-AA case (31-minute window), not a hand-built shape.
const golden = JSON.parse(readFileSync(new URL("./fixtures/varga-api-response.golden.json", import.meta.url), "utf8"));
const realMinutes = golden.scan.minutes as SegmentMinute[];
const userId = "11111111-1111-4111-8111-111111111111";
const caseId = "22222222-2222-4222-8222-222222222222";
const resultId = "33333333-3333-4333-8333-333333333333";
const newerResultId = "44444444-4444-4444-8444-444444444444";
const segmentV1 = { contract: "segment-v1", case_id: caseId, result_id: resultId, candidate_time: "09:05", window_offset_minutes: 60 };
// Real 31-minute scan: D1 is one sign (certain); every candidate weighs on the
// first D9/D10 segments so the posterior picks them.
function realSummary() {
const candidates = realMinutes.filter((_, index) => index % 2 === 0).map((minute) => ({ time: minute.time, score: minute.offset <= 4 ? 12 : 1 }));
return buildSegmentSummary({ minutes: realMinutes, candidates, windowMinutes: realMinutes.length, scanComplete: true });
}
// Explicitly fictional ±60 control: a 121-minute window makes D9/D10 blocked by width alone.
function wideSummary() {
const minutes: SegmentMinute[] = Array.from({ length: 121 }, (_, offset) => ({
offset, date: "2000-06-14", time: `${String(8 + Math.floor(offset / 60)).padStart(2, "0")}:${String(offset % 60).padStart(2, "0")}`,
signs: { D1: 4, D9: Math.floor(offset / 13) % 12, D10: Math.floor(offset / 12) % 12 },
}));
return buildSegmentSummary({ minutes, candidates: [{ time: minutes[60]!.time, score: 10 }], windowMinutes: 121, scanComplete: true });
}
function dossier(summary: unknown, id = resultId, owningCase = caseId) {
return { case: { case_id: owningCase }, latest_result: { result_id: id, decision_receipt: { inference_state: { segment_summary: summary } } } };
}
function client(data: unknown, error: unknown = null) {
const calls: { fn: string; args: Record<string, unknown> }[] = [];
return {
calls,
rpc: async (fn: string, args: Record<string, unknown>) => { calls.push({ fn, args }); return { data, error }; },
};
}
test("provenance: only segment-v1 with uuid case/result is read", () => {
assert.deepEqual(segmentProvenance(segmentV1), { caseId, resultId, windowOffset: 60 });
assert.deepEqual(segmentProvenance({ ...segmentV1, window_offset_minutes: undefined }), { caseId, resultId, windowOffset: null });
for (const value of [null, {}, { contract: "candidate-v2", case_id: caseId, result_id: resultId }, { ...segmentV1, case_id: "x" }, "segment-v1"]) {
assert.equal(segmentProvenance(value), null);
}
});
test("five inputs: segment-v1 / legacy adoption / unrectified / missing result / corrupt summary", async () => {
clearAdoptedChartTierCache();
const warnings: string[] = [];
const warn = (payload: { reason: string }) => { warnings.push(payload.reason); };
// 1. segment-v1 with a wide window: D9 and D10 blocked, D1 determined.
const wide = client(dossier(wideSummary()));
assert.deepEqual(await loadAdoptedChartTiers(wide, { userId, provenance: segmentV1 }, warn),
{ source: "segment-v1", resultMatch: "adopted", unreliable: ["D9", "D10"] });
assert.deepEqual(wide.calls, [{ fn: CASE_DOSSIER_RPC, args: { p_user_id: userId, p_case_id: caseId } }]);
// 2. Legacy (candidate-minute) adoption and 3. unrectified profile: no RPC, null.
const untouched = client(dossier(wideSummary()));
assert.equal(await loadAdoptedChartTiers(untouched, { userId, provenance: { contract: "candidate-v2", case_id: caseId, result_id: resultId } }, warn), null);
assert.equal(await loadAdoptedChartTiers(untouched, { userId, provenance: null }, warn), null);
assert.equal(untouched.calls.length, 0);
// 4. Result missing (RPC error, or a dossier without a latest result): null and a warning.
clearAdoptedChartTierCache();
assert.equal(await loadAdoptedChartTiers(client(null, { code: "P0001" }), { userId, provenance: segmentV1 }, warn), null);
assert.equal(await loadAdoptedChartTiers(client({ case: { case_id: caseId } }), { userId, provenance: segmentV1 }, warn), null);
// 5. Corrupt summary (tier inconsistent with its own shares): null and a warning.
const corrupt = JSON.parse(JSON.stringify(wideSummary()));
corrupt.charts[1].tier = "credible";
assert.equal(await loadAdoptedChartTiers(client(dossier(corrupt)), { userId, provenance: segmentV1 }, warn), null);
assert.deepEqual(warnings, ["P0001", "invalid_segment_summary", "invalid_segment_summary"]);
});
test("real narrow scan: certain D1 and credible D9/D10 are not flagged", () => {
const summary = realSummary();
const tiers = Object.fromEntries(summary.charts.map((chart) => [chart.chart, chart.tier]));
assert.equal(tiers.D1, "certain");
// The saved minute is what D7 adopted from this very summary.
const result = chartTiersFromDossier(dossier(summary), { caseId, resultId, windowOffset: summary.adoption_minute!.offset });
assert.notEqual(result, "invalid");
if (result === "invalid") return;
assert.deepEqual(result.unreliable, summary.charts.filter((chart) => chart.tier === "blocked" || chart.tier === "indistinct").map((chart) => chart.chart));
assert.ok(!result.unreliable.includes("D1"));
});
test("a newer result of the same Case is read; another Case never is", () => {
const newer = chartTiersFromDossier(dossier(wideSummary(), newerResultId), { caseId, resultId, windowOffset: 60 });
assert.deepEqual(newer, { source: "segment-v1", resultMatch: "latest", unreliable: ["D9", "D10"] });
assert.equal(chartTiersFromDossier(dossier(wideSummary(), resultId, "55555555-5555-4555-8555-555555555555"), { caseId, resultId, windowOffset: 60 }), "invalid");
});
test("results are cached per adopted result for five minutes", async () => {
clearAdoptedChartTierCache();
const reader = client(dossier(wideSummary()));
let now = 1_000;
await loadAdoptedChartTiers(reader, { userId, provenance: segmentV1 }, () => {}, () => now);
now += 60_000;
await loadAdoptedChartTiers(reader, { userId, provenance: segmentV1 }, () => {}, () => now);
assert.equal(reader.calls.length, 1);
now += 5 * 60_000;
await loadAdoptedChartTiers(reader, { userId, provenance: segmentV1 }, () => {}, () => now);
assert.equal(reader.calls.length, 2);
});
// Reviewer addition (Claude 2026-10-01): reliability is judged for the saved minute, not the head.
test("a credible chart is still flagged when the saved minute is outside its head segment", () => {
const summary = realSummary();
const d9 = summary.charts.find((chart) => chart.chart === "D9")!;
assert.ok(!["blocked", "indistinct"].includes(d9.tier) && !d9.full_window_unique, "fixture: D9 credible and changing");
const outside = d9.segments.find((segment) => segment.index !== d9.top_segment)!;
const moved = chartTiersFromDossier(dossier(summary, newerResultId), { caseId, resultId, windowOffset: outside.start });
assert.notEqual(moved, "invalid");
if (moved === "invalid") return;
assert.equal(moved.resultMatch, "latest");
assert.ok(moved.unreliable.includes("D9"), "saved minute's D9 differs from the head the card would name");
assert.ok(!moved.unreliable.includes("D1"), "D1 never changes in this window");
});
test("an unknown saved-minute offset flags every chart that changes in the window", () => {
const summary = realSummary();
const result = chartTiersFromDossier(dossier(summary), { caseId, resultId, windowOffset: null });
assert.notEqual(result, "invalid");
if (result === "invalid") return;
assert.deepEqual(result.unreliable, summary.charts.filter((chart) => !chart.full_window_unique).map((chart) => chart.chart));
});