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.
90 lines
6.0 KiB
TypeScript
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);
|
|
});
|