import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { spawnSync } from "node:child_process"; import test from "node:test"; import { startPostgresFixture } from "./helpers/postgres-fixture.ts"; const runnerPath = new URL("../scripts/db-migrate.mjs", import.meta.url).pathname; const jobMigration = readFileSync( new URL("../db/migrations/20260814040000_personal_report_jobs_v2.sql", import.meta.url), "utf8", ); const USER_ID = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"; const REPORT_ID = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"; const REQUEST_ID = "cccccccc-cccc-4ccc-8ccc-cccccccccccc"; const SECOND_REPORT_ID = "dddddddd-dddd-4ddd-8ddd-dddddddddddd"; const SECOND_REQUEST_ID = "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee"; const THIRD_REPORT_ID = "77777777-7777-4777-8777-777777777777"; const THIRD_REQUEST_ID = "88888888-8888-4888-8888-888888888888"; const FOURTH_REPORT_ID = "99999999-9999-4999-8999-999999999999"; const FOURTH_REQUEST_ID = "12121212-1212-4121-8121-121212121212"; const FIFTH_REPORT_ID = "34343434-3434-4343-8343-343434343434"; const FIFTH_REQUEST_ID = "56565656-5656-4565-8565-565656565656"; const WRONG_LEASE = "ffffffff-ffff-4fff-8fff-ffffffffffff"; const FINGERPRINT = "1".repeat(64); const SECOND_FINGERPRINT = "2".repeat(64); const THIRD_FINGERPRINT = "7".repeat(64); const FOURTH_FINGERPRINT = "8".repeat(64); const FIFTH_FINGERPRINT = "9".repeat(64); const CALCULATION_HASH = "3".repeat(64); const EVIDENCE_HASH = "4".repeat(64); const SKILL_NAME = "jyotish-personal-report"; const SKILL_VERSION = "1.0.0"; const SKILL_COMMIT = "5".repeat(40); const SKILL_SNAPSHOT = "6".repeat(64); function sqlLiteral(value: string): string { return `'${value.replaceAll("'", "''")}'`; } function documentFor(reportId: string): string { return JSON.stringify({ schemaVersion: "report_document.v2", reportId, provenance: { calculationHash: CALCULATION_HASH, evidenceHash: EVIDENCE_HASH, skillName: SKILL_NAME, skillVersion: SKILL_VERSION, skillSourceCommit: SKILL_COMMIT, skillSnapshotSha256: SKILL_SNAPSHOT, }, }); } function insertGeneratingReport(reportId: string, requestId: string, fingerprint: string): string { return ` insert into public.personal_reports ( id, user_id, request_id, request_fingerprint, report_type, status, schema_version, presentation_mode, requested_themes, depth, skill_name, skill_version, skill_source_commit, skill_snapshot_sha256 ) values ( '${reportId}', '${USER_ID}', '${requestId}', '${fingerprint}', 'personal_full', 'generating', 'report_document.v2', 'default', array['general']::text[], 'standard', '${SKILL_NAME}', '${SKILL_VERSION}', '${SKILL_COMMIT}', '${SKILL_SNAPSHOT}' ); `; } function completeSql(input: { jobId: string; leaseToken: string; reportId: string; requestId: string; fingerprint: string; }): string { return ` set role service_role; select status from public.complete_personal_report_job( '${input.jobId}', '${input.leaseToken}', '${USER_ID}', '${input.reportId}', '${input.requestId}', '${input.fingerprint}', 'report_document.v2', ${sqlLiteral(documentFor(input.reportId))}::jsonb, '${CALCULATION_HASH}', '${EVIDENCE_HASH}', '${SKILL_NAME}', '${SKILL_VERSION}', '${SKILL_COMMIT}', '${SKILL_SNAPSHOT}' ); `; } function failSql(input: { jobId: string; leaseToken: string; reportId: string; requestId: string; fingerprint: string; }): string { return ` set role service_role; select status from public.fail_personal_report_job( '${input.jobId}', '${input.leaseToken}', '${USER_ID}', '${input.reportId}', '${input.requestId}', '${input.fingerprint}', 'report_schema_invalid', 'report_schema_invalid' ); `; } test("personal report job migration is atomic, lease-bound, recoverable, and owner read-only", () => { const fixture = startPostgresFixture(); const schemaUrl = fixture.connectionUrl("schema_owner", "schema-owner-test-password"); try { const migration = spawnSync(process.execPath, [runnerPath], { encoding: "utf8", env: { ...process.env, SCHEMA_DATABASE_URL: schemaUrl }, }); assert.equal(migration.status, 0, migration.stderr); assert.match(migration.stdout, /applied 20260814025000_personal_report_document_v2\.sql/); assert.match(migration.stdout, /applied 20260814040000_personal_report_jobs_v2\.sql/); fixture.psql(` insert into identity.users (id, name, email, email_verified, email_verified_at) values ('${USER_ID}', 'Report Test User', 'report-job-test@example.com', true, now()); ${insertGeneratingReport(REPORT_ID, REQUEST_ID, FINGERPRINT)} `); const originalJobId = fixture.psql(` select id from public.personal_report_jobs where user_id = '${USER_ID}' and request_id = '${REQUEST_ID}' `); assert.match(originalJobId, /^[0-9a-f-]{36}$/); // Simulate a generating row created before the durable trigger existed, // then re-run the forward migration to verify its historical backfill. fixture.psql(`delete from public.personal_report_jobs where id = '${originalJobId}'`); assert.equal(fixture.psql(`select count(*) from public.personal_report_jobs where id = '${originalJobId}'`), "0"); fixture.psql(jobMigration); const backfilledJobId = fixture.psql(` select id from public.personal_report_jobs where user_id = '${USER_ID}' and request_id = '${REQUEST_ID}' `); assert.match(backfilledJobId, /^[0-9a-f-]{36}$/); assert.throws( () => fixture.psqlAs( "app_runtime", "app-runtime-test-password", `set role authenticated; select set_config('request.jwt.claim.sub', '${USER_ID}', true); delete from public.personal_report_jobs where id = '${backfilledJobId}';`, ), /permission denied for table personal_report_jobs/, ); assert.equal(fixture.psql(`select count(*) from public.personal_report_jobs where id = '${backfilledJobId}'`), "1"); const claim = fixture.psqlAs( "service_runtime", "service-runtime-test-password", `set role service_role; select id::text || ':' || lease_token::text from public.claim_personal_report_job('report-worker', 60, '${backfilledJobId}');`, ); const [jobId, leaseToken] = claim.split("\n").at(-1)!.split(":"); assert.equal(jobId, backfilledJobId); assert.match(leaseToken, /^[0-9a-f-]{36}$/); assert.throws( () => fixture.psqlAs( "service_runtime", "service-runtime-test-password", completeSql({ jobId, leaseToken: WRONG_LEASE, reportId: REPORT_ID, requestId: REQUEST_ID, fingerprint: FINGERPRINT, }), ), /personal_report_job_lease_lost/, ); assert.equal( fixture.psql(` select report.status || ':' || job.status from public.personal_reports report join public.personal_report_jobs job on job.user_id = report.user_id and job.request_id = report.request_id where report.id = '${REPORT_ID}' `), "generating:running", ); assert.equal( fixture.psqlAs( "service_runtime", "service-runtime-test-password", completeSql({ jobId, leaseToken, reportId: REPORT_ID, requestId: REQUEST_ID, fingerprint: FINGERPRINT, }), ), "SET\nready", ); assert.equal( fixture.psql(` select report.status || ':' || job.status || ':' || job.progress_percent from public.personal_reports report join public.personal_report_jobs job on job.user_id = report.user_id and job.request_id = report.request_id where report.id = '${REPORT_ID}' `), "ready:ready:100", ); fixture.psql(insertGeneratingReport(THIRD_REPORT_ID, THIRD_REQUEST_ID, THIRD_FINGERPRINT)); const thirdJobId = fixture.psql(` select id from public.personal_report_jobs where user_id = '${USER_ID}' and request_id = '${THIRD_REQUEST_ID}' `); const thirdClaim = fixture.psqlAs( "service_runtime", "service-runtime-test-password", `set role service_role; select lease_token from public.claim_personal_report_job('failure-worker', 60, '${thirdJobId}');`, ); const thirdLeaseToken = thirdClaim.split("\n").at(-1)!; assert.match(thirdLeaseToken, /^[0-9a-f-]{36}$/); assert.throws( () => fixture.psqlAs( "service_runtime", "service-runtime-test-password", failSql({ jobId: thirdJobId, leaseToken: WRONG_LEASE, reportId: THIRD_REPORT_ID, requestId: THIRD_REQUEST_ID, fingerprint: THIRD_FINGERPRINT, }), ), /personal_report_job_lease_lost/, ); assert.equal( fixture.psql(` select report.status || ':' || job.status from public.personal_reports report join public.personal_report_jobs job on job.user_id = report.user_id and job.request_id = report.request_id where report.id = '${THIRD_REPORT_ID}' `), "generating:running", ); assert.equal( fixture.psqlAs( "service_runtime", "service-runtime-test-password", failSql({ jobId: thirdJobId, leaseToken: thirdLeaseToken, reportId: THIRD_REPORT_ID, requestId: THIRD_REQUEST_ID, fingerprint: THIRD_FINGERPRINT, }), ), "SET\nfailed", ); assert.equal( fixture.psql(` select report.status || ':' || report.failure_code || ':' || job.status || ':' || job.last_error_code from public.personal_reports report join public.personal_report_jobs job on job.user_id = report.user_id and job.request_id = report.request_id where report.id = '${THIRD_REPORT_ID}' `), "failed:report_schema_invalid:failed:report_schema_invalid", ); fixture.psql(insertGeneratingReport(SECOND_REPORT_ID, SECOND_REQUEST_ID, SECOND_FINGERPRINT)); const secondJobId = fixture.psql(` select id from public.personal_report_jobs where user_id = '${USER_ID}' and request_id = '${SECOND_REQUEST_ID}' `); fixture.psql(` delete from public.personal_report_jobs where id = '${secondJobId}'; insert into public.personal_report_jobs ( id, user_id, request_id, request_fingerprint, status, attempt_count, max_attempts, next_attempt_at, progress_phase, last_error_code, last_error_at ) values ( '${secondJobId}', '${USER_ID}', '${SECOND_REQUEST_ID}', '${SECOND_FINGERPRINT}', 'retrying', 2, 3, clock_timestamp() - interval '1 second', 'retry_wait', 'lease_expired', clock_timestamp() ); `); const secondClaim = fixture.psqlAs( "service_runtime", "service-runtime-test-password", `set role service_role; select lease_token from public.claim_personal_report_job('split-worker', 60, '${secondJobId}');`, ); assert.match(secondClaim.split("\n").at(-1)!, /^[0-9a-f-]{36}$/); fixture.psql(` update public.personal_reports set status = 'ready', report_document = ${sqlLiteral(documentFor(SECOND_REPORT_ID))}::jsonb, calculation_hash = '${CALCULATION_HASH}', evidence_hash = '${EVIDENCE_HASH}', completed_at = clock_timestamp() where id = '${SECOND_REPORT_ID}'; update public.personal_report_jobs set lease_acquired_at = clock_timestamp() - interval '3 seconds', heartbeat_at = clock_timestamp() - interval '2 seconds', lease_expires_at = clock_timestamp() - interval '1 second' where id = '${secondJobId}'; `); assert.equal( fixture.psqlAs( "service_runtime", "service-runtime-test-password", "set role service_role; select * from public.recover_expired_personal_report_jobs(10);", ), "SET\n0|0", ); assert.equal( fixture.psql(`select status || ':' || progress_percent from public.personal_report_jobs where id = '${secondJobId}'`), "ready:100", ); fixture.psql(insertGeneratingReport(FOURTH_REPORT_ID, FOURTH_REQUEST_ID, FOURTH_FINGERPRINT)); const fourthJobId = fixture.psql(` select id from public.personal_report_jobs where user_id = '${USER_ID}' and request_id = '${FOURTH_REQUEST_ID}' `); fixture.psql(` delete from public.personal_report_jobs where id = '${fourthJobId}'; insert into public.personal_report_jobs ( id, user_id, request_id, request_fingerprint, status, attempt_count, max_attempts, next_attempt_at, progress_phase, last_error_code, last_error_at ) values ( '${fourthJobId}', '${USER_ID}', '${FOURTH_REQUEST_ID}', '${FOURTH_FINGERPRINT}', 'retrying', 2, 3, clock_timestamp() - interval '1 second', 'retry_wait', 'lease_expired', clock_timestamp() ); `); const fourthClaim = fixture.psqlAs( "service_runtime", "service-runtime-test-password", `set role service_role; select lease_token from public.claim_personal_report_job('exhausted-worker', 60, '${fourthJobId}');`, ); assert.match(fourthClaim.split("\n").at(-1)!, /^[0-9a-f-]{36}$/); fixture.psql(` update public.personal_report_jobs set lease_acquired_at = clock_timestamp() - interval '3 seconds', heartbeat_at = clock_timestamp() - interval '2 seconds', lease_expires_at = clock_timestamp() - interval '1 second' where id = '${fourthJobId}'; `); assert.equal( fixture.psqlAs( "service_runtime", "service-runtime-test-password", "set role service_role; select * from public.recover_expired_personal_report_jobs(10);", ), "SET\n0|1", ); assert.equal( fixture.psql(` select report.status || ':' || report.failure_code || ':' || job.status || ':' || job.last_error_code from public.personal_reports report join public.personal_report_jobs job on job.user_id = report.user_id and job.request_id = report.request_id where report.id = '${FOURTH_REPORT_ID}' `), "failed:calculation_unavailable:failed:lease_expired_attempts_exhausted", ); fixture.psql(insertGeneratingReport(FIFTH_REPORT_ID, FIFTH_REQUEST_ID, FIFTH_FINGERPRINT)); assert.equal( fixture.psql(` select report.status || ':' || job.status from public.personal_reports report join public.personal_report_jobs job on job.user_id = report.user_id and job.request_id = report.request_id where report.id = '${FIFTH_REPORT_ID}' `), "generating:queued", ); } finally { fixture.stop(); } });