8e31680b45
Intake stores how sure the user is; rectification now searches that range, offers a one-click widen when event fit is low at the edge, and trisects windows longer than two hours before the minute grid. Co-authored-by: Cursor <cursoragent@cursor.com>
701 lines
24 KiB
PL/PgSQL
701 lines
24 KiB
PL/PgSQL
-- Declared uncertainty: sub-window block_scan, widen RPC, date reliability.
|
|
-- Exclusive span > 120 stays in block_scan; inclusive width cap for widen is 241.
|
|
|
|
begin;
|
|
|
|
do $migration$
|
|
begin
|
|
if current_user <> 'schema_owner' then
|
|
raise exception 'rectification_declared_uncertainty_requires_schema_owner'
|
|
using errcode = '42501';
|
|
end if;
|
|
end
|
|
$migration$;
|
|
|
|
alter table public.agentic_rectification_cases
|
|
add column if not exists widen_declined_at_fingerprint text;
|
|
|
|
comment on column public.agentic_rectification_cases.widen_declined_at_fingerprint is
|
|
'Evidence ledger fingerprint at which the user declined a widen-window card.';
|
|
|
|
alter table public.agentic_rectification_evidence
|
|
add column if not exists date_reliability text;
|
|
|
|
alter table public.agentic_rectification_evidence
|
|
drop constraint if exists agentic_rectification_evidence_date_reliability_check;
|
|
|
|
alter table public.agentic_rectification_evidence
|
|
add constraint agentic_rectification_evidence_date_reliability_check
|
|
check (
|
|
date_reliability is null
|
|
or date_reliability in ('high', 'medium', 'low', 'uncertain', 'unreliable')
|
|
);
|
|
|
|
comment on column public.agentic_rectification_evidence.date_reliability is
|
|
'Optional day-event reliability: high = checked record, medium = memory.';
|
|
|
|
create or replace function public.agentic_rectification_is_clock(p_clock text)
|
|
returns boolean
|
|
language sql
|
|
immutable
|
|
parallel safe
|
|
set search_path = ''
|
|
as $$
|
|
select p_clock is not null
|
|
and p_clock ~ '^([01][0-9]|2[0-3]):[0-5][0-9]$';
|
|
$$;
|
|
|
|
create or replace function public.agentic_rectification_clock_minutes(p_clock text)
|
|
returns integer
|
|
language sql
|
|
immutable
|
|
strict
|
|
parallel safe
|
|
set search_path = ''
|
|
as $$
|
|
select split_part(p_clock, ':', 1)::integer * 60 + split_part(p_clock, ':', 2)::integer;
|
|
$$;
|
|
|
|
create or replace function public.agentic_rectification_clock_span_minutes(
|
|
p_start text,
|
|
p_end text
|
|
)
|
|
returns integer
|
|
language sql
|
|
immutable
|
|
strict
|
|
parallel safe
|
|
set search_path = ''
|
|
as $$
|
|
select case
|
|
when public.agentic_rectification_clock_minutes(p_end)
|
|
>= public.agentic_rectification_clock_minutes(p_start)
|
|
then public.agentic_rectification_clock_minutes(p_end)
|
|
- public.agentic_rectification_clock_minutes(p_start)
|
|
else 1440 - public.agentic_rectification_clock_minutes(p_start)
|
|
+ public.agentic_rectification_clock_minutes(p_end)
|
|
end;
|
|
$$;
|
|
|
|
create or replace function public.agentic_rectification_clock_inclusive_width(
|
|
p_start text,
|
|
p_end text
|
|
)
|
|
returns integer
|
|
language sql
|
|
immutable
|
|
strict
|
|
parallel safe
|
|
set search_path = ''
|
|
as $$
|
|
select public.agentic_rectification_clock_span_minutes(p_start, p_end) + 1;
|
|
$$;
|
|
|
|
create or replace function public.agentic_rectification_clock_contains(
|
|
p_outer_start text,
|
|
p_outer_end text,
|
|
p_inner_start text,
|
|
p_inner_end text
|
|
)
|
|
returns boolean
|
|
language plpgsql
|
|
immutable
|
|
strict
|
|
parallel safe
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_outer_width integer;
|
|
v_origin integer;
|
|
v_inner_start integer;
|
|
v_inner_end integer;
|
|
v_outer_last integer;
|
|
begin
|
|
v_outer_width := public.agentic_rectification_clock_inclusive_width(p_outer_start, p_outer_end);
|
|
if v_outer_width >= 1440 then
|
|
return true;
|
|
end if;
|
|
v_origin := public.agentic_rectification_clock_minutes(p_outer_start);
|
|
v_inner_start := (
|
|
public.agentic_rectification_clock_minutes(p_inner_start) - v_origin + 1440
|
|
) % 1440;
|
|
v_inner_end := (
|
|
public.agentic_rectification_clock_minutes(p_inner_end) - v_origin + 1440
|
|
) % 1440;
|
|
v_outer_last := v_outer_width - 1;
|
|
if v_inner_start <= v_inner_end then
|
|
return v_inner_start <= v_outer_last and v_inner_end <= v_outer_last;
|
|
end if;
|
|
return false;
|
|
end;
|
|
$$;
|
|
|
|
revoke all on function public.agentic_rectification_is_clock(text)
|
|
from public, anon, authenticated;
|
|
revoke all on function public.agentic_rectification_clock_minutes(text)
|
|
from public, anon, authenticated;
|
|
revoke all on function public.agentic_rectification_clock_span_minutes(text, text)
|
|
from public, anon, authenticated;
|
|
revoke all on function public.agentic_rectification_clock_inclusive_width(text, text)
|
|
from public, anon, authenticated;
|
|
revoke all on function public.agentic_rectification_clock_contains(text, text, text, text)
|
|
from public, anon, authenticated;
|
|
grant execute on function public.agentic_rectification_is_clock(text) to service_role;
|
|
grant execute on function public.agentic_rectification_clock_minutes(text) to service_role;
|
|
grant execute on function public.agentic_rectification_clock_span_minutes(text, text) to service_role;
|
|
grant execute on function public.agentic_rectification_clock_inclusive_width(text, text) to service_role;
|
|
grant execute on function public.agentic_rectification_clock_contains(text, text, text, text) to service_role;
|
|
|
|
create or replace function public.set_agentic_rectification_case_stage(
|
|
p_user_id uuid,
|
|
p_case_id uuid,
|
|
p_stage text
|
|
)
|
|
returns jsonb
|
|
language plpgsql
|
|
security definer
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_case public.agentic_rectification_cases%rowtype;
|
|
begin
|
|
if p_user_id is null or p_case_id is null or p_stage not in ('minute', 'block_scan') 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
|
|
for update;
|
|
if not found then
|
|
raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001';
|
|
end if;
|
|
if v_case.status in ('confirmed', 'closed', 'abandoned', 'superseded') then
|
|
raise exception 'agentic_rectification_case_terminal' using errcode = 'P0001';
|
|
end if;
|
|
update public.agentic_rectification_cases
|
|
set
|
|
stage = p_stage,
|
|
last_activity_at = pg_catalog.now()
|
|
where id = v_case.id;
|
|
return jsonb_build_object(
|
|
'case_id', v_case.id,
|
|
'stage', p_stage
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
create or replace function public.advance_agentic_rectification_case_from_block_scan(
|
|
p_user_id uuid,
|
|
p_case_id uuid,
|
|
p_start_time text,
|
|
p_end_time text
|
|
)
|
|
returns jsonb
|
|
language plpgsql
|
|
security definer
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_case public.agentic_rectification_cases%rowtype;
|
|
v_range jsonb;
|
|
v_current_start text;
|
|
v_current_end text;
|
|
v_span integer;
|
|
v_rounds integer;
|
|
v_stage text;
|
|
v_block_scan jsonb;
|
|
begin
|
|
if p_user_id is null or p_case_id is null
|
|
or not public.agentic_rectification_is_clock(p_start_time)
|
|
or not public.agentic_rectification_is_clock(p_end_time)
|
|
or p_start_time = p_end_time 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
|
|
for update;
|
|
if not found then
|
|
raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001';
|
|
end if;
|
|
if v_case.status in ('confirmed', 'closed', 'abandoned', 'superseded') then
|
|
raise exception 'agentic_rectification_case_terminal' using errcode = 'P0001';
|
|
end if;
|
|
if v_case.stage is distinct from 'block_scan' then
|
|
raise exception 'agentic_rectification_not_block_scan' using errcode = 'P0001';
|
|
end if;
|
|
v_current_start := coalesce(v_case.candidate_range->>'start_time', '');
|
|
v_current_end := coalesce(v_case.candidate_range->>'end_time', '');
|
|
if not public.agentic_rectification_is_clock(v_current_start)
|
|
or not public.agentic_rectification_is_clock(v_current_end) then
|
|
raise exception 'agentic_rectification_invalid_range' using errcode = 'P0001';
|
|
end if;
|
|
if not public.agentic_rectification_clock_contains(
|
|
v_current_start, v_current_end, p_start_time, p_end_time
|
|
) then
|
|
raise exception 'agentic_rectification_invalid_block_window' using errcode = 'P0001';
|
|
end if;
|
|
v_span := public.agentic_rectification_clock_span_minutes(p_start_time, p_end_time);
|
|
begin
|
|
v_rounds := coalesce((v_case.block_scan->>'rounds')::integer, 0);
|
|
exception
|
|
when invalid_text_representation then
|
|
v_rounds := 0;
|
|
end;
|
|
if v_rounds < 0 then
|
|
v_rounds := 0;
|
|
end if;
|
|
v_range := jsonb_build_object('start_time', p_start_time, 'end_time', p_end_time);
|
|
if v_span > 120 and v_rounds < 3 then
|
|
v_stage := 'block_scan';
|
|
v_block_scan := jsonb_build_object('rounds', v_rounds);
|
|
else
|
|
v_stage := 'minute';
|
|
v_block_scan := null;
|
|
end if;
|
|
update public.agentic_rectification_results
|
|
set invalidated_at = pg_catalog.now()
|
|
where case_id = v_case.id
|
|
and invalidated_at is null;
|
|
update public.agentic_rectification_cases
|
|
set
|
|
candidate_range = v_range,
|
|
stage = v_stage,
|
|
block_scan = v_block_scan,
|
|
last_activity_at = pg_catalog.now()
|
|
where id = v_case.id;
|
|
return jsonb_build_object(
|
|
'case_id', v_case.id,
|
|
'stage', v_stage,
|
|
'candidate_range', v_range
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
create or replace function public.widen_agentic_rectification_case_window(
|
|
p_user_id uuid,
|
|
p_case_id uuid,
|
|
p_start_time text,
|
|
p_end_time text
|
|
)
|
|
returns jsonb
|
|
language plpgsql
|
|
security definer
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_case public.agentic_rectification_cases%rowtype;
|
|
v_range jsonb;
|
|
v_current_start text;
|
|
v_current_end text;
|
|
v_old_width integer;
|
|
v_new_width integer;
|
|
begin
|
|
if p_user_id is null or p_case_id is null
|
|
or not public.agentic_rectification_is_clock(p_start_time)
|
|
or not public.agentic_rectification_is_clock(p_end_time)
|
|
or p_start_time = p_end_time 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
|
|
for update;
|
|
if not found then
|
|
raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001';
|
|
end if;
|
|
if v_case.status in ('confirmed', 'closed', 'abandoned', 'superseded') then
|
|
raise exception 'agentic_rectification_case_terminal' using errcode = 'P0001';
|
|
end if;
|
|
if v_case.accepted_time is not null then
|
|
raise exception 'agentic_rectification_already_adopted' using errcode = 'P0001';
|
|
end if;
|
|
if coalesce(v_case.stage, 'minute') is distinct from 'minute' then
|
|
raise exception 'agentic_rectification_not_minute' using errcode = 'P0001';
|
|
end if;
|
|
v_current_start := coalesce(v_case.candidate_range->>'start_time', '');
|
|
v_current_end := coalesce(v_case.candidate_range->>'end_time', '');
|
|
if not public.agentic_rectification_is_clock(v_current_start)
|
|
or not public.agentic_rectification_is_clock(v_current_end) then
|
|
raise exception 'agentic_rectification_invalid_range' using errcode = 'P0001';
|
|
end if;
|
|
if not public.agentic_rectification_clock_contains(
|
|
p_start_time, p_end_time, v_current_start, v_current_end
|
|
) then
|
|
raise exception 'agentic_rectification_invalid_widen_window' using errcode = 'P0001';
|
|
end if;
|
|
v_old_width := public.agentic_rectification_clock_inclusive_width(v_current_start, v_current_end);
|
|
v_new_width := public.agentic_rectification_clock_inclusive_width(p_start_time, p_end_time);
|
|
if v_new_width <= v_old_width or v_new_width > 241 then
|
|
raise exception 'agentic_rectification_invalid_widen_window' using errcode = 'P0001';
|
|
end if;
|
|
v_range := jsonb_build_object('start_time', p_start_time, 'end_time', p_end_time);
|
|
update public.agentic_rectification_results
|
|
set invalidated_at = pg_catalog.now()
|
|
where case_id = v_case.id
|
|
and invalidated_at is null;
|
|
update public.agentic_rectification_cases
|
|
set
|
|
candidate_range = v_range,
|
|
last_activity_at = pg_catalog.now()
|
|
where id = v_case.id;
|
|
return jsonb_build_object(
|
|
'case_id', v_case.id,
|
|
'stage', 'minute',
|
|
'candidate_range', v_range
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
create or replace function public.set_agentic_rectification_widen_declined(
|
|
p_user_id uuid,
|
|
p_case_id uuid,
|
|
p_fingerprint text
|
|
)
|
|
returns jsonb
|
|
language plpgsql
|
|
security definer
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_case public.agentic_rectification_cases%rowtype;
|
|
begin
|
|
if p_user_id is null or p_case_id is null
|
|
or p_fingerprint is null or btrim(p_fingerprint) = '' 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
|
|
for update;
|
|
if not found then
|
|
raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001';
|
|
end if;
|
|
if v_case.status in ('confirmed', 'closed', 'abandoned', 'superseded') then
|
|
raise exception 'agentic_rectification_case_terminal' using errcode = 'P0001';
|
|
end if;
|
|
update public.agentic_rectification_cases
|
|
set
|
|
widen_declined_at_fingerprint = btrim(p_fingerprint),
|
|
last_activity_at = pg_catalog.now()
|
|
where id = v_case.id;
|
|
return jsonb_build_object(
|
|
'case_id', v_case.id,
|
|
'widen_declined_at_fingerprint', btrim(p_fingerprint)
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
create or replace function public.set_agentic_rectification_evidence_date_reliability(
|
|
p_user_id uuid,
|
|
p_case_id uuid,
|
|
p_evidence_id uuid,
|
|
p_date_reliability text
|
|
)
|
|
returns jsonb
|
|
language plpgsql
|
|
security definer
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_case public.agentic_rectification_cases%rowtype;
|
|
v_evidence public.agentic_rectification_evidence%rowtype;
|
|
begin
|
|
if p_user_id is null or p_case_id is null or p_evidence_id is null
|
|
or p_date_reliability not in ('high', 'medium') 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
|
|
for update;
|
|
if not found then
|
|
raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001';
|
|
end if;
|
|
if v_case.status in ('confirmed', 'closed', 'abandoned', 'superseded') then
|
|
raise exception 'agentic_rectification_case_terminal' using errcode = 'P0001';
|
|
end if;
|
|
select * into v_evidence
|
|
from public.agentic_rectification_evidence
|
|
where id = p_evidence_id and case_id = v_case.id
|
|
for update;
|
|
if not found then
|
|
raise exception 'agentic_rectification_evidence_not_found' using errcode = 'P0001';
|
|
end if;
|
|
update public.agentic_rectification_evidence
|
|
set date_reliability = p_date_reliability
|
|
where id = v_evidence.id;
|
|
return jsonb_build_object(
|
|
'evidence_id', v_evidence.id,
|
|
'date_reliability', p_date_reliability
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
revoke all on function public.widen_agentic_rectification_case_window(uuid, uuid, text, text)
|
|
from public, anon, authenticated;
|
|
grant execute on function public.widen_agentic_rectification_case_window(uuid, uuid, text, text)
|
|
to service_role;
|
|
|
|
revoke all on function public.set_agentic_rectification_widen_declined(uuid, uuid, text)
|
|
from public, anon, authenticated;
|
|
grant execute on function public.set_agentic_rectification_widen_declined(uuid, uuid, text)
|
|
to service_role;
|
|
|
|
revoke all on function public.set_agentic_rectification_evidence_date_reliability(uuid, uuid, uuid, text)
|
|
from public, anon, authenticated;
|
|
grant execute on function public.set_agentic_rectification_evidence_date_reliability(uuid, uuid, uuid, text)
|
|
to service_role;
|
|
|
|
create or replace function public.get_agentic_rectification_case(
|
|
p_user_id uuid,
|
|
p_case_id uuid
|
|
)
|
|
returns jsonb
|
|
language plpgsql
|
|
security definer
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_case public.agentic_rectification_cases%rowtype;
|
|
v_result public.agentic_rectification_results%rowtype;
|
|
v_evidence_count bigint;
|
|
v_turn_count bigint;
|
|
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 count(*) into v_evidence_count
|
|
from public.agentic_rectification_evidence
|
|
where case_id = v_case.id;
|
|
|
|
select count(*) into v_turn_count
|
|
from public.agentic_rectification_turns
|
|
where case_id = v_case.id;
|
|
|
|
select * into v_result
|
|
from public.agentic_rectification_results
|
|
where case_id = v_case.id
|
|
and invalidated_at is null
|
|
order by created_at desc
|
|
limit 1;
|
|
|
|
return jsonb_build_object(
|
|
'case_id', v_case.id,
|
|
'session_id', v_case.session_id,
|
|
'status', v_case.status,
|
|
'skill_name', v_case.skill_name,
|
|
'skill_version', v_case.skill_version,
|
|
'candidate_range', v_case.candidate_range,
|
|
'stage', coalesce(v_case.stage, 'minute'),
|
|
'block_scan', v_case.block_scan,
|
|
'widen_declined_at_fingerprint', v_case.widen_declined_at_fingerprint,
|
|
'reported_birth_time', v_case.baseline_birth_snapshot->>'reported_birth_time',
|
|
'birth_time_source', v_case.baseline_birth_snapshot->>'birth_time_source',
|
|
'accepted_time', v_case.accepted_time,
|
|
'confirmed_time', v_case.confirmed_time,
|
|
'created_at', v_case.created_at,
|
|
'last_activity_at', v_case.last_activity_at,
|
|
'completed_at', v_case.completed_at,
|
|
'closed_reason', v_case.closed_reason,
|
|
'evidence_count', v_evidence_count,
|
|
'turn_count', v_turn_count,
|
|
'latest_result', case
|
|
when v_result.id is null then null
|
|
else jsonb_build_object(
|
|
'result_id', v_result.id,
|
|
'candidates', v_result.candidates,
|
|
'overall_confidence', v_result.overall_confidence,
|
|
'display_allowed', v_result.display_allowed,
|
|
'selection_allowed', v_result.selection_allowed,
|
|
'confirmation_allowed', v_result.confirmation_allowed,
|
|
'representative_time', v_result.representative_time,
|
|
'selected_candidate_id', v_result.selected_candidate_id,
|
|
'selected_time', v_result.selected_time,
|
|
'selection_kind', v_result.selection_kind,
|
|
'evidence_ledger_fingerprint', v_result.evidence_ledger_fingerprint,
|
|
'candidate_range_fingerprint', v_result.candidate_range_fingerprint,
|
|
'skill_version', v_result.skill_version,
|
|
'algorithm_version', v_result.algorithm_version,
|
|
'event_contract_version', v_result.event_contract_version,
|
|
'decision_policy_version', v_result.decision_policy_version,
|
|
'decision_receipt', public.compose_agentic_rectification_decision_receipt(v_case.id, v_result.id, v_result.decision_receipt),
|
|
'execution_ledger', v_result.execution_ledger,
|
|
'created_at', v_result.created_at,
|
|
'invalidated_at', v_result.invalidated_at
|
|
)
|
|
end
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
revoke all on function public.get_agentic_rectification_case(uuid, uuid)
|
|
from public, anon, authenticated;
|
|
grant execute on function public.get_agentic_rectification_case(uuid, uuid)
|
|
to service_role;
|
|
|
|
create or replace function public.get_agentic_rectification_case_dossier(
|
|
p_user_id uuid,
|
|
p_case_id uuid
|
|
)
|
|
returns jsonb
|
|
language plpgsql
|
|
security definer
|
|
set search_path = ''
|
|
as $$
|
|
declare
|
|
v_case public.agentic_rectification_cases%rowtype;
|
|
v_turns jsonb;
|
|
v_evidence jsonb;
|
|
v_summary public.agentic_rectification_case_conversation_summaries%rowtype;
|
|
v_result public.agentic_rectification_results%rowtype;
|
|
v_evidence_count bigint;
|
|
v_turn_count bigint;
|
|
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', recent.id,
|
|
'role', message.role,
|
|
'text', message.text,
|
|
'status', recent.status,
|
|
'created_at', recent.created_at,
|
|
'completed_at', recent.completed_at
|
|
) order by recent.created_at, recent.id, message.ordinal), '[]'::jsonb)
|
|
into v_turns
|
|
from (
|
|
select t.*
|
|
from public.agentic_rectification_turns t
|
|
where t.case_id = v_case.id
|
|
order by t.created_at desc, t.id desc
|
|
limit 50
|
|
) recent
|
|
cross join lateral (
|
|
values
|
|
(1, 'user'::text, recent.user_message),
|
|
(2, 'assistant'::text, recent.assistant_message)
|
|
) as message(ordinal, role, text)
|
|
where message.text is not null;
|
|
|
|
select coalesce(jsonb_agg(jsonb_build_object(
|
|
'id', e.id,
|
|
'source_turn_id', e.source_turn_id,
|
|
'subject', e.subject,
|
|
'event_kind', e.event_kind,
|
|
'domain', e.domain,
|
|
'occurred_from', e.occurred_from,
|
|
'occurred_to', e.occurred_to,
|
|
'date_precision', e.date_precision,
|
|
'date_reliability', e.date_reliability,
|
|
'summary', e.summary,
|
|
'status', e.status,
|
|
'supersedes_evidence_id', e.supersedes_evidence_id,
|
|
'created_at', e.created_at
|
|
) order by e.created_at, e.id), '[]'::jsonb)
|
|
into v_evidence
|
|
from public.agentic_rectification_evidence e
|
|
where e.case_id = v_case.id;
|
|
|
|
select count(*) into v_evidence_count
|
|
from public.agentic_rectification_evidence where case_id = v_case.id;
|
|
select count(*) into v_turn_count
|
|
from public.agentic_rectification_turns where case_id = v_case.id;
|
|
|
|
select * into v_summary
|
|
from public.agentic_rectification_case_conversation_summaries
|
|
where case_id = v_case.id;
|
|
if not found then
|
|
perform public.refresh_agentic_rectification_case_conversation_summary(v_case.id);
|
|
select * into v_summary
|
|
from public.agentic_rectification_case_conversation_summaries
|
|
where case_id = v_case.id;
|
|
end if;
|
|
|
|
select * into v_result
|
|
from public.agentic_rectification_results
|
|
where case_id = v_case.id and invalidated_at is null
|
|
order by created_at desc, id desc
|
|
limit 1;
|
|
|
|
return jsonb_build_object(
|
|
'case', jsonb_build_object(
|
|
'case_id', v_case.id,
|
|
'session_id', v_case.session_id,
|
|
'status', v_case.status,
|
|
'skill_name', v_case.skill_name,
|
|
'skill_version', v_case.skill_version,
|
|
'candidate_range', v_case.candidate_range,
|
|
'stage', coalesce(v_case.stage, 'minute'),
|
|
'block_scan', v_case.block_scan,
|
|
'widen_declined_at_fingerprint', v_case.widen_declined_at_fingerprint,
|
|
'reported_birth_time', v_case.baseline_birth_snapshot->>'reported_birth_time',
|
|
'birth_time_source', v_case.baseline_birth_snapshot->>'birth_time_source',
|
|
'accepted_time', v_case.accepted_time,
|
|
'confirmed_time', v_case.confirmed_time,
|
|
'completed_at', v_case.completed_at,
|
|
'closed_reason', v_case.closed_reason,
|
|
'last_activity_at', v_case.last_activity_at,
|
|
'evidence_count', v_evidence_count,
|
|
'turn_count', v_turn_count
|
|
),
|
|
'turns', v_turns,
|
|
'evidence', v_evidence,
|
|
'conversation_summary', jsonb_build_object(
|
|
'confirmed_evidence_summary', v_summary.confirmed_evidence_summary,
|
|
'pending_revisions', v_summary.pending_revisions,
|
|
'active_focus', v_summary.active_focus,
|
|
'declined_skipped_topics', v_summary.declined_skipped_topics,
|
|
'candidate_divergence_summary', v_summary.candidate_divergence_summary,
|
|
'missing_evidence_categories', v_summary.missing_evidence_categories,
|
|
'last_result_policy', v_summary.last_result_policy,
|
|
'summary_version', v_summary.summary_version,
|
|
'updated_at', v_summary.updated_at
|
|
),
|
|
'latest_result', case when v_result.id is null then null else jsonb_build_object(
|
|
'result_id', v_result.id,
|
|
'candidates', v_result.candidates,
|
|
'overall_confidence', v_result.overall_confidence,
|
|
'display_allowed', v_result.display_allowed,
|
|
'selection_allowed', v_result.selection_allowed,
|
|
'confirmation_allowed', v_result.confirmation_allowed,
|
|
'representative_time', v_result.representative_time,
|
|
'selected_candidate_id', v_result.selected_candidate_id,
|
|
'selected_time', v_result.selected_time,
|
|
'selection_kind', v_result.selection_kind,
|
|
'evidence_ledger_fingerprint', v_result.evidence_ledger_fingerprint,
|
|
'candidate_range_fingerprint', v_result.candidate_range_fingerprint,
|
|
'skill_version', v_result.skill_version,
|
|
'algorithm_version', v_result.algorithm_version,
|
|
'event_contract_version', v_result.event_contract_version,
|
|
'decision_policy_version', v_result.decision_policy_version,
|
|
'decision_receipt', public.compose_agentic_rectification_decision_receipt(v_case.id, v_result.id, v_result.decision_receipt),
|
|
'execution_ledger', v_result.execution_ledger,
|
|
'created_at', v_result.created_at,
|
|
'invalidated_at', v_result.invalidated_at
|
|
) end
|
|
);
|
|
end;
|
|
$$;
|
|
|
|
revoke all on function public.get_agentic_rectification_case_dossier(uuid, uuid)
|
|
from public, anon, authenticated;
|
|
grant execute on function public.get_agentic_rectification_case_dossier(uuid, uuid)
|
|
to service_role;
|
|
|
|
commit;
|