-- Persist first-class inference-round audit fields without changing RPC signatures. -- Entropy, eliminated IDs and round_kind are extracted from inference_state. begin; alter table public.agentic_rectification_inference_transitions add column if not exists entropy_before double precision, add column if not exists entropy_after double precision, add column if not exists eliminated_candidate_ids jsonb not null default '[]'::jsonb, add column if not exists round_kind text; alter table public.agentic_rectification_inference_transitions drop constraint if exists agentic_rectification_inference_round_kind_check; alter table public.agentic_rectification_inference_transitions add constraint agentic_rectification_inference_round_kind_check check (round_kind is null or round_kind in ('informative', 'low_information')); alter table public.agentic_rectification_inference_transitions drop constraint if exists agentic_rectification_inference_eliminated_ids_check; alter table public.agentic_rectification_inference_transitions add constraint agentic_rectification_inference_eliminated_ids_check check (jsonb_typeof(eliminated_candidate_ids) = 'array'); create or replace function public.fill_agentic_rectification_inference_round() returns trigger language plpgsql set search_path = '' as $$ declare v_round jsonb; v_len integer; begin v_round := case when jsonb_typeof(new.inference_state -> 'last_inference_round') = 'object' then new.inference_state -> 'last_inference_round' else null end; if v_round is null then v_len := jsonb_array_length(coalesce(new.inference_state -> 'rounds', '[]'::jsonb)); if v_len > 0 then v_round := new.inference_state -> 'rounds' -> (v_len - 1); end if; end if; if v_round is not null and jsonb_typeof(v_round) = 'object' then begin new.entropy_before := (v_round ->> 'entropy_before')::double precision; exception when others then new.entropy_before := new.entropy_before; end; begin new.entropy_after := (v_round ->> 'entropy_after')::double precision; exception when others then new.entropy_after := new.entropy_after; end; if jsonb_typeof(v_round -> 'eliminated_ids') = 'array' then new.eliminated_candidate_ids := v_round -> 'eliminated_ids'; end if; if v_round ->> 'kind' in ('informative', 'low_information') then new.round_kind := v_round ->> 'kind'; end if; end if; if new.round_kind is null and new.posterior_before = new.posterior_after and new.score_deltas = '{}'::jsonb then new.round_kind := 'low_information'; end if; return new; end; $$; drop trigger if exists fill_agentic_rectification_inference_round on public.agentic_rectification_inference_transitions; create trigger fill_agentic_rectification_inference_round before insert or update of inference_state, posterior_before, posterior_after, score_deltas on public.agentic_rectification_inference_transitions for each row execute function public.fill_agentic_rectification_inference_round(); create or replace function public.get_agentic_rectification_latest_inference_transition( p_user_id uuid, p_case_id uuid ) returns jsonb language plpgsql stable security definer set search_path = '' as $$ declare v_case public.agentic_rectification_cases%rowtype; v_transition public.agentic_rectification_inference_transitions%rowtype; begin if p_user_id is null or p_case_id is null then raise exception 'agentic_rectification_invalid_input' using errcode = 'P0001'; end if; select * into v_case from public.agentic_rectification_cases where id = p_case_id and user_id = p_user_id; if not found then raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001'; end if; select * into v_transition from public.agentic_rectification_inference_transitions where case_id = p_case_id order by revision desc limit 1; if not found then return null; end if; return jsonb_build_object( 'id', v_transition.id, 'result_id', v_transition.result_id, 'previous_revision', v_transition.previous_revision, 'revision', v_transition.revision, 'probe_id', v_transition.probe_id, 'reason', v_transition.reason, 'decision_state_fingerprint', v_transition.decision_state_fingerprint, 'inference_state', v_transition.inference_state, 'posterior_before', v_transition.posterior_before, 'posterior_after', v_transition.posterior_after, 'score_deltas', v_transition.score_deltas, 'entropy_before', v_transition.entropy_before, 'entropy_after', v_transition.entropy_after, 'eliminated_candidate_ids', v_transition.eliminated_candidate_ids, 'round_kind', v_transition.round_kind ); end; $$; revoke all on function public.get_agentic_rectification_latest_inference_transition(uuid, uuid) from public, anon, authenticated; grant execute on function public.get_agentic_rectification_latest_inference_transition(uuid, uuid) to service_role; create or replace function public.list_agentic_rectification_inference_transitions( p_user_id uuid, p_case_id uuid ) returns jsonb language plpgsql stable security definer set search_path = '' as $$ declare v_case public.agentic_rectification_cases%rowtype; v_rows jsonb; begin if p_user_id is null or p_case_id is null then raise exception 'agentic_rectification_invalid_input' using errcode = 'P0001'; end if; select * into v_case from public.agentic_rectification_cases where id = p_case_id and user_id = p_user_id; if not found then raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001'; end if; select coalesce(jsonb_agg(jsonb_build_object( 'id', item.id, 'result_id', item.result_id, 'previous_revision', item.previous_revision, 'revision', item.revision, 'probe_id', item.probe_id, 'semantic_key', item.semantic_key, 'candidate_split_hash', item.candidate_split_hash, 'answer_class', item.answer_class, 'reason', item.reason, 'decision_state_fingerprint', item.decision_state_fingerprint, 'inference_state', item.inference_state, 'posterior_before', item.posterior_before, 'posterior_after', item.posterior_after, 'score_deltas', item.score_deltas, 'entropy_before', item.entropy_before, 'entropy_after', item.entropy_after, 'eliminated_candidate_ids', item.eliminated_candidate_ids, 'round_kind', item.round_kind ) order by item.revision), '[]'::jsonb) into v_rows from public.agentic_rectification_inference_transitions item where item.case_id = p_case_id; return v_rows; end; $$; revoke all on function public.list_agentic_rectification_inference_transitions(uuid, uuid) from public, anon, authenticated; grant execute on function public.list_agentic_rectification_inference_transitions(uuid, uuid) to service_role; commit;