import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import test from "node:test"; const migration = readFileSync( new URL("../supabase/migrations/20260804010000_agentic_rectification_candidate_acceptance.sql", import.meta.url), "utf8", ); const preservationMigration = readFileSync( new URL("../supabase/migrations/20260804020000_preserve_reported_birth_time_on_candidate_acceptance.sql", import.meta.url), "utf8", ); const decisionContractV2Migration = readFileSync( new URL( "../supabase/migrations/20260814030000_rectification_event_decision_contract_v2.sql", import.meta.url, ), "utf8", ); const profileFreshnessMigration = readFileSync( new URL( "../supabase/migrations/20260827010000_rectification_candidate_profile_freshness.sql", import.meta.url, ), "utf8", ); test("candidate acceptance migration adds accepted status and durable result ownership", () => { assert.match(migration, /birth_time_status in \([\s\S]*'reported'[\s\S]*'assessing'[\s\S]*'rectifying'[\s\S]*'candidate'[\s\S]*'accepted'[\s\S]*'confirmed'[\s\S]*\)/); assert.match(migration, /create table public\.agentic_rectification_results/); assert.match(migration, /user_id uuid not null references auth\.users\(id\)/); assert.match(migration, /session_id uuid not null references public\.chat_sessions\(id\)/); assert.match(migration, /expires_at timestamptz not null/); assert.match(migration, /invalidated_at timestamptz/); }); test("candidate acceptance RPC validates ownership, freshness, gate, membership, and profile baseline", () => { assert.match(migration, /where id = p_result_id[\s\S]*user_id = p_user_id[\s\S]*session_id = p_session_id/); assert.match(migration, /invalidated_at is not null or v_result\.expires_at <= pg_catalog\.now\(\)/); assert.match(migration, /if not v_result\.selection_allowed/); assert.match(migration, /jsonb_array_elements\(v_result\.candidates\)[\s\S]*candidate ->> 'time'/); assert.match(migration, /v_profile\.birth_date is distinct from v_result\.baseline_birth_date/); assert.match(migration, /v_profile\.reported_birth_time is distinct from v_result\.baseline_reported_birth_time/); assert.match(migration, /v_profile\.active_birth_time is distinct from v_result\.baseline_active_birth_time/); assert.match(migration, /v_profile\.birth_time_period is distinct from v_result\.baseline_birth_time_period/); assert.match(migration, /v_profile\.latitude is distinct from v_result\.baseline_latitude/); assert.match(migration, /v_profile\.longitude is distinct from v_result\.baseline_longitude/); assert.match(migration, /v_profile\.timezone_offset is distinct from v_result\.baseline_timezone_offset/); }); test("candidate acceptance is idempotent before baseline checks and separates accepted from confirmed", () => { const idempotent = migration.indexOf("if v_result.selected_time is not null"); const baseline = migration.indexOf("select * into v_profile"); assert.ok(idempotent >= 0 && baseline > idempotent); assert.match(migration, /v_result\.confirmation_allowed[\s\S]*v_result\.representative_time is not distinct from p_time[\s\S]*then 'engine_confirmed'[\s\S]*else 'user_accepted'/); assert.match(migration, /v_status := case when v_selection_kind = 'engine_confirmed' then 'confirmed' else 'accepted' end/); assert.match(migration, /agentic_rectification_candidate_superseded/); assert.match(migration, /v_profile\.active_birth_time is distinct from v_result\.selected_time/); }); test("candidate acceptance writes the active chart time without replacing reported time", () => { const profileUpdate = migration.slice( migration.indexOf("update public.profiles"), migration.indexOf("update public.agentic_rectification_results", migration.indexOf("update public.profiles")), ); assert.match(profileUpdate, /active_birth_time = p_time/); assert.match(profileUpdate, /birth_time = p_time/); assert.match(profileUpdate, /birth_time_status = v_status/); assert.doesNotMatch(profileUpdate, /reported_birth_time\s*=/); }); test("candidate acceptance RPC is service-role only", () => { assert.match(migration, /revoke all on function public\.accept_agentic_rectification_candidate[\s\S]*from public, anon, authenticated/); assert.match(migration, /grant execute on function public\.accept_agentic_rectification_candidate[\s\S]*to service_role/); assert.doesNotMatch(migration, /grant execute on function public\.accept_agentic_rectification_candidate[\s\S]*to authenticated/); }); test("profile declaration changes invalidate restored Agentic candidate results", () => { assert.match(migration, /create trigger profiles_invalidate_agentic_rectification_results/); assert.match(migration, /old\.birth_time_period is distinct from new\.birth_time_period/); assert.match(migration, /old\.latitude is distinct from new\.latitude/); assert.match(migration, /set invalidated_at = pg_catalog\.now\(\)/); assert.match(migration, /coalesce\(new\.birth_time_status, ''\) not in \('accepted', 'confirmed'\)/); }); test("forward repair separates original declaration from the active chart time", () => { const profileUpdate = preservationMigration.slice( preservationMigration.indexOf("update public.profiles\n set active_birth_time"), preservationMigration.indexOf("update public.agentic_rectification_results", preservationMigration.indexOf("update public.profiles\n set active_birth_time")), ); assert.match(profileUpdate, /active_birth_time = p_time/); assert.match(profileUpdate, /birth_time_status = v_status/); assert.doesNotMatch(profileUpdate, /^\s*birth_time = p_time/m); assert.doesNotMatch(profileUpdate, /reported_birth_time\s*=/); assert.doesNotMatch(preservationMigration, /v_profile\.birth_time is distinct from v_result\.selected_time/); }); test("forward repair removes legacy field mirroring and repairs already selected Agentic profiles", () => { const guard = preservationMigration.slice( preservationMigration.indexOf("create or replace function public.guard_birth_time_journey"), preservationMigration.indexOf("update public.profiles", preservationMigration.indexOf("create or replace function public.guard_birth_time_journey")), ); assert.doesNotMatch(guard, /new\.birth_time := new\.active_birth_time/); assert.doesNotMatch(guard, /new\.active_birth_time := new\.birth_time/); assert.match(preservationMigration, /p\.birth_time_status in \('accepted', 'confirmed'\)/); assert.match(preservationMigration, /p\.active_birth_time is not distinct from selected\.selected_time/); }); test("forward repair lets the user change a previously adopted candidate", () => { assert.doesNotMatch(preservationMigration, /agentic_rectification_candidate_already_selected/); assert.match(preservationMigration, /v_profile\.active_birth_time is distinct from v_result\.selected_time/); assert.match(preservationMigration, /update public\.agentic_rectification_results[\s\S]*selected_time = p_time/); }); test("decision contract V2 accepts server candidate UUIDs and never caller-supplied times", () => { const acceptStart = decisionContractV2Migration.indexOf( "create or replace function public.accept_agentic_rectification_candidate_for_case_v2(", ); const confirmStart = decisionContractV2Migration.indexOf( "create or replace function public.confirm_agentic_rectification_candidate_for_case_v2(", ); const acceptFunction = decisionContractV2Migration.slice(acceptStart, confirmStart); const confirmFunction = decisionContractV2Migration.slice(confirmStart); assert.match(acceptFunction, /p_candidate_id uuid/); assert.match(acceptFunction, /p_request_id uuid/); assert.doesNotMatch(acceptFunction, /p_time\s+time/); assert.match(confirmFunction, /p_candidate_id uuid/); assert.match(confirmFunction, /p_request_id uuid/); assert.doesNotMatch(confirmFunction, /p_time\s+time/); for (const functionBody of [acceptFunction, confirmFunction]) { assert.match(functionBody, /where id = p_result_id[\s\S]*user_id = p_user_id[\s\S]*case_id = p_case_id/); assert.match(functionBody, /where id = p_candidate_id[\s\S]*result_id = p_result_id[\s\S]*user_id = p_user_id[\s\S]*case_id = p_case_id/); assert.match(functionBody, /v_candidate\.candidate_time/); } }); test("decision contract V2 acceptance can only write accepted state", () => { const acceptStart = decisionContractV2Migration.indexOf( "create or replace function public.accept_agentic_rectification_candidate_for_case_v2(", ); const confirmStart = decisionContractV2Migration.indexOf( "create or replace function public.confirm_agentic_rectification_candidate_for_case_v2(", ); const acceptFunction = decisionContractV2Migration.slice(acceptStart, confirmStart); assert.match(acceptFunction, /birth_time_status = 'accepted'/); assert.match(acceptFunction, /selection_kind = 'user_accepted'/); assert.match(acceptFunction, /status = 'candidate_accepted'/); assert.doesNotMatch(acceptFunction, /engine_confirmed/); assert.doesNotMatch(acceptFunction, /birth_time_status = 'confirmed'/); }); test("decision contract V2 confirmation remains a separate exact and consent-grounded gate", () => { const confirmStart = decisionContractV2Migration.indexOf( "create or replace function public.confirm_agentic_rectification_candidate_for_case_v2(", ); const confirmFunction = decisionContractV2Migration.slice(confirmStart); assert.match(confirmFunction, /if not v_result\.confirmation_allowed/); assert.match(confirmFunction, /if not v_candidate\.is_representative/); assert.match(confirmFunction, /agentic_rectification_confirmation_exact_gate_blocked/); assert.match(confirmFunction, /public\.agentic_rectification_normalize_quote\(p_consent_quote\)/); assert.match(confirmFunction, /public\.agentic_rectification_normalize_quote\(v_turn\.user_message\)/); assert.match(confirmFunction, /agentic_rectification_consent_not_grounded/); assert.match(confirmFunction, /birth_time_status = 'confirmed'/); assert.match(confirmFunction, /selection_kind = 'engine_confirmed'/); }); test("candidate acceptance shares one calculation-input freshness guard across first accept and reselection", () => { const acceptFunction = profileFreshnessMigration.slice( profileFreshnessMigration.indexOf( "create or replace function public.accept_agentic_rectification_candidate_for_case_v2(", ), profileFreshnessMigration.indexOf("commit;"), ); const requestReplay = acceptFunction.indexOf("if found then"); const freshnessGuard = acceptFunction.indexOf("v_snapshot := v_case.baseline_birth_snapshot;"); const selectionBranch = acceptFunction.indexOf("if v_result.selected_candidate_id is not null then"); const freshnessChecks = acceptFunction.slice(freshnessGuard, selectionBranch); assert.ok(requestReplay >= 0 && requestReplay < freshnessGuard, "exact request replay must remain idempotent"); assert.ok(freshnessGuard >= 0 && freshnessGuard < selectionBranch, "freshness must guard first accept and reselection"); assert.doesNotMatch( freshnessChecks, /v_profile\.active_birth_time is distinct from \(v_snapshot ->> 'active_birth_time'\)/, ); assert.doesNotMatch( freshnessChecks, /v_profile\.birth_place_label is distinct from v_snapshot ->> 'birth_place_label'/, ); for (const requiredFreshnessCheck of [ /v_profile\.birth_date is distinct from \(v_snapshot ->> 'birth_date'\)::date/, /v_profile\.reported_birth_time is distinct from \(v_snapshot ->> 'reported_birth_time'\)::time without time zone/, /v_profile\.birth_time_source is distinct from v_snapshot ->> 'birth_time_source'/, /v_profile\.birth_time_period is distinct from v_snapshot ->> 'birth_time_period'/, /v_profile\.declared_window_start is distinct from v_snapshot ->> 'declared_window_start'/, /v_profile\.declared_window_end is distinct from v_snapshot ->> 'declared_window_end'/, /v_profile\.uncertainty_before_minutes is distinct from \(v_snapshot ->> 'uncertainty_before_minutes'\)::integer/, /v_profile\.uncertainty_after_minutes is distinct from \(v_snapshot ->> 'uncertainty_after_minutes'\)::integer/, /v_profile\.latitude is distinct from \(v_snapshot ->> 'latitude'\)::double precision/, /v_profile\.longitude is distinct from \(v_snapshot ->> 'longitude'\)::double precision/, /v_profile\.timezone_id is distinct from v_snapshot ->> 'timezone_id'/, /v_profile\.timezone_offset is distinct from \(v_snapshot ->> 'timezone_offset'\)::double precision/, ]) { assert.match(freshnessChecks, requiredFreshnessCheck); } }); test("candidate replay and reselection still require the selected accepted state", () => { const acceptFunction = profileFreshnessMigration.slice( profileFreshnessMigration.indexOf( "create or replace function public.accept_agentic_rectification_candidate_for_case_v2(", ), profileFreshnessMigration.indexOf("commit;"), ); const selectedStateChecks = acceptFunction.slice( acceptFunction.indexOf("if v_result.selected_candidate_id is not null then"), acceptFunction.indexOf("update public.profiles"), ); assert.match(selectedStateChecks, /v_result\.selected_time is not distinct from v_candidate\.candidate_time/); assert.match(selectedStateChecks, /v_case\.accepted_time is not distinct from v_candidate\.candidate_time/); assert.match(selectedStateChecks, /v_result\.selection_kind is not distinct from 'user_accepted'/); assert.match(selectedStateChecks, /v_profile\.active_birth_time is not distinct from v_candidate\.candidate_time/); assert.match(selectedStateChecks, /v_profile\.birth_time_status is not distinct from 'accepted'/); assert.match(selectedStateChecks, /v_case\.status is distinct from 'candidate_accepted'/); assert.match(selectedStateChecks, /v_profile\.active_birth_time is distinct from v_result\.selected_time/); assert.match(selectedStateChecks, /v_profile\.birth_time_status is distinct from 'accepted'/); }); test("decision receipt projection rejects contradictory latest transitions", () => { const composeFunction = profileFreshnessMigration.slice( profileFreshnessMigration.indexOf( "create or replace function public.compose_agentic_rectification_decision_receipt(", ), profileFreshnessMigration.indexOf( "create or replace function public.accept_agentic_rectification_candidate_for_case_v2(", ), ); assert.match(composeFunction, /jsonb_typeof\(v_transition\.inference_state -> 'revision'\) is distinct from 'number'/); assert.match(composeFunction, /\(v_transition\.inference_state ->> 'revision'\)::integer is distinct from v_transition\.revision/); assert.match(composeFunction, /jsonb_typeof\(v_transition\.inference_state -> 'candidate_set_id'\) is distinct from 'string'/); assert.match(composeFunction, /v_transition\.inference_state ->> 'candidate_set_id' is distinct from v_transition\.candidate_set_id/); assert.match(composeFunction, /return v_receipt - 'inference_state' - 'decision_state_fingerprint';/); }); test("candidate acceptance treats the latest inference transition as authoritative", () => { const acceptFunction = profileFreshnessMigration.slice( profileFreshnessMigration.indexOf( "create or replace function public.accept_agentic_rectification_candidate_for_case_v2(", ), profileFreshnessMigration.indexOf("commit;"), ); const transitionRead = acceptFunction.indexOf("select * into v_latest_transition"); const inferenceChoice = acceptFunction.indexOf("when v_latest_transition.id is not null then v_latest_transition.inference_state"); const receiptFallback = acceptFunction.indexOf("else v_result.decision_receipt -> 'inference_state'"); assert.ok(transitionRead >= 0 && transitionRead < inferenceChoice); assert.ok(inferenceChoice >= 0 && inferenceChoice < receiptFallback); assert.match(acceptFunction, /v_latest_transition\.revision is distinct from \(v_inference ->> 'revision'\)::integer/); assert.match(acceptFunction, /v_latest_transition\.candidate_set_id is distinct from v_inference ->> 'candidate_set_id'/); assert.doesNotMatch( acceptFunction, /v_result\.decision_receipt\s*->\s*'inference_state'[\s\S]*is distinct from v_latest_transition\.inference_state/, ); }); test("candidate acceptance validates load-bearing inference fields fail-closed", () => { const acceptFunction = profileFreshnessMigration.slice( profileFreshnessMigration.indexOf( "create or replace function public.accept_agentic_rectification_candidate_for_case_v2(", ), profileFreshnessMigration.indexOf("commit;"), ); assert.match(acceptFunction, /coalesce\(\(item\.value ->> 'time'\) !~ [^\n]+, true\)/); assert.match(acceptFunction, /coalesce\(item\.value ->> 'status', ''\) not in \('active', 'equivalent', 'winner', 'eliminated'\)/); assert.match(acceptFunction, /jsonb_typeof\(item\.value -> 'probability'\) is distinct from 'number'/); assert.match(acceptFunction, /jsonb_typeof\(item\.value -> 'posterior_score'\) is distinct from 'number'/); assert.match(acceptFunction, /jsonb_typeof\(item\.value -> 'cluster_range'\) is distinct from 'array'/); assert.match(acceptFunction, /jsonb_array_length\(item\.value -> 'cluster_range'\) is distinct from 2/); });