import assert from "node:assert/strict"; import { spawnSync } from "node:child_process"; import { fileURLToPath } from "node:url"; import { readFileSync } from "node:fs"; import test from "node:test"; import { startPostgresFixture } from "./helpers/postgres-fixture.ts"; const runnerPath = fileURLToPath( new URL("../scripts/db-migrate.mjs", import.meta.url), ); const migrationSql = readFileSync( new URL("../supabase/migrations/20260814010000_immutable_skill_registry.sql", import.meta.url), "utf8", ); 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: "66666666-6666-4666-8666-666666666666", otherUser: "77777777-7777-4777-8777-777777777777", cascadeUser: "88888888-8888-4888-8888-888888888888", legacySession: "22222222-2222-4222-8222-222222222222", legacyCase: "11111111-1111-4111-8111-111111111111", legacyTurn: "33333333-3333-4333-8333-333333333333", legacyEvidence: "55555555-5555-4555-8555-555555555555", legacyResult: "99999999-9999-4999-8999-999999999999", terminalSession: "22222222-2222-4222-8222-222222222223", terminalCase: "11111111-1111-4111-8111-111111111112", verifiedTurn: "33333333-3333-4333-8333-333333333334", verifiedRequest: "44444444-4444-4444-8444-444444444444", cascadeSession: "22222222-2222-4222-8222-222222222224", cascadeCase: "11111111-1111-4111-8111-111111111113", cascadeTurn: "33333333-3333-4333-8333-333333333335", cascadeRequest: "44444444-4444-4444-8444-444444444445", caseDeleteSession: "22222222-2222-4222-8222-222222222225", caseDeleteCase: "11111111-1111-4111-8111-111111111114", caseDeleteTurn: "33333333-3333-4333-8333-333333333336", caseDeleteRequest: "44444444-4444-4444-8444-444444444446", }; const oldHash = "a".repeat(64); const newHash = "b".repeat(64); const adoptionHash = "c".repeat(64); const sourceCommit = "0fd111d16b45796086a6c1d0945dbd3de6755d8a"; function sqlLiteral(value: string): string { return `'${value.replaceAll("'", "''")}'`; } test("immutable Skill migration enforces RPC-only identity, legacy adoption, and cascade-safe receipts", { 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/, ""); const expectServiceError = (statement: string, pattern: RegExp) => { assert.throws(() => serviceSql(statement), pattern); }; const expectOwnerError = (statement: string, pattern: RegExp) => { assert.throws( () => fixture.psqlAs( "schema_owner", "schema-owner-test-password", statement, ), pattern, ); }; const insertUser = (id: string, email: string) => fixture.psqlAs( "identity_runtime", "identity-runtime-test-password", `insert into identity.users (id, name, email, email_verified, email_verified_at) values (${sqlLiteral(id)}, 'Skill Registry User', ${sqlLiteral(email)}, true, now());`, ); const insertSession = (id: string, userId: string) => fixture.psql(` insert into public.chat_sessions (id, user_id, title, theme, session_type, messages) values (${sqlLiteral(id)}, ${sqlLiteral(userId)}, '生时校正', 'general', 'birth_time_rectification', '[]'::jsonb); `); const insertCase = (input: { id: string; userId: string; sessionId: string; status?: "draft" | "closed"; hash?: string | null; }) => fixture.psql(` 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, completed_at ) values ( ${sqlLiteral(input.id)}, ${sqlLiteral(input.userId)}, ${sqlLiteral(input.sessionId)}, ${sqlLiteral(input.status ?? "draft")}, 'jyotish-birth-time-rectification', '9.0.0', ${input.hash ? sqlLiteral(input.hash) : "null"}, ${input.hash ? sqlLiteral(sourceCommit) : "null"}, ${sqlLiteral(oldHash)}, '{"birth_date":"1997-08-08"}'::jsonb, '{"start_time":"04:50","end_time":"05:10"}'::jsonb, ${input.status === "closed" ? "now()" : "null"} ); `); try { fixture.psql(`create role historical_runtime_probe noinherit;`); fixture.psqlAs( "schema_owner", "schema-owner-test-password", `create or replace function public.open_agentic_rectification_case_v2( uuid, uuid, text, uuid, text, text, text, text, text, jsonb, jsonb ) returns jsonb language sql as $$ select '{}'::jsonb $$; grant execute on function public.open_agentic_rectification_case_v2( uuid, uuid, text, uuid, text, text, text, text, text, jsonb, jsonb ) to historical_runtime_probe, service_runtime;`, ); const first = migrate(); assert.equal(first.status, 0, `${first.stdout}${first.stderr}`); assert.match(first.stdout, /applied 20260814010000_immutable_skill_registry\.sql/); const aclCatalog = fixture.psql(` select string_agg( case when has_function_privilege('historical_runtime_probe', p.oid, 'EXECUTE') then 't' else 'f' end || ':' || case when has_function_privilege('service_role', p.oid, 'EXECUTE') then 't' else 'f' end || ':' || case when has_function_privilege('anon', p.oid, 'EXECUTE') then 't' else 'f' end || ':' || case when has_function_privilege('authenticated', p.oid, 'EXECUTE') then 't' else 'f' end || ':' || case when exists ( select 1 from pg_catalog.aclexplode(p.proacl) a join pg_catalog.pg_roles r on r.oid = a.grantee where r.rolname = 'service_runtime' and a.privilege_type = 'EXECUTE' ) then 't' else 'f' end, ',' order by p.proname ) from pg_catalog.pg_proc p join pg_catalog.pg_namespace n on n.oid = p.pronamespace where n.nspname = 'public' and p.proname in ( 'open_agentic_rectification_case_v2', 'get_agentic_rectification_skill_identity', 'get_agentic_rectification_skill_identity_status', 'upgrade_agentic_rectification_skill_v2', 'adopt_agentic_rectification_skill_v1', 'insert_agentic_rectification_skill_run_receipt' ); `); assert.equal(aclCatalog, "f:t:f:f:f,f:t:f:f:f,f:t:f:f:f,f:t:f:f:f,f:t:f:f:f,f:t:f:f:f"); fixture.psql(` grant execute on function public.open_agentic_rectification_case_v2( uuid, uuid, text, uuid, text, text, text, text, text, jsonb, jsonb ) to historical_runtime_probe, service_runtime; grant execute on function public.get_agentic_rectification_skill_identity(uuid, uuid) to historical_runtime_probe, service_runtime; grant execute on function public.get_agentic_rectification_skill_identity_status(uuid, uuid) to historical_runtime_probe, service_runtime; grant execute on function public.upgrade_agentic_rectification_skill_v2( uuid, uuid, text, text, text, text ) to historical_runtime_probe, service_runtime; grant execute on function public.adopt_agentic_rectification_skill_v1( uuid, uuid, text, text, text, text ) to historical_runtime_probe, service_runtime; grant execute on function public.insert_agentic_rectification_skill_run_receipt( uuid, uuid, uuid, uuid, text, text, text, text, text ) to historical_runtime_probe, service_runtime; `); fixture.psqlAs( "schema_owner", "schema-owner-test-password", migrationSql, ); assert.equal( fixture.psql(` select string_agg( case when has_function_privilege('historical_runtime_probe', p.oid, 'EXECUTE') then 't' else 'f' end || ':' || case when has_function_privilege('service_role', p.oid, 'EXECUTE') then 't' else 'f' end || ':' || case when exists ( select 1 from pg_catalog.aclexplode(p.proacl) a join pg_catalog.pg_roles r on r.oid = a.grantee where r.rolname = 'service_runtime' and a.privilege_type = 'EXECUTE' ) then 't' else 'f' end || ':' || case when has_function_privilege('anon', p.oid, 'EXECUTE') then 't' else 'f' end || ':' || case when has_function_privilege('authenticated', p.oid, 'EXECUTE') then 't' else 'f' end, ',' order by p.proname ) from pg_catalog.pg_proc p join pg_catalog.pg_namespace n on n.oid = p.pronamespace where n.nspname = 'public' and p.proname in ( 'open_agentic_rectification_case_v2', 'get_agentic_rectification_skill_identity', 'get_agentic_rectification_skill_identity_status', 'upgrade_agentic_rectification_skill_v2', 'adopt_agentic_rectification_skill_v1', 'insert_agentic_rectification_skill_run_receipt' ); `), "f:t:f:f:f,f:t:f:f:f,f:t:f:f:f,f:t:f:f:f,f:t:f:f:f,f:t:f:f:f", ); assert.equal( fixture.psql("select pg_has_role('service_runtime', 'service_role', 'MEMBER');"), "t", ); assert.equal( serviceSql(` select string_agg( case when has_function_privilege(current_user, p.oid, 'EXECUTE') then 't' else 'f' end, ',' order by p.proname ) from pg_catalog.pg_proc p join pg_catalog.pg_namespace n on n.oid = p.pronamespace where n.nspname = 'public' and p.proname in ( 'open_agentic_rectification_case_v2', 'get_agentic_rectification_skill_identity', 'get_agentic_rectification_skill_identity_status', 'upgrade_agentic_rectification_skill_v2', 'adopt_agentic_rectification_skill_v1', 'insert_agentic_rectification_skill_run_receipt' ); `), "t,t,t,t,t,t", ); const second = migrate(); assert.equal(second.status, 0, `${second.stdout}${second.stderr}`); assert.match(second.stdout, /already applied 20260814010000_immutable_skill_registry\.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_table_privilege('service_role', 'public.agentic_rectification_cases', 'TRUNCATE'), has_table_privilege('service_role', 'public.agentic_rectification_skill_upgrade_receipts', 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE'), has_table_privilege('service_role', 'public.agentic_rectification_skill_run_receipts', 'SELECT,INSERT,UPDATE,DELETE,TRUNCATE') ) `), "f:f:f:f:f:f:f", ); const catalog = fixture.psql(` select p.proname || ':' || pg_catalog.pg_get_userbyid(p.proowner) || ':' || p.prosecdef || ':' || coalesce(array_to_string(p.proconfig, ','), '') || ':' || has_function_privilege('service_role', p.oid, 'EXECUTE') || ':' || has_function_privilege('anon', p.oid, 'EXECUTE') || ':' || has_function_privilege('authenticated', p.oid, 'EXECUTE') from pg_catalog.pg_proc p join pg_catalog.pg_namespace n on n.oid = p.pronamespace where n.nspname = 'public' and p.proname in ( 'open_agentic_rectification_case_v2', 'get_agentic_rectification_skill_identity', 'get_agentic_rectification_skill_identity_status', 'upgrade_agentic_rectification_skill_v2', 'adopt_agentic_rectification_skill_v1', 'insert_agentic_rectification_skill_run_receipt' ) order by p.proname; `); for (const line of catalog.split("\n")) { assert.match(line, /^[^:]+:schema_owner:true:search_path="":true:f:f$/); } assert.equal(catalog.split("\n").length, 6); assert.equal( fixture.psql(` select string_agg(c.relname || ':' || pg_catalog.pg_get_userbyid(c.relowner), ',' order by c.relname) from pg_catalog.pg_class c join pg_catalog.pg_namespace n on n.oid = c.relnamespace where n.nspname = 'public' and c.relname in ( 'agentic_rectification_cases', 'agentic_rectification_skill_upgrade_receipts', 'agentic_rectification_skill_run_receipts' ); `), "agentic_rectification_cases:schema_owner,agentic_rectification_skill_run_receipts:schema_owner,agentic_rectification_skill_upgrade_receipts:schema_owner", ); insertUser(ids.user, "skill-registry@example.com"); insertUser(ids.otherUser, "skill-registry-other@example.com"); insertUser(ids.cascadeUser, "skill-registry-cascade@example.com"); const openedCaseId = serviceSql(` select public.open_agentic_rectification_case_v2( ${sqlLiteral(ids.user)}::uuid, gen_random_uuid(), 'homepage', null, 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(oldHash)}, ${sqlLiteral(sourceCommit)}, ${sqlLiteral(oldHash)}, '{"birth_date":"1997-08-08","latitude":25.04,"longitude":121.56,"timezone_offset":8,"birth_time_source":"family_exact"}'::jsonb, '{"start_time":"04:50","end_time":"05:10"}'::jsonb )->>'case_id'; `); assert.match(openedCaseId, /^[0-9a-f-]{36}$/); assert.equal( fixture.psql(`select skill_version || ':' || skill_sha256 from public.agentic_rectification_cases where id = ${sqlLiteral(openedCaseId)}`), `9.0.0:${oldHash}`, ); expectServiceError( `insert into public.agentic_rectification_cases ( user_id, session_id, status, skill_name, skill_version, baseline_profile_fingerprint, baseline_birth_snapshot, candidate_range ) values (${sqlLiteral(ids.user)}, gen_random_uuid(), 'draft', 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(oldHash)}, '{}'::jsonb, '{}'::jsonb);`, /permission denied for table agentic_rectification_cases/, ); expectServiceError( `update public.agentic_rectification_cases set skill_sha256 = ${sqlLiteral(newHash)} where id = ${sqlLiteral(openedCaseId)};`, /permission denied for table agentic_rectification_cases/, ); fixture.psql(` insert into public.agentic_rectification_turns (id, case_id, user_message, status, model_name) values (${sqlLiteral(ids.verifiedTurn)}, ${sqlLiteral(openedCaseId)}, 'verified run', 'pending', 'fixture-model'); `); assert.equal( serviceSql(`select public.insert_agentic_rectification_skill_run_receipt( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(openedCaseId)}::uuid, ${sqlLiteral(ids.verifiedTurn)}::uuid, ${sqlLiteral(ids.verifiedRequest)}::uuid, 'turn', 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(oldHash)}, ${sqlLiteral(sourceCommit)} )->>'skill_sha256';`), oldHash, ); assert.equal( serviceSql(`select public.upgrade_agentic_rectification_skill_v2( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(openedCaseId)}::uuid, 'jyotish-birth-time-rectification', '9.1.0', ${sqlLiteral(newHash)}, null )->>'skill_sha256';`), newHash, ); assert.equal( fixture.psql(`select previous_identity_status || ':' || upgrade_kind || ':' || previous_skill_sha256 || ':' || skill_sha256 from public.agentic_rectification_skill_upgrade_receipts where case_id = ${sqlLiteral(openedCaseId)}`), `verified:version_upgrade:${oldHash}:${newHash}`, ); assert.equal( serviceSql(`select public.insert_agentic_rectification_skill_run_receipt( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(openedCaseId)}::uuid, ${sqlLiteral(ids.verifiedTurn)}::uuid, gen_random_uuid()::uuid, 'regeneration', 'jyotish-birth-time-rectification', '9.1.0', ${sqlLiteral(newHash)}, null )->>'run_kind';`), 'regeneration', ); assert.equal( fixture.psql(`select count(*) from public.agentic_rectification_skill_run_receipts where turn_id = ${sqlLiteral(ids.verifiedTurn)}`), '2', ); expectServiceError( `select public.adopt_agentic_rectification_skill_v1( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(openedCaseId)}::uuid, 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(adoptionHash)}, ${sqlLiteral(sourceCommit)} );`, /agentic_rectification_skill_identity_already_verified/, ); insertSession(ids.legacySession, ids.user); insertCase({ id: ids.legacyCase, userId: ids.user, sessionId: ids.legacySession, hash: null }); fixture.psql(` insert into public.agentic_rectification_turns (id, case_id, user_message, status, model_name) values (${sqlLiteral(ids.legacyTurn)}, ${sqlLiteral(ids.legacyCase)}, 'legacy evidence', 'pending', 'fixture-model'); insert into public.agentic_rectification_evidence ( id, case_id, source_turn_id, user_quote, subject, event_kind, domain, date_precision, summary ) values ( ${sqlLiteral(ids.legacyEvidence)}, ${sqlLiteral(ids.legacyCase)}, ${sqlLiteral(ids.legacyTurn)}, 'legacy evidence', 'self', 'career_entry', 'career', 'year', 'legacy evidence summary' ); insert into public.agentic_rectification_results ( id, user_id, session_id, engine_result_id, canonical_input_hash, algorithm_version, candidate_range, candidates, overall_confidence, selection_allowed, confirmation_allowed, baseline_birth_date, baseline_latitude, baseline_longitude, baseline_timezone_offset, case_id, skill_version ) values ( ${sqlLiteral(ids.legacyResult)}, ${sqlLiteral(ids.user)}, ${sqlLiteral(ids.legacySession)}, 'legacy-engine-result', ${sqlLiteral(oldHash)}, 'legacy-algorithm', '{"start_time":"04:50","end_time":"05:10"}'::jsonb, '[]'::jsonb, 'low', false, false, '1997-08-08', 25.04, 121.56, 8, ${sqlLiteral(ids.legacyCase)}, '9.0.0' ); `); assert.equal( serviceSql(`select (public.get_agentic_rectification_skill_identity_status( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.legacyCase)}::uuid )->>'skill_identity_status') || ':' || (public.get_agentic_rectification_skill_identity_status( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.legacyCase)}::uuid )->>'requires_skill_adoption');`), "legacy_unverifiable:true", ); expectServiceError( `select public.get_agentic_rectification_skill_identity(${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.legacyCase)}::uuid);`, /agentic_rectification_legacy_skill_identity_unverifiable/, ); expectServiceError( `select public.insert_agentic_rectification_skill_run_receipt( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.legacyCase)}::uuid, ${sqlLiteral(ids.legacyTurn)}::uuid, gen_random_uuid(), 'turn', 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(adoptionHash)}, ${sqlLiteral(sourceCommit)} );`, /agentic_rectification_skill_identity_mismatch/, ); expectServiceError( `select public.adopt_agentic_rectification_skill_v1( ${sqlLiteral(ids.otherUser)}::uuid, ${sqlLiteral(ids.legacyCase)}::uuid, 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(adoptionHash)}, ${sqlLiteral(sourceCommit)} );`, /agentic_rectification_case_not_found/, ); insertSession(ids.terminalSession, ids.user); insertCase({ id: ids.terminalCase, userId: ids.user, sessionId: ids.terminalSession, status: "closed", hash: null }); assert.equal( serviceSql(`select (public.get_agentic_rectification_skill_identity_status( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.terminalCase)}::uuid )->>'skill_identity_status') || ':' || (public.get_agentic_rectification_skill_identity_status( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.terminalCase)}::uuid )->>'requires_skill_adoption');`), "legacy_unverifiable:false", ); expectServiceError( `select public.adopt_agentic_rectification_skill_v1( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.terminalCase)}::uuid, 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(adoptionHash)}, ${sqlLiteral(sourceCommit)} );`, /agentic_rectification_case_terminal/, ); const adopted = serviceSql(`select public.adopt_agentic_rectification_skill_v1( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.legacyCase)}::uuid, 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(adoptionHash)}, ${sqlLiteral(sourceCommit)} );`); assert.equal(JSON.parse(adopted).idempotent, false); const replayed = serviceSql(`select public.adopt_agentic_rectification_skill_v1( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.legacyCase)}::uuid, 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(adoptionHash)}, ${sqlLiteral(sourceCommit)} );`); assert.equal(JSON.parse(replayed).idempotent, true); assert.equal( fixture.psql(`select coalesce(previous_skill_sha256, 'NULL') || ':' || previous_identity_status || ':' || upgrade_kind || ':' || skill_sha256 from public.agentic_rectification_skill_upgrade_receipts where case_id = ${sqlLiteral(ids.legacyCase)}`), `NULL:legacy_unverifiable:legacy_adoption:${adoptionHash}`, ); assert.equal( fixture.psql(`select count(*) from public.agentic_rectification_skill_upgrade_receipts where case_id = ${sqlLiteral(ids.legacyCase)}`), "1", ); assert.equal( fixture.psql(`select concat_ws(':', (select count(*) from public.agentic_rectification_turns where case_id = ${sqlLiteral(ids.legacyCase)}), (select count(*) from public.agentic_rectification_evidence where case_id = ${sqlLiteral(ids.legacyCase)}), (select count(*) from public.agentic_rectification_results where case_id = ${sqlLiteral(ids.legacyCase)}) )`), "1:1:1", ); expectServiceError( `insert into public.agentic_rectification_skill_upgrade_receipts ( case_id, user_id, previous_skill_name, previous_skill_version, previous_identity_status, upgrade_kind, skill_name, skill_version, skill_sha256 ) values (${sqlLiteral(ids.legacyCase)}, ${sqlLiteral(ids.user)}, 'jyotish-birth-time-rectification', '9.0.0', 'legacy_unverifiable', 'legacy_adoption', 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(adoptionHash)});`, /permission denied for table agentic_rectification_skill_upgrade_receipts/, ); expectOwnerError( `update public.agentic_rectification_skill_upgrade_receipts set skill_sha256 = ${sqlLiteral(oldHash)} where case_id = ${sqlLiteral(ids.legacyCase)};`, /agentic_rectification_skill_receipts_are_append_only/, ); expectOwnerError( `delete from public.agentic_rectification_skill_run_receipts where case_id = ${sqlLiteral(openedCaseId)};`, /agentic_rectification_skill_receipts_are_append_only/, ); expectOwnerError( `delete from public.agentic_rectification_skill_upgrade_receipts where case_id = ${sqlLiteral(openedCaseId)};`, /agentic_rectification_skill_receipts_are_append_only/, ); expectOwnerError( `truncate table public.agentic_rectification_skill_upgrade_receipts;`, /agentic_rectification_skill_receipts_are_append_only/, ); expectOwnerError( `truncate table public.agentic_rectification_skill_run_receipts;`, /agentic_rectification_skill_receipts_are_append_only/, ); expectOwnerError( `truncate table public.agentic_rectification_cases cascade;`, /agentic_rectification_skill_receipts_are_append_only/, ); assert.equal( fixture.psql(`select concat_ws(':', (select count(*) from public.agentic_rectification_cases where id = ${sqlLiteral(ids.legacyCase)}), (select count(*) from public.agentic_rectification_skill_upgrade_receipts where case_id = ${sqlLiteral(ids.legacyCase)}), (select count(*) from public.agentic_rectification_skill_run_receipts where case_id = ${sqlLiteral(openedCaseId)}) )`), '1:1:2', ); insertSession(ids.caseDeleteSession, ids.user); insertCase({ id: ids.caseDeleteCase, userId: ids.user, sessionId: ids.caseDeleteSession, hash: oldHash, }); fixture.psql(`insert into public.agentic_rectification_turns (id, case_id, user_message, status, model_name) values (${sqlLiteral(ids.caseDeleteTurn)}, ${sqlLiteral(ids.caseDeleteCase)}, 'case cascade user', 'pending', 'fixture-model');`); serviceSql(`select public.insert_agentic_rectification_skill_run_receipt( ${sqlLiteral(ids.user)}::uuid, ${sqlLiteral(ids.caseDeleteCase)}::uuid, ${sqlLiteral(ids.caseDeleteTurn)}::uuid, ${sqlLiteral(ids.caseDeleteRequest)}::uuid, 'turn', 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(oldHash)}, ${sqlLiteral(sourceCommit)} );`); fixture.psql(`delete from public.agentic_rectification_cases where id = ${sqlLiteral(ids.caseDeleteCase)};`); assert.equal( fixture.psql(`select concat_ws(':', (select count(*) from public.agentic_rectification_cases where id = ${sqlLiteral(ids.caseDeleteCase)}), (select count(*) from public.agentic_rectification_turns where id = ${sqlLiteral(ids.caseDeleteTurn)}), (select count(*) from public.agentic_rectification_skill_run_receipts where case_id = ${sqlLiteral(ids.caseDeleteCase)}) )`), '0:0:0', ); fixture.psql(`delete from public.agentic_rectification_turns where id = ${sqlLiteral(ids.verifiedTurn)};`); assert.equal( fixture.psql(`select count(*) from public.agentic_rectification_skill_run_receipts where turn_id = ${sqlLiteral(ids.verifiedTurn)}`), "0", ); assert.equal( fixture.psql(`select count(*) from public.agentic_rectification_skill_upgrade_receipts where case_id = ${sqlLiteral(openedCaseId)}`), "1", ); fixture.psql(`delete from public.agentic_rectification_cases where id = ${sqlLiteral(openedCaseId)};`); assert.equal( fixture.psql(`select count(*) from public.agentic_rectification_skill_upgrade_receipts where case_id = ${sqlLiteral(openedCaseId)}`), "0", ); insertSession(ids.cascadeSession, ids.cascadeUser); insertCase({ id: ids.cascadeCase, userId: ids.cascadeUser, sessionId: ids.cascadeSession, hash: oldHash }); fixture.psql(`insert into public.agentic_rectification_turns (id, case_id, user_message, status, model_name) values (${sqlLiteral(ids.cascadeTurn)}, ${sqlLiteral(ids.cascadeCase)}, 'cascade user', 'pending', 'fixture-model');`); serviceSql(`select public.insert_agentic_rectification_skill_run_receipt( ${sqlLiteral(ids.cascadeUser)}::uuid, ${sqlLiteral(ids.cascadeCase)}::uuid, ${sqlLiteral(ids.cascadeTurn)}::uuid, ${sqlLiteral(ids.cascadeRequest)}::uuid, 'turn', 'jyotish-birth-time-rectification', '9.0.0', ${sqlLiteral(oldHash)}, ${sqlLiteral(sourceCommit)} );`); serviceSql(`select public.upgrade_agentic_rectification_skill_v2( ${sqlLiteral(ids.cascadeUser)}::uuid, ${sqlLiteral(ids.cascadeCase)}::uuid, 'jyotish-birth-time-rectification', '9.1.0', ${sqlLiteral(newHash)}, null );`); fixture.psqlAs( "identity_runtime", "identity-runtime-test-password", `delete from identity.users where id = ${sqlLiteral(ids.cascadeUser)};`, ); assert.equal( fixture.psql(`select concat_ws(':', (select count(*) from public.agentic_rectification_cases where id = ${sqlLiteral(ids.cascadeCase)}), (select count(*) from public.agentic_rectification_skill_run_receipts where case_id = ${sqlLiteral(ids.cascadeCase)}), (select count(*) from public.agentic_rectification_skill_upgrade_receipts where case_id = ${sqlLiteral(ids.cascadeCase)}) )`), "0:0:0", ); } finally { fixture.stop(); } });