7baf230066
Accepted profiles were selecting a revoked rectification table and failing the report before the engine ran. Degrade to a null window when that optional read fails. Co-authored-by: Cursor <cursoragent@cursor.com>
149 lines
4.4 KiB
TypeScript
149 lines
4.4 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
import {
|
|
READ_REPORT_CANDIDATE_RANGE_RPC,
|
|
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("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/,
|
|
);
|
|
});
|