Files
Jyotisha/frontend/supabase/migrations/20260827020000_rectification_vedastro_validation_retry.sql
T
Jesse_Chen f3327235ea
Independent Staging Quality Gate / validate (push) Successful in 10m50s
Independent Staging Quality Gate / publish (push) Successful in 13m29s
fix(rectification): remove static interview fallbacks
2026-08-27 16:40:47 +08:00

303 lines
13 KiB
PL/PgSQL

begin;
-- Register the semantic stop-and-review tool in both storage and the receipt
-- RPC. Without this forward allowlist update, the model can classify the stop
-- intent correctly but the first durable receipt is rejected by the database.
alter table public.agentic_rectification_tool_receipts
drop constraint if exists agentic_rectification_tool_receipts_tool_name_check,
add constraint agentic_rectification_tool_receipts_tool_name_check check (
tool_name in (
'rectification-read-case', 'rectification-set-focus',
'rectification-resolve-focus', 'rectification-record-evidence-batch',
'rectification-propose-evidence', 'rectification-confirm-evidence',
'rectification-revise-evidence', 'rectification-compare-candidates',
'rectification-read-diagnostics', 'rectification-offer-candidates',
'rectification-accept-candidate', 'rectification-confirm-birth-time',
'rectification-stop-and-review', 'rectification-close-case'
)
);
create or replace function public.insert_agentic_rectification_tool_receipt(
p_user_id uuid,
p_case_id uuid,
p_turn_id uuid,
p_tool_name text,
p_public_phase text,
p_status text,
p_input_fingerprint text,
p_result_fingerprint text,
p_engine_version text,
p_safe_error_code text,
p_executed_methods jsonb,
p_attempt_id uuid
)
returns jsonb
language plpgsql
security definer
set search_path = ''
as $$
declare
v_attempt public.agentic_rectification_run_attempts%rowtype;
v_receipt_id uuid;
begin
if p_user_id is null or p_case_id is null or p_turn_id is null or p_attempt_id is null
or p_tool_name not in (
'rectification-read-case', 'rectification-set-focus',
'rectification-resolve-focus', 'rectification-record-evidence-batch',
'rectification-propose-evidence', 'rectification-confirm-evidence',
'rectification-revise-evidence', 'rectification-compare-candidates',
'rectification-read-diagnostics', 'rectification-offer-candidates',
'rectification-accept-candidate', 'rectification-confirm-birth-time',
'rectification-stop-and-review', 'rectification-close-case'
)
or p_public_phase not in (
'run.started', 'skill.started', 'skill.loaded', 'skill.bound', 'case.loaded',
'intent.classified', 'evidence.proposed', 'evidence.confirmed',
'candidates.comparing', 'candidates.updated', 'diagnostics.completed',
'candidate.accepted', 'birth_time.confirmed', 'answer.composed',
'billing.settled', 'answer.delta', 'run.completed', 'run.failed'
)
or p_status not in ('started', 'completed', 'failed', 'skipped')
or p_executed_methods is null or jsonb_typeof(p_executed_methods) <> 'array'
or exists (
select 1 from jsonb_array_elements_text(p_executed_methods) method(value)
where method.value not in (
'd1-rashi', 'd2-hora', 'd3-drekkana', 'd4-chaturthamsha', 'd5-panchamsha',
'd7-saptamsha', 'd9-navamsa',
'd10-dashamsa', 'd11-labhamsha', 'd12-dwadashamsha',
'd24-chaturvimshamsha',
'd30-trimshamsha', 'vimshottari-dasha', 'narayana-dasha',
'gochara', 'ashtakavarga', 'shadbala', 'arudha-pada',
'functional-benefic-malefic'
)
) then
raise exception 'agentic_rectification_invalid_input' using errcode = 'P0001';
end if;
if not exists (
select 1 from public.agentic_rectification_cases
where id = p_case_id and user_id = p_user_id
) then
raise exception 'agentic_rectification_case_not_found' using errcode = 'P0001';
end if;
if not exists (
select 1 from public.agentic_rectification_turns
where id = p_turn_id and case_id = p_case_id
) then
raise exception 'agentic_rectification_turn_not_found' using errcode = 'P0001';
end if;
select * into v_attempt
from public.agentic_rectification_run_attempts
where id = p_attempt_id and case_id = p_case_id and turn_id = p_turn_id
for update;
if not found then
raise exception 'agentic_rectification_attempt_not_found' using errcode = 'P0001';
end if;
if v_attempt.status <> 'started' then
raise exception 'agentic_rectification_attempt_not_started' using errcode = 'P0001';
end if;
insert into public.agentic_rectification_tool_receipts (
case_id, turn_id, attempt_id, tool_name, public_phase, status,
input_fingerprint, result_fingerprint, engine_version, safe_error_code,
executed_methods, completed_at
) values (
p_case_id, p_turn_id, p_attempt_id, p_tool_name, p_public_phase, p_status,
p_input_fingerprint, p_result_fingerprint, p_engine_version, p_safe_error_code,
p_executed_methods,
case when p_status = 'completed' then pg_catalog.now() else null end
) returning id into v_receipt_id;
return jsonb_build_object('receipt_id', v_receipt_id, 'attempt_id', p_attempt_id);
end;
$$;
revoke all on function public.insert_agentic_rectification_tool_receipt(
uuid, uuid, uuid, text, text, text, text, text, text, text, jsonb, uuid
) from public, anon, authenticated;
grant execute on function public.insert_agentic_rectification_tool_receipt(
uuid, uuid, uuid, text, text, text, text, text, text, text, jsonb, uuid
) to service_role;
-- A transient VedAstro failure must be retryable without recomputing or mutating
-- the candidate ranking. Only the current fresh result's external validation
-- receipt may change; all candidate, inference and selection state stays intact.
create or replace function public.refresh_agentic_rectification_vedastro_validation(
p_user_id uuid,
p_case_id uuid,
p_result_id uuid,
p_evidence_ledger_fingerprint text,
p_candidate_range_fingerprint text,
p_validation jsonb,
p_minute_sensitive_status text
)
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_profile public.profiles%rowtype;
v_snapshot jsonb;
v_status text;
v_minute_sensitive_status text;
v_failure_code text;
v_safe_validation jsonb;
v_exact jsonb;
v_gates jsonb;
v_receipt jsonb;
begin
if p_user_id is null or p_case_id is null or p_result_id is null
or length(btrim(coalesce(p_evidence_ledger_fingerprint, ''))) = 0
or length(btrim(coalesce(p_candidate_range_fingerprint, ''))) = 0
or p_validation is null or jsonb_typeof(p_validation) <> 'object'
or p_minute_sensitive_status not in ('passed', 'failed', 'not_evaluated') then
raise exception 'agentic_rectification_invalid_input' using errcode = 'P0001';
end if;
v_status := p_validation ->> 'status';
if v_status not in ('passed', 'failed', 'not_evaluated')
or jsonb_typeof(p_validation -> 'search_events_primary_supports_local_winner') is distinct from 'boolean'
or jsonb_typeof(p_validation -> 'can_confirm_exact_minute') is distinct from 'boolean'
or (
jsonb_typeof(p_validation -> 'failure') is distinct from 'object'
and jsonb_typeof(p_validation -> 'failure') is distinct from 'null'
) then
raise exception 'agentic_rectification_invalid_validation' using errcode = 'P0001';
end if;
v_failure_code := case
when jsonb_typeof(p_validation -> 'failure') = 'object'
then nullif(btrim(coalesce(p_validation #>> '{failure,code}', '')), '')
else null
end;
if v_failure_code is not null
and v_failure_code not in ('timeout', 'engine_request_failed', 'engine_invalid_response', 'unknown') then
raise exception 'agentic_rectification_invalid_validation' using errcode = 'P0001';
end if;
if p_minute_sensitive_status = 'passed' and v_status <> 'passed' then
raise exception 'agentic_rectification_invalid_validation' using errcode = 'P0001';
end if;
if (p_validation ->> 'can_confirm_exact_minute')::boolean
and (v_status <> 'passed' or p_minute_sensitive_status <> 'passed') then
raise exception 'agentic_rectification_invalid_validation' using errcode = 'P0001';
end if;
v_minute_sensitive_status := case
when v_status = 'passed' then p_minute_sensitive_status
when v_status = 'failed' then 'failed'
else 'not_evaluated'
end;
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', 'needs_rebaseline') then
raise exception 'agentic_rectification_case_terminal' using errcode = 'P0001';
end if;
select * into v_result
from public.agentic_rectification_results
where id = p_result_id
and user_id = p_user_id
and case_id = p_case_id
for update;
if not found then
raise exception 'agentic_rectification_candidate_not_found' using errcode = 'P0001';
end if;
if v_result.invalidated_at is not null or v_result.expires_at <= pg_catalog.now()
or v_result.evidence_ledger_fingerprint is distinct from p_evidence_ledger_fingerprint
or v_result.candidate_range_fingerprint is distinct from p_candidate_range_fingerprint then
raise exception 'agentic_rectification_candidate_expired' using errcode = 'P0001';
end if;
if exists (
select 1
from public.agentic_rectification_results newer
where newer.user_id = p_user_id
and newer.case_id = p_case_id
and newer.invalidated_at is null
and newer.created_at > v_result.created_at
) then
raise exception 'agentic_rectification_candidate_superseded' using errcode = 'P0001';
end if;
select * into v_profile
from public.profiles
where id = p_user_id;
if not found then
raise exception 'agentic_rectification_candidate_profile_changed' using errcode = 'P0001';
end if;
v_snapshot := v_case.baseline_birth_snapshot;
if v_profile.birth_date is distinct from (v_snapshot ->> 'birth_date')::date
or v_profile.reported_birth_time is distinct from (v_snapshot ->> 'reported_birth_time')::time without time zone
or v_profile.birth_time_source is distinct from v_snapshot ->> 'birth_time_source'
or v_profile.birth_time_period is distinct from v_snapshot ->> 'birth_time_period'
or v_profile.declared_window_start is distinct from v_snapshot ->> 'declared_window_start'
or v_profile.declared_window_end is distinct from v_snapshot ->> 'declared_window_end'
or v_profile.uncertainty_before_minutes is distinct from (v_snapshot ->> 'uncertainty_before_minutes')::integer
or v_profile.uncertainty_after_minutes is distinct from (v_snapshot ->> 'uncertainty_after_minutes')::integer
or v_profile.latitude is distinct from (v_snapshot ->> 'latitude')::double precision
or v_profile.longitude is distinct from (v_snapshot ->> 'longitude')::double precision
or v_profile.timezone_id is distinct from v_snapshot ->> 'timezone_id'
or v_profile.timezone_offset is distinct from (v_snapshot ->> 'timezone_offset')::double precision then
raise exception 'agentic_rectification_candidate_profile_changed' using errcode = 'P0001';
end if;
v_safe_validation := jsonb_build_object(
'status', v_status,
'search_events_primary_supports_local_winner',
(p_validation ->> 'search_events_primary_supports_local_winner')::boolean,
'can_confirm_exact_minute',
(p_validation ->> 'can_confirm_exact_minute')::boolean,
'failure', case
when v_failure_code is null then 'null'::jsonb
else jsonb_build_object('code', v_failure_code)
end
);
v_receipt := case
when jsonb_typeof(v_result.decision_receipt) = 'object' then v_result.decision_receipt
else '{}'::jsonb
end;
v_gates := case
when jsonb_typeof(v_receipt -> 'gates') = 'object' then v_receipt -> 'gates'
else '{}'::jsonb
end;
v_exact := case
when jsonb_typeof(v_gates -> 'exact_confirmation') = 'object' then v_gates -> 'exact_confirmation'
else '{}'::jsonb
end;
v_exact := jsonb_set(v_exact, '{vedastro_event_validation}', v_safe_validation, true);
v_exact := jsonb_set(v_exact, '{external_validation_status}', to_jsonb(v_minute_sensitive_status), true);
v_gates := jsonb_set(v_gates, '{exact_confirmation}', v_exact, true);
v_receipt := jsonb_set(v_receipt, '{gates}', v_gates, true);
v_receipt := jsonb_set(v_receipt, '{unique_minute_claim}', 'false'::jsonb, true);
update public.agentic_rectification_results
set decision_receipt = v_receipt,
updated_at = pg_catalog.now()
where id = v_result.id;
return jsonb_build_object(
'result_id', v_result.id,
'decision_receipt', public.compose_agentic_rectification_decision_receipt(
v_case.id,
v_result.id,
v_receipt
)
);
end;
$$;
revoke all on function public.refresh_agentic_rectification_vedastro_validation(uuid, uuid, uuid, text, text, jsonb, text)
from public, anon, authenticated;
grant execute on function public.refresh_agentic_rectification_vedastro_validation(uuid, uuid, uuid, text, text, jsonb, text)
to service_role;
commit;