import assert from "node:assert/strict"; import test from "node:test"; import { readFileSync } from "node:fs"; import { clusterEquivalentCandidates } from "../src/lib/rectification-agentic/core/cluster-candidates.ts"; import { buildInferenceState } from "../src/lib/rectification-agentic/core/build-state.ts"; import { remainingSplitLayers } from "../src/lib/rectification-agentic/v9/collection-question-pool.ts"; import { lagnaContrastIntervalLabel, parseLagnaContrast } from "../src/lib/rectification-agentic/v9/refinement-packet.ts"; test("native lagna absolute endpoints survive parsing and board formatting", () => { const fixture = JSON.parse(readFileSync(new URL("./fixtures/rectification-dated-lagna.native.json", import.meta.url), "utf8")); const parsed = parseLagnaContrast(fixture.lagna_contrast)!; assert.ok(parsed); assert.deepEqual(parsed.intervals.map((row) => [row.start_at, row.end_at, row.segment_index]), fixture.lagna_contrast.intervals.map((row: Record) => [row.start_at, row.end_at, row.segment_index])); assert.match(lagnaContrastIntervalLabel(parsed.intervals[0]!), /2000-02-29 23:58.*2000-03-01 00:02/); assert.match(parsed.user_meaning, /2000-02-29 23:58/); const source = readFileSync(new URL("../src/components/rectification-board.tsx", import.meta.url), "utf8"); assert.match(source, /\{lagnaContrastIntervalLabel\(interval\)\}/); }); // Synthetic arithmetic cases, not engine-response goldens. const candidate = (time: string, index: number, offset: number, segment: number) => ({ id: time, time, score: 1, relative_support: 1, candidate_date: time.startsWith("23") ? "2000-06-14" : "2000-06-15", window_index: index, window_offset_minutes: offset, segment_index: segment, }); test("dated equivalent clustering respects segment boundaries and midnight adjacency", () => { const disjoint = [candidate("10:00", 0, 0, 0), candidate("10:02", 1, 2, 1)]; assert.equal(clusterEquivalentCandidates(disjoint).length, 2); const midnight = [candidate("23:59", 0, 0, 0), candidate("00:00", 1, 1, 0)]; assert.deepEqual(clusterEquivalentCandidates(midnight).map((row) => row.member_ids), [["23:59", "00:00"]]); assert.equal(clusterEquivalentCandidates(midnight, ["00:00"]).length, 2); assert.equal(clusterEquivalentCandidates([candidate("10:00", 0, 0, 0), candidate("10:05", 1, 5, 0)]).length, 2); const state = buildInferenceState({ range_start: "10:00", range_end: "10:02", candidates: disjoint, events: [], probes: [] }); assert.ok(state.candidates.every((row) => row.status === "active")); assert.deepEqual(state.candidates.map((row) => row.posterior_score), [1, 1]); }); test("dated and legacy ordinary same-day equivalent clusters match", () => { const dated = [candidate("10:00", 0, 0, 0), candidate("10:01", 1, 1, 0)]; assert.deepEqual(clusterEquivalentCandidates(dated), clusterEquivalentCandidates(dated.map(({ id, time, score }) => ({ id, time, score })))); }); const bound = { candidate_date: "2000-06-15", segment_index: 0, segment_start_at: "2000-06-15T10:00", segment_end_at: "2000-06-15T10:10" }; const transitions = [ { ...bound, layer: "d9", at: "10:00", window_index: 0, window_offset_minutes: 0, segment_start: true, from_sign: "白羊", to_sign: "白羊" }, { ...bound, layer: "d9", at: "10:10", window_index: 10, window_offset_minutes: 10, from_sign: "白羊", to_sign: "金牛" }, { ...bound, layer: "d10", at: "10:00", window_index: 0, window_offset_minutes: 0, segment_start: true, from_sign: "白羊", to_sign: "白羊" }, { ...bound, layer: "d10", at: "10:01", window_index: 1, window_offset_minutes: 1, from_sign: "白羊", to_sign: "金牛" }, ]; test("active subset excludes eliminated D9 split without resurrecting full-window flags", () => { assert.deepEqual(remainingSplitLayers({ transitions, activeTimes: ["10:00", "10:01"], scanFlags: { d9_candidates_differ: true } }), ["d10"]); assert.deepEqual(remainingSplitLayers({ transitions, activeTimes: ["10:02", "10:03"], scanFlags: { d9_candidates_differ: true, d10_candidates_differ: true } }), []); assert.deepEqual(remainingSplitLayers({ transitions: transitions.filter((row) => !("segment_start" in row && row.segment_start)).map(({ layer, at }) => ({ layer, at })), activeTimes: ["10:00", "10:01"] }), ["d10"]); }); test("separate segment starts only justify collection when surviving signs differ", () => { const starts = [transitions[0]!, { ...transitions[0]!, at: "12:00", segment_start_at: "2000-06-15T12:00", segment_end_at: "2000-06-15T12:01", segment_index: 1, window_index: 11, window_offset_minutes: 120 }]; assert.deepEqual(remainingSplitLayers({ transitions: starts, activeTimes: ["10:00", "12:00"] }), []); assert.deepEqual(remainingSplitLayers({ transitions: [starts[0]!, { ...starts[1]!, from_sign: "金牛", to_sign: "金牛" }], activeTimes: ["10:00", "12:00"] }), ["d9"]); }); test("dated lagna parser keeps absolute endpoints and rejects partial or impossible dates", () => { const interval = { start: "23:59", end: "00:00", lagna: "白羊", lords: {}, start_at: "2000-06-14T23:59", end_at: "2000-06-15T00:00", segment_index: 0 }; const second = { ...interval, start: "00:01", end: "00:02", start_at: "2000-06-15T00:01", end_at: "2000-06-15T00:02" }; const parsed = parseLagnaContrast({ intervals: [interval, second] }); assert.equal((parsed?.intervals[0] as unknown as Record)?.start_at, interval.start_at); assert.match(parsed!.user_meaning, /2000-06-14 23:59/); for (const patch of [{ start_at: "2000-02-30T23:59" }, { end_at: undefined }, { segment_index: -1 }, { start_at: "2000-06-14T23:58" }]) { assert.equal(parseLagnaContrast({ intervals: [{ ...interval, ...patch }, second] }), null); } });