Files
Jyotisha/frontend/tests/database-report-candidate-range.test.ts
T
Jesse_Chen 814c924e4a
Independent Staging Quality Gate / validate (push) Successful in 9m20s
Independent Staging Quality Gate / publish (push) Successful in 6m51s
fix(rectification): exhaustion exit, explain layer, range reading, unknown-time scan (BUG-565–568)
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>
2026-09-07 09:10:37 +08:00

205 lines
7.7 KiB
TypeScript

import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";
import test from "node:test";
import { startPostgresFixture } from "./helpers/postgres-fixture.ts";
const runnerPath = fileURLToPath(
new URL("../scripts/db-migrate.mjs", import.meta.url),
);
function dockerAvailable(): boolean {
return spawnSync("docker", ["version", "--format", "{{.Server.Version}}"], {
encoding: "utf8",
stdio: "ignore",
}).status === 0;
}
const skipWithoutDocker = dockerAvailable() ? false : "docker unavailable on this host";
const ids = {
user: "a1111111-1111-4111-8111-111111111111",
otherUser: "a2222222-2222-4222-8222-222222222222",
session: "b1111111-1111-4111-8111-111111111111",
otherSession: "b2222222-2222-4222-8222-222222222222",
caseId: "c1111111-1111-4111-8111-111111111111",
otherCase: "c2222222-2222-4222-8222-222222222222",
legacyCase: "d1111111-1111-4111-8111-111111111111",
};
function sqlLiteral(value: string): string {
return `'${value.replaceAll("'", "''")}'`;
}
test("read_report_candidate_range is service_role-only, returns only the window, and stays empty without rows", { skip: skipWithoutDocker }, () => {
const fixture = startPostgresFixture();
const migrate = () =>
spawnSync(process.execPath, [runnerPath], {
encoding: "utf8",
env: {
...process.env,
SCHEMA_DATABASE_URL: fixture.connectionUrl(
"schema_owner",
"schema-owner-test-password",
),
},
});
const serviceSql = (statement: string) =>
fixture
.psqlAs(
"service_runtime",
"service-runtime-test-password",
`set role service_role; ${statement}`,
)
.replace(/^SET\n/, "");
try {
const first = migrate();
assert.equal(first.status, 0, `${first.stdout}${first.stderr}`);
assert.match(first.stdout, /applied 20260904010000_read_report_candidate_range\.sql/);
const second = migrate();
assert.equal(second.status, 0, `${second.stdout}${second.stderr}`);
assert.match(second.stdout, /already applied 20260904010000_read_report_candidate_range\.sql/);
assert.equal(
fixture.psql(`
select concat_ws(':',
has_table_privilege('service_role', 'public.agentic_rectification_cases', 'SELECT'),
has_table_privilege('service_role', 'public.agentic_rectification_cases', 'INSERT'),
has_table_privilege('service_role', 'public.agentic_rectification_cases', 'UPDATE'),
has_table_privilege('service_role', 'public.agentic_rectification_cases', 'DELETE'),
has_function_privilege('service_role', 'public.read_report_candidate_range(uuid, uuid)', 'EXECUTE'),
has_function_privilege('anon', 'public.read_report_candidate_range(uuid, uuid)', 'EXECUTE'),
has_function_privilege('authenticated', 'public.read_report_candidate_range(uuid, uuid)', 'EXECUTE')
)
`),
"f:f:f:f:t:f:f",
);
const catalog = fixture.psql(`
select concat_ws(':',
pg_catalog.pg_get_userbyid(p.proowner),
p.prosecdef::text,
coalesce(array_to_string(p.proconfig, ','), ''),
p.provolatile::text
)
from pg_catalog.pg_proc p
join pg_catalog.pg_namespace n on n.oid = p.pronamespace
where n.nspname = 'public' and p.proname = 'read_report_candidate_range'
`);
assert.match(catalog, /^schema_owner:true:search_path="":s$/);
fixture.psqlAs(
"identity_runtime",
"identity-runtime-test-password",
`insert into identity.users (id, name, email, email_verified, email_verified_at)
values (${sqlLiteral(ids.user)}, 'Range User', 'range-user@example.com', true, now()),
(${sqlLiteral(ids.otherUser)}, 'Other User', 'range-other@example.com', true, now());`,
);
assert.equal(
serviceSql(`select public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid) is null`),
"t",
);
fixture.psql(`
insert into public.chat_sessions (id, user_id, title, theme, session_type, messages)
values (
${sqlLiteral(ids.session)}, ${sqlLiteral(ids.user)}, '生时校正', 'general',
'birth_time_rectification', '[]'::jsonb
), (
${sqlLiteral(ids.otherSession)}, ${sqlLiteral(ids.otherUser)}, '生时校正', 'general',
'birth_time_rectification', '[]'::jsonb
);
insert into public.agentic_rectification_cases (
id, user_id, session_id, status, skill_name, skill_version,
skill_sha256, skill_source_commit, baseline_profile_fingerprint,
baseline_birth_snapshot, candidate_range
) values (
${sqlLiteral(ids.caseId)}, ${sqlLiteral(ids.user)}, ${sqlLiteral(ids.session)},
'candidate_accepted', 'jyotish-birth-time-rectification', '9.0.0',
${sqlLiteral("a".repeat(64))}, ${sqlLiteral("0".repeat(40))}, ${sqlLiteral("a".repeat(64))},
'{"birth_date":"1997-08-08"}'::jsonb,
'{"start_time":"10:00","end_time":"10:04","secret":"must-not-leak"}'::jsonb
), (
${sqlLiteral(ids.otherCase)}, ${sqlLiteral(ids.otherUser)}, ${sqlLiteral(ids.otherSession)},
'candidate_accepted', 'jyotish-birth-time-rectification', '9.0.0',
${sqlLiteral("b".repeat(64))}, ${sqlLiteral("1".repeat(40))}, ${sqlLiteral("b".repeat(64))},
'{"birth_date":"1997-08-08"}'::jsonb,
'{"start_time":"11:00","end_time":"11:20"}'::jsonb
);
`);
assert.throws(
() => serviceSql(`select candidate_range from public.agentic_rectification_cases limit 1`),
/permission denied for table agentic_rectification_cases/,
);
assert.equal(
serviceSql(
`select public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid) = '{"start_time":"10:00","end_time":"10:04"}'::jsonb`,
),
"t",
);
const keys = serviceSql(`
select array_to_string(array(
select jsonb_object_keys(public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid))
order by 1
), ',')
`);
assert.equal(keys, "end_time,start_time");
assert.equal(
serviceSql(
`select public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid) ? 'secret'`,
),
"f",
);
fixture.psql(`
update public.agentic_rectification_cases
set adopted_credible_range = '{"start_time":"05:00","end_time":"05:26","representative_time":"05:12","width_minutes":27,"source":"inference_credible_range"}'::jsonb
where id = ${sqlLiteral(ids.caseId)};
`);
assert.equal(
serviceSql(
`select public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid) = '{"start_time":"05:00","end_time":"05:26"}'::jsonb`,
),
"t",
);
const opening = fixture.psql(`
select (candidate_range->>'start_time') || '-' || (candidate_range->>'end_time')
from public.agentic_rectification_cases
where id = ${sqlLiteral(ids.caseId)};
`);
assert.match(opening, /10:00-10:04/);
try {
fixture.psql(`
insert into public.birth_time_rectification_cases (
id, user_id, status, reported_date, source, candidate_start, candidate_end
) values (
${sqlLiteral(ids.legacyCase)}, ${sqlLiteral(ids.user)}, 'confirmed',
'1997-08-08', 'family_exact', '08:16', '08:20'
);
`);
assert.equal(
serviceSql(
`select public.read_report_candidate_range(${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.legacyCase)}::uuid) = '{"start_time":"08:16","end_time":"08:20"}'::jsonb`,
),
"t",
);
} catch (error) {
assert.ok(
false,
`legacy birth_time_rectification_cases seed failed: ${error instanceof Error ? error.message : error}`,
);
}
} finally {
fixture.stop();
}
});