814c924e4a
Keep askable cards after exhaustion, explain each probe, read the adopted credible range in reports and chat, and compare declared periods before the minute grid when the clock is unknown. Co-authored-by: Cursor <cursoragent@cursor.com>
166 lines
5.0 KiB
TypeScript
166 lines
5.0 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
import {
|
|
READ_REPORT_CANDIDATE_RANGE_RPC,
|
|
adoptedCredibleRangePayload,
|
|
loadReportCandidateRange,
|
|
parseReportCandidateRange,
|
|
reportCandidateRangeErrorCode,
|
|
} from "../src/lib/report-candidate-range.ts";
|
|
import {
|
|
resolveReportBirthTimeSensitivityInput,
|
|
} from "../src/lib/personal-report-route-core.ts";
|
|
import { REPORT_STABLE_CODES } from "../src/lib/personal-report-codes.ts";
|
|
|
|
const workerSource = readFileSync(
|
|
new URL("../src/lib/personal-report-worker.ts", import.meta.url),
|
|
"utf8",
|
|
);
|
|
const createRoute = readFileSync(
|
|
new URL("../src/app/api/reports/route.ts", import.meta.url),
|
|
"utf8",
|
|
);
|
|
const helperSource = readFileSync(
|
|
new URL("../src/lib/report-candidate-range.ts", import.meta.url),
|
|
"utf8",
|
|
);
|
|
|
|
function capturingWarn() {
|
|
const reasons: string[] = [];
|
|
return {
|
|
reasons,
|
|
warn: (payload: { event: "report_candidate_range_unavailable"; reason: string }) => {
|
|
reasons.push(payload.reason);
|
|
},
|
|
};
|
|
}
|
|
|
|
test("permission denied, thrown errors, and empty rows all degrade to a null window", async () => {
|
|
const denied = capturingWarn();
|
|
assert.equal(
|
|
await loadReportCandidateRange(
|
|
{
|
|
rpc: async () => ({
|
|
data: null,
|
|
error: { code: "42501", message: "permission denied for table agentic_rectification_cases" },
|
|
}),
|
|
},
|
|
{ userId: "11111111-1111-4111-8111-111111111111" },
|
|
denied.warn,
|
|
),
|
|
null,
|
|
);
|
|
assert.deepEqual(denied.reasons, ["42501"]);
|
|
|
|
const thrown = capturingWarn();
|
|
assert.equal(
|
|
await loadReportCandidateRange(
|
|
{
|
|
rpc: async () => {
|
|
throw new TypeError("rpc exploded");
|
|
},
|
|
},
|
|
{ userId: "11111111-1111-4111-8111-111111111111" },
|
|
thrown.warn,
|
|
),
|
|
null,
|
|
);
|
|
assert.deepEqual(thrown.reasons, ["TypeError"]);
|
|
|
|
const empty = capturingWarn();
|
|
assert.equal(
|
|
await loadReportCandidateRange(
|
|
{ rpc: async () => ({ data: null, error: null }) },
|
|
{ userId: "11111111-1111-4111-8111-111111111111" },
|
|
empty.warn,
|
|
),
|
|
null,
|
|
);
|
|
assert.deepEqual(empty.reasons, []);
|
|
});
|
|
|
|
test("a valid RPC window is returned and extra columns are ignored", async () => {
|
|
const log = capturingWarn();
|
|
assert.deepEqual(
|
|
await loadReportCandidateRange(
|
|
{
|
|
rpc: async (fn, args) => {
|
|
assert.equal(fn, READ_REPORT_CANDIDATE_RANGE_RPC);
|
|
assert.equal(args.p_user_id, "11111111-1111-4111-8111-111111111111");
|
|
assert.equal(args.p_rectification_case_id, "22222222-2222-4222-8222-222222222222");
|
|
return {
|
|
data: {
|
|
start_time: "10:00:00",
|
|
end_time: "10:04:00",
|
|
user_id: "must-not-leak",
|
|
candidate_range: { secret: true },
|
|
},
|
|
error: null,
|
|
};
|
|
},
|
|
},
|
|
{
|
|
userId: "11111111-1111-4111-8111-111111111111",
|
|
rectificationCaseId: "22222222-2222-4222-8222-222222222222",
|
|
},
|
|
log.warn,
|
|
),
|
|
{ startTime: "10:00", endTime: "10:04" },
|
|
);
|
|
assert.deepEqual(log.reasons, []);
|
|
});
|
|
|
|
test("degraded candidate windows keep report sensitivity input unwindowed", () => {
|
|
const input = resolveReportBirthTimeSensitivityInput(
|
|
{},
|
|
"accepted",
|
|
"10:30",
|
|
null,
|
|
);
|
|
assert.equal(input.birth_time_accuracy, "provisional");
|
|
assert.equal("candidate_range" in input, false);
|
|
assert.equal(REPORT_STABLE_CODES.calculationUnavailable, "calculation_unavailable");
|
|
});
|
|
|
|
test("adopted credible range payload is inclusive and never invents a clock", () => {
|
|
assert.deepEqual(adoptedCredibleRangePayload({
|
|
startTime: "05:00",
|
|
endTime: "05:26",
|
|
representativeTime: "05:12",
|
|
}), {
|
|
start_time: "05:00",
|
|
end_time: "05:26",
|
|
representative_time: "05:12",
|
|
width_minutes: 27,
|
|
source: "inference_credible_range",
|
|
});
|
|
assert.equal(adoptedCredibleRangePayload({ startTime: "25:00", endTime: "05:00" }), null);
|
|
assert.equal(adoptedCredibleRangePayload({ startTime: "05:26", endTime: "05:00" }), null);
|
|
});
|
|
|
|
test("error codes never include messages or birth content", () => {
|
|
assert.equal(
|
|
reportCandidateRangeErrorCode({
|
|
code: "42501",
|
|
message: "permission denied for table agentic_rectification_cases",
|
|
}),
|
|
"42501",
|
|
);
|
|
assert.equal(parseReportCandidateRange({ start_time: "25:00", end_time: "10:00" }), null);
|
|
assert.doesNotMatch(helperSource, /error\.message|details|hint/);
|
|
});
|
|
|
|
test("worker and create route read candidate windows only through the shared RPC helper", () => {
|
|
for (const source of [workerSource, createRoute]) {
|
|
assert.match(source, /loadReportCandidateRange/);
|
|
assert.doesNotMatch(source, /from\("agentic_rectification_cases"\)/);
|
|
assert.doesNotMatch(source, /from\("birth_time_rectification_cases"\)/);
|
|
assert.doesNotMatch(source, /\.in\("status", \["confirmed", "completed"\]\)/);
|
|
}
|
|
assert.doesNotMatch(
|
|
workerSource,
|
|
/loadReportCandidateRange[\s\S]{0,400}calculation_unavailable/,
|
|
);
|
|
});
|