fix(rectification): share datedPrecision for quarter and range events
Independent Staging Quality Gate / validate (push) Successful in 24m33s
Independent Staging Quality Gate / publish (push) Successful in 13m11s

Training already counted quarter/range as dated, while the inference ledger mapped them to unknown and left the events unused.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-28 23:19:09 +08:00
parent 53eb815c95
commit 2c5e8bf2e6
5 changed files with 43 additions and 3 deletions
@@ -165,7 +165,7 @@ export function datePrecisionRank(precision: string): number {
return PRECISION_RANK[precision] ?? -1;
}
function datedPrecision(value: string): DatedEventInput["precision"] {
export function datedPrecision(value: string): DatedEventInput["precision"] {
if (value === "day" || value === "month" || value === "year" || value === "unknown") return value;
return "year";
}
@@ -15,6 +15,7 @@ import { rankActive } from "../core/convergence-evaluator.ts";
import { rangeFromTimes, unionStillValidRange } from "../core/credible-range.ts";
import { previousInferenceFromReceipt } from "../core/compose-receipt.ts";
import type { AnswerClass, ConflictProbe, InferenceState } from "../core/types.ts";
import { datedPrecision } from "./evidence-model.ts";
import {
isHoldoutVerificationQuote,
type ChoiceKey,
@@ -28,8 +29,8 @@ function yearFrom(value: string | null | undefined): number | null {
}
function asPrecision(value: string | null | undefined): EngineEventInput["precision"] {
if (value === "day" || value === "month" || value === "year") return value;
return "unknown";
if (!value) return "unknown";
return datedPrecision(value);
}
export function askedProbeKeysFromReceipt(
@@ -196,6 +196,24 @@ test("a corrupted receipt range outside the window still fail-closes", () => {
assert.equal(projection.credibleRange, null);
});
test("quarter-precision evidence stays dated in the inference ledger", () => {
const state = buildCaseInferenceState({
range: { start_time: "05:00", end_time: "05:10" },
candidates: [
{ candidateId: "05:00", time: "05:00", relativeSupport: 50 },
{ candidateId: "05:10", time: "05:10", relativeSupport: 50 },
],
evidence: [
{ id: "q-career", domain: "career", occurredFrom: "2018-04-01", datePrecision: "quarter" },
{ id: "y-edu", domain: "education", occurredFrom: "2016-01-01", datePrecision: "year" },
],
probes: [],
});
const quarter = state.events.find((item) => item.id === "q-career");
assert.equal(quarter?.precision, "year");
assert.notEqual(quarter?.usage, "unused");
});
test("buildCaseInferenceState receipt is the producer of the projected range", () => {
const state = buildCaseInferenceState({
range: { start_time: "04:55", end_time: "05:02" },
@@ -29,6 +29,7 @@ import {
isEvidenceDomain,
isEvidenceKind,
isEvidenceStatus,
datedPrecision,
normalizeQuote,
quoteIsGroundedInMessage,
} from "../src/lib/rectification-agentic/v9/evidence-model.ts";
@@ -130,6 +131,10 @@ test("evidence model exposes the full kind/domain/precision/status sets", () =>
assert.equal(isDatePrecision(precision), true);
}
assert.equal(isDatePrecision("exact_minute"), false);
assert.equal(datedPrecision("quarter"), "year");
assert.equal(datedPrecision("range"), "year");
assert.equal(datedPrecision("day"), "day");
assert.equal(datedPrecision("unknown"), "unknown");
for (const status of ["draft", "pending_confirmation", "confirmed", "superseded", "rejected"]) {
assert.equal(isEvidenceStatus(status), true);
}