Files
Jyotisha/frontend/tests/rectification-dated-transitions.test.ts
T
jesse-ux b85c4a686a
Independent Staging Quality Gate / validate (push) Successful in 13m27s
Independent Staging Quality Gate / publish (push) Failing after 1h0m1s
fix(rectification): anchor candidate windows to civil dates across midnight
Carry explicit local date intervals instead of inferring the day from clock
order. Cluster width, delivery, adoption, and reports keep the actual civil
date; adopted date is stored separately from the reported birth_date.

Algorithm identity is scoring-9 / spec-v5. Scoring weights, confirmation
thresholds, and Skill version are unchanged. Isolated Linux final-3 gates
passed; four pre-existing Python failures remain. This is not a production
release.
2026-09-21 02:55:00 +08:00

90 lines
6.0 KiB
TypeScript

import assert from "node:assert/strict";
import test from "node:test";
import { readFileSync } from "node:fs";
import { parseWindowScanTransitions } from "../src/lib/rectification-agentic/v9/refinement-packet.ts";
import { signFromTransitions } from "../src/lib/rectification-agentic/core/sign-from-transitions.ts";
import { remainingLayerGroups } from "../src/lib/rectification-agentic/core/candidate-contrast-packet.ts";
import { remainingSplitLayers } from "../src/lib/rectification-agentic/v9/collection-question-pool.ts";
test("native dated scan preserves every candidate's actual sign across midnight", () => {
const fixture = JSON.parse(readFileSync(new URL("./fixtures/rectification-dated-transitions.native.json", import.meta.url), "utf8")) as {
scan: { transitions: readonly Record<string, unknown>[] };
expected_signs: Record<string, Record<string, string>>;
};
const parsed = parseWindowScanTransitions(fixture.scan.transitions);
assert.equal(parsed.length, fixture.scan.transitions.length);
assert.ok(parsed.some((row) => row.segment_start));
for (const [time, signs] of Object.entries(fixture.expected_signs)) {
for (const [layer, sign] of Object.entries(signs)) {
assert.equal(signFromTransitions(parsed, layer, time), sign, `${layer} at ${time}`);
}
}
assert.equal(signFromTransitions(parsed, "d9", "12:00"), null);
});
// Synthetic lookup arithmetic, not a fabricated engine response/golden.
const bounds = { segment_start_at: "2000-06-14T23:58", segment_end_at: "2000-06-15T00:01" };
const raw = [
{ layer: "d9", at: "23:58", candidate_date: "2000-06-14", window_index: 0, window_offset_minutes: 0, segment_index: 0, segment_start: true, from_sign: "白羊", to_sign: "白羊", ...bounds },
{ layer: "d9", at: "23:59", candidate_date: "2000-06-14", window_index: 1, window_offset_minutes: 1, segment_index: 0, from_sign: "白羊", to_sign: "金牛", ...bounds },
{ layer: "d9", at: "00:00", candidate_date: "2000-06-15", window_index: 2, window_offset_minutes: 2, segment_index: 0, from_sign: "金牛", to_sign: "双子", ...bounds },
];
test("dated transition parser retains civil order and midnight sign lookup", () => {
const parsed = parseWindowScanTransitions(raw);
assert.equal(signFromTransitions(parsed, "d9", "23:58"), "白羊");
assert.equal(signFromTransitions(parsed, "d9", "23:59"), "金牛");
assert.equal(signFromTransitions(parsed, "d9", "00:00"), "双子");
assert.equal(signFromTransitions(parsed, "d9", "00:01"), "双子");
assert.equal(signFromTransitions(parsed, "d9", "12:00"), null);
assert.deepEqual(remainingLayerGroups(["00:01", "23:59", "00:00", "23:58"], parsed, "d9"), [["23:58"], ["23:59"], ["00:00", "00:01"]]);
});
test("declared segment gap is not inferred as a transition or a covered minute", () => {
const parsed = parseWindowScanTransitions([
{ ...raw[0], at: "00:00", candidate_date: "2000-06-15", segment_start_at: "2000-06-15T00:00", segment_end_at: "2000-06-15T00:01" },
{ ...raw[0], at: "23:00", candidate_date: "2000-06-15", window_index: 2, window_offset_minutes: 1380, segment_index: 1, from_sign: "处女", to_sign: "处女", segment_start_at: "2000-06-15T23:00", segment_end_at: "2000-06-15T23:01" },
]);
assert.equal(signFromTransitions(parsed, "d9", "00:01"), "白羊");
assert.equal(signFromTransitions(parsed, "d9", "23:01"), "处女");
assert.equal(signFromTransitions(parsed, "d9", "12:00"), null);
assert.deepEqual(remainingLayerGroups(["23:01", "00:01", "12:00"], parsed, "d9"), [["00:01"], ["23:01"]]);
});
test("malformed or partial dated transition contract fails closed", () => {
for (const patch of [{ candidate_date: "2000-02-30" }, { window_index: -1 }, { segment_end_at: null }, { candidate_date: undefined }, { at: "24:00" }, { layer: "unknown" }]) {
assert.deepEqual(parseWindowScanTransitions([{ ...raw[0], ...patch }]), []);
assert.deepEqual(parseWindowScanTransitions([raw[0], { ...raw[1], ...patch }]), []);
}
});
test("dated transitions reject inconsistent offsets, missing starts and mixed historical rows", () => {
assert.deepEqual(parseWindowScanTransitions(raw.slice(1)), []);
assert.deepEqual(parseWindowScanTransitions([raw[0], { ...raw[1], window_offset_minutes: 2 }]), []);
assert.deepEqual(parseWindowScanTransitions([raw[0], { ...raw[1], window_index: 0 }]), []);
assert.deepEqual(parseWindowScanTransitions([raw[0], { layer: "d9", at: "00:00", from_sign: "金牛", to_sign: "双子" }]), []);
});
test("same-day dated changes keep legacy sign assignments and grouping", () => {
const dated = parseWindowScanTransitions(raw.map((row, i) => ({ ...row, at: `10:0${i}`, candidate_date: "2000-06-15",
segment_start_at: "2000-06-15T10:00", segment_end_at: "2000-06-15T10:03" })));
const legacy = parseWindowScanTransitions(dated.filter((row) => !row.segment_start).map((row) => ({ layer: row.layer, at: row.at, from_sign: row.from_sign, to_sign: row.to_sign })));
const times = ["10:00", "10:01", "10:02", "10:03"];
assert.deepEqual(times.map((time) => signFromTransitions(dated, "d9", time)), times.map((time) => signFromTransitions(legacy, "d9", time)));
assert.deepEqual(remainingLayerGroups(times, dated, "d9"), remainingLayerGroups(times, legacy, "d9"));
});
test("segment initial states do not trigger a remaining-layer question", () => {
const markers = parseWindowScanTransitions([raw[0]]);
assert.deepEqual(remainingSplitLayers({ transitions: markers, activeTimes: ["23:58", "00:01"] }), []);
assert.deepEqual(remainingSplitLayers({ transitions: parseWindowScanTransitions(raw), activeTimes: ["23:58", "00:01"] }), ["d9"]);
});
test("legacy transitions retain old lookup and grouping", () => {
const parsed = parseWindowScanTransitions([{ layer: "d9", at: "10:01", from_sign: "白羊", to_sign: "金牛" }]);
assert.equal(signFromTransitions(parsed, "d9", "10:00"), "白羊");
assert.equal(signFromTransitions(parsed, "d9", "10:02"), "金牛");
assert.deepEqual(remainingLayerGroups(["10:00", "10:01", "10:02"], parsed, "d9"), [["10:00"], ["10:01", "10:02"]]);
assert.equal("candidate_date" in parsed[0]!, false);
});