Files
Jyotisha/frontend/tests/agentic-rectification-candidate-acceptance-migration.test.ts
T
Jesse_Chen 5f855c610c
Independent Staging Quality Gate / validate (push) Failing after 15m32s
Independent Staging Quality Gate / publish (push) Has been skipped
fix(rectification): keep candidate state coherent
2026-08-27 13:59:38 +08:00

292 lines
17 KiB
TypeScript

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/);
});