fix(rectification): anchor candidate windows to civil dates across midnight
Independent Staging Quality Gate / validate (push) Successful in 13m27s
Independent Staging Quality Gate / publish (push) Failing after 1h0m1s

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.
This commit is contained in:
jesse-ux
2026-09-21 02:55:00 +08:00
parent 3be740f84d
commit b85c4a686a
115 changed files with 106484 additions and 315 deletions
@@ -27,8 +27,13 @@ import {
const golden = JSON.parse(readFileSync(new URL(
"./fixtures/rectification-engine-version-cross-midnight-golden.json", import.meta.url,
), "utf8"));
// Historical golden identity stays fixed; it must not be relabeled as the live engine.
const CURRENT = "rectification-v5-matrix-scoring-8";
const PREVIOUS = "rectification-v5-matrix-scoring-7";
const LIVE_CURRENT = "rectification-v5-matrix-scoring-9";
const liveGolden = JSON.parse(readFileSync(new URL(
"./fixtures/rectification-midnight-date-anchor.delivery.native.json", import.meta.url,
), "utf8"));
const envKeys = [
"RECTIFICATION_ENGINE_VERSION", "RECTIFICATION_ALGORITHM_VERSION",
"RECTIFICATION_DECISION_POLICY_VERSION",
@@ -47,15 +52,25 @@ function isolateIdentityEnv(t: test.TestContext) {
test("receipt default matches the cross-midnight native scoring version without changing Skill identity", (t) => {
isolateIdentityEnv(t);
assert.equal(v9EngineVersion(), CURRENT);
assert.equal(v9EngineVersion(), LIVE_CURRENT);
for (const blank of ["", " "]) {
process.env.RECTIFICATION_ENGINE_VERSION = blank;
assert.equal(v9EngineVersion(), CURRENT);
assert.equal(v9EngineVersion(), LIVE_CURRENT);
}
assert.equal(golden.score.algorithm_version, CURRENT);
assert.equal(golden.versions.algorithm_version, CURRENT);
const python = readFileSync(new URL("../../scripts/rectification/scoring_service.py", import.meta.url), "utf8");
assert.match(python, /ALGORITHM_VERSION = "rectification-v5-matrix-scoring-8"/);
assert.match(python, /ALGORITHM_VERSION = "rectification-v5-matrix-scoring-9"/);
assert.equal(liveGolden.response.algorithm_version, LIVE_CURRENT);
const fingerprints = { evidenceLedgerFingerprint: "e".repeat(64), candidateRangeFingerprint: "c".repeat(64) };
const live = {
algorithmVersion: liveGolden.response.algorithm_version,
policyVersion: liveGolden.response.decision_policy_version,
};
const historical = { ...fingerprints, algorithmVersion: CURRENT, policyVersion: golden.versions.decision_policy_version };
assert.equal(cachedEngineScoreIsReusable(historical, fingerprints, live), false);
assert.equal(cachedEngineScoreIsReusable({ ...historical, algorithmVersion: LIVE_CURRENT }, fingerprints, live), true);
assert.equal(historical.algorithmVersion, CURRENT, "checking live identity never relabels history");
// A receipt default must not become an environment override for cache identity.
assert.deepEqual(liveEngineScoringIdentityFromEnv({}), { algorithmVersion: null, policyVersion: null });
});
@@ -338,14 +353,28 @@ test("missing stage source, absent results and nonlatest result IDs cannot autho
assert.equal(resultIdentityView(parseV9CaseDossier(empty)!, { algorithmVersion: null, policyVersion: null }).read_only, false);
});
const historicalGolden = golden;
async function runGoldenToolSequence(t: test.TestContext, options: {
compareVersion?: string;
diagnosticsVersion?: string;
diagnosticsFailure?: boolean;
useLiveGolden?: boolean;
} = {}) {
isolateIdentityEnv(t);
// A scoring-9 response needs its real dated contract, never a relabeled scoring-8 fixture.
const golden = options.useLiveGolden ? {
request: liveGolden.request,
score: liveGolden.response,
versions: {
algorithm_version: liveGolden.response.algorithm_version,
decision_policy_version: liveGolden.response.decision_policy_version,
},
} : historicalGolden;
const request = golden.request;
const candidateRange = { start_time: request.start_time, end_time: request.end_time };
const candidateRange = {
start_time: request.start_time, end_time: request.end_time,
...(request.candidate_intervals ? { candidate_intervals: request.candidate_intervals } : {}),
};
const evidence = request.events.map((event: Record<string, string>) => ({
id: event.id, source_turn_id: TURN_ID, subject: "self", event_kind: event.event_kind,
domain: event.domain, occurred_from: event.date_start, occurred_to: event.date_end,
@@ -395,11 +424,11 @@ async function runGoldenToolSequence(t: test.TestContext, options: {
if (options.diagnosticsFailure && name === "rectification-read-diagnostics") await assert.rejects(execute);
else {
const projection = await execute() as { read_only?: boolean; algorithm_version?: string; can_confirm_exact_minute?: boolean };
if (name === "rectification-compare-candidates" && options.compareVersion && options.compareVersion !== CURRENT) {
if (name === "rectification-compare-candidates" && options.compareVersion && options.compareVersion !== golden.versions.algorithm_version) {
assert.equal(projection.read_only, true, "rolling response mismatch stays read-only after saving true provenance");
assert.equal(projection.algorithm_version, options.compareVersion);
}
if (name === "rectification-read-diagnostics" && options.diagnosticsVersion && options.diagnosticsVersion !== CURRENT) {
if (name === "rectification-read-diagnostics" && options.diagnosticsVersion && options.diagnosticsVersion !== golden.versions.algorithm_version) {
assert.equal(projection.read_only, true);
assert.equal(projection.algorithm_version, options.diagnosticsVersion);
assert.equal(projection.can_confirm_exact_minute, false, "rolling diagnostics cannot claim current validation");
@@ -432,7 +461,7 @@ test("mixed completed identities require chronological aggregation (covered by d
// remain the real native golden. This is not a claim to have run future algorithms.
const version9 = "rectification-v5-matrix-scoring-9";
const version10 = "rectification-v5-matrix-scoring-10";
const receipts = await runGoldenToolSequence(t, { compareVersion: version9, diagnosticsVersion: version10 });
const receipts = await runGoldenToolSequence(t, { compareVersion: version9, diagnosticsVersion: version10, useLiveGolden: true });
const completed = receipts.filter((call) => call.args.p_status === "completed");
assert.equal(new Set(completed.map((call) => call.args.p_turn_id)).size, 1);
assert.deepEqual(completed.map((call) => call.args.p_engine_version), [version9, version10]);
@@ -466,7 +495,7 @@ test("history opens with its bound Skill and reads old engine receipt values unc
});
assert.equal(opened.disposition, "readonly");
const receipt = await loadV9TurnReceipt(accounting.client as never, USER_ID, CASE_ID, TURN_ID);
assert.equal(v9EngineVersion(), CURRENT);
assert.equal(v9EngineVersion(), LIVE_CURRENT);
assert.equal(receipt?.engineVersion, oldVersion);
assert.deepEqual(historical, before);
assert.equal(accounting.calls.some((call) => /insert|persist|upgrade/.test(call.fn)), false);