166 lines
9.5 KiB
PL/PgSQL
166 lines
9.5 KiB
PL/PgSQL
create or replace function public.upgrade_birth_time_legacy_case(
|
|
p_user_id uuid, p_case_id uuid, p_expected_version bigint,
|
|
p_public_turn_state jsonb, p_private_state jsonb
|
|
)
|
|
returns bigint language plpgsql security definer set search_path = '' as $$
|
|
declare
|
|
v_case public.birth_time_rectification_cases%rowtype;
|
|
v_action text;
|
|
begin
|
|
select c.* into v_case from public.birth_time_rectification_cases c
|
|
where c.id = p_case_id and c.user_id = p_user_id for update;
|
|
if not found then raise exception 'birth_time_legacy_case_not_found'; end if;
|
|
if v_case.journey_protocol = 'dynamic-choice-v2' then return v_case.turn_version; end if;
|
|
v_action = v_case.turn_state #>> '{nextAction,kind}';
|
|
if v_case.journey_snapshot ->> 'state' in ('candidate', 'confirming', 'ready')
|
|
or v_action in ('present_low_result', 'present_medium_result', 'candidate_saved',
|
|
'request_candidate_confirmation', 'ready') then
|
|
raise exception 'birth_time_legacy_case_terminal';
|
|
end if;
|
|
if v_case.turn_version is distinct from p_expected_version
|
|
or p_public_turn_state ->> 'journeyProtocol' is distinct from 'dynamic-choice-v2'
|
|
or (p_public_turn_state ->> 'turnVersion')::bigint is distinct from p_expected_version
|
|
or jsonb_typeof(p_private_state) is distinct from 'object' then
|
|
raise exception 'stale_birth_time_legacy_upgrade';
|
|
end if;
|
|
update public.birth_time_rectification_cases
|
|
set journey_protocol = 'dynamic-choice-v2', turn_state = p_public_turn_state,
|
|
evidence_draft = null
|
|
where id = p_case_id and user_id = p_user_id
|
|
and journey_protocol = 'legacy-guided-v1' and turn_version = p_expected_version;
|
|
if not found then raise exception 'stale_birth_time_legacy_upgrade'; end if;
|
|
perform public.persist_birth_time_dynamic_private_state(p_case_id, p_user_id, p_private_state);
|
|
return p_expected_version;
|
|
end;
|
|
$$;
|
|
|
|
create or replace function public.complete_birth_time_dynamic_scoring_job(
|
|
p_user_id uuid, p_case_id uuid, p_job_id uuid, p_expected_version bigint,
|
|
p_evidence_fingerprint text, p_algorithm_version text,
|
|
p_public_turn_state jsonb, p_snapshot jsonb, p_candidate_result jsonb,
|
|
p_private_state jsonb
|
|
)
|
|
returns bigint language plpgsql security definer set search_path = '' as $$
|
|
declare
|
|
v_case public.birth_time_rectification_cases%rowtype;
|
|
v_job public.birth_time_rectification_scoring_jobs%rowtype;
|
|
begin
|
|
select j.* into v_job from public.birth_time_rectification_scoring_jobs j
|
|
where j.id = p_job_id and j.case_id = p_case_id and j.user_id = p_user_id for update;
|
|
if not found then raise exception 'birth_time_dynamic_scoring_job_not_found'; end if;
|
|
select c.* into v_case from public.birth_time_rectification_cases c
|
|
where c.id = p_case_id and c.user_id = p_user_id
|
|
and c.journey_protocol = 'dynamic-choice-v2' for update;
|
|
if not found then raise exception 'birth_time_dynamic_case_not_found'; end if;
|
|
if v_job.evidence_fingerprint is distinct from p_evidence_fingerprint then
|
|
raise exception 'birth_time_dynamic_scoring_fingerprint_mismatch';
|
|
end if;
|
|
if v_job.algorithm_version is distinct from p_algorithm_version then
|
|
raise exception 'birth_time_dynamic_scoring_algorithm_mismatch';
|
|
end if;
|
|
if v_job.status = 'completed' then
|
|
if v_job.result is distinct from p_candidate_result
|
|
or v_case.turn_version is distinct from p_expected_version + 1 then
|
|
raise exception 'stale_birth_time_dynamic_scoring_job';
|
|
end if;
|
|
return v_case.turn_version;
|
|
end if;
|
|
if v_job.status is distinct from 'processing'
|
|
or v_case.turn_version is distinct from p_expected_version
|
|
or v_case.turn_state #>> '{nextAction,jobId}' is distinct from p_job_id::text
|
|
or coalesce(v_case.turn_state #>> '{nextAction,kind}', '') not in ('score_pending', 'retry_scoring')
|
|
or p_candidate_result ->> 'algorithmVersion' is distinct from p_algorithm_version
|
|
or p_public_turn_state ->> 'journeyProtocol' is distinct from 'dynamic-choice-v2'
|
|
or (p_public_turn_state ->> 'turnVersion')::bigint is distinct from p_expected_version + 1
|
|
or jsonb_path_exists(p_public_turn_state, '$.**.partitionId')
|
|
or jsonb_path_exists(p_public_turn_state, '$.**.candidateScores')
|
|
or jsonb_path_exists(p_public_turn_state, '$.**.agentContext')
|
|
or jsonb_typeof(p_private_state) is distinct from 'object' then
|
|
raise exception 'stale_birth_time_dynamic_scoring_job';
|
|
end if;
|
|
update public.birth_time_rectification_scoring_jobs
|
|
set status = 'completed', result = p_candidate_result, failure_code = null,
|
|
completed_at = now(), updated_at = now()
|
|
where id = p_job_id and status = 'processing';
|
|
update public.birth_time_rectification_cases
|
|
set status = case p_snapshot ->> 'state'
|
|
when 'ready' then 'confirmed' when 'confirming' then 'confirming'
|
|
when 'candidate' then 'candidate' else 'rectifying' end,
|
|
journey_snapshot = p_snapshot, candidate_result = p_candidate_result,
|
|
event_scoring_version = p_algorithm_version,
|
|
candidate_result_id = (p_candidate_result ->> 'resultId')::uuid,
|
|
candidate_start = (p_candidate_result #>> '{winningSegment,startTime}')::time,
|
|
candidate_end = (p_candidate_result #>> '{winningSegment,endTime}')::time,
|
|
turn_version = p_expected_version + 1, turn_state = p_public_turn_state,
|
|
evidence_draft = null, updated_at = now()
|
|
where id = p_case_id and user_id = p_user_id and turn_version = p_expected_version;
|
|
if not found then raise exception 'stale_birth_time_dynamic_scoring_job'; end if;
|
|
perform public.persist_birth_time_dynamic_private_state(p_case_id, p_user_id, p_private_state);
|
|
return p_expected_version + 1;
|
|
end;
|
|
$$;
|
|
|
|
create or replace function public.fail_birth_time_dynamic_scoring_job(
|
|
p_user_id uuid, p_case_id uuid, p_job_id uuid, p_expected_version bigint,
|
|
p_evidence_fingerprint text, p_algorithm_version text, p_failure_code text,
|
|
p_public_turn_state jsonb, p_private_state jsonb
|
|
)
|
|
returns bigint language plpgsql security definer set search_path = '' as $$
|
|
declare
|
|
v_case public.birth_time_rectification_cases%rowtype;
|
|
v_job public.birth_time_rectification_scoring_jobs%rowtype;
|
|
begin
|
|
select j.* into v_job from public.birth_time_rectification_scoring_jobs j
|
|
where j.id = p_job_id and j.case_id = p_case_id and j.user_id = p_user_id for update;
|
|
if not found then raise exception 'birth_time_dynamic_scoring_job_not_found'; end if;
|
|
select c.* into v_case from public.birth_time_rectification_cases c
|
|
where c.id = p_case_id and c.user_id = p_user_id
|
|
and c.journey_protocol = 'dynamic-choice-v2' for update;
|
|
if not found then raise exception 'birth_time_dynamic_case_not_found'; end if;
|
|
if v_job.evidence_fingerprint is distinct from p_evidence_fingerprint then
|
|
raise exception 'birth_time_dynamic_scoring_fingerprint_mismatch';
|
|
end if;
|
|
if v_job.algorithm_version is distinct from p_algorithm_version then
|
|
raise exception 'birth_time_dynamic_scoring_algorithm_mismatch';
|
|
end if;
|
|
if v_job.status = 'failed' then
|
|
if v_job.failure_code is distinct from p_failure_code
|
|
or v_case.turn_version is distinct from p_expected_version + 1 then
|
|
raise exception 'stale_birth_time_dynamic_scoring_job';
|
|
end if;
|
|
return v_case.turn_version;
|
|
end if;
|
|
if v_job.status is distinct from 'processing'
|
|
or v_case.turn_version is distinct from p_expected_version
|
|
or v_case.turn_state #>> '{nextAction,jobId}' is distinct from p_job_id::text
|
|
or coalesce(v_case.turn_state #>> '{nextAction,kind}', '') not in ('score_pending', 'retry_scoring')
|
|
or p_public_turn_state #>> '{nextAction,kind}' is distinct from 'retry_scoring'
|
|
or p_public_turn_state #>> '{nextAction,jobId}' is distinct from p_job_id::text
|
|
or p_public_turn_state ->> 'journeyProtocol' is distinct from 'dynamic-choice-v2'
|
|
or (p_public_turn_state ->> 'turnVersion')::bigint is distinct from p_expected_version + 1
|
|
or jsonb_path_exists(p_public_turn_state, '$.**.partitionId')
|
|
or jsonb_path_exists(p_public_turn_state, '$.**.candidateScores')
|
|
or jsonb_path_exists(p_public_turn_state, '$.**.agentContext')
|
|
or jsonb_typeof(p_private_state) is distinct from 'object' then
|
|
raise exception 'stale_birth_time_dynamic_scoring_job';
|
|
end if;
|
|
update public.birth_time_rectification_scoring_jobs
|
|
set status = 'failed', failure_code = p_failure_code, updated_at = now()
|
|
where id = p_job_id and status = 'processing';
|
|
update public.birth_time_rectification_cases
|
|
set turn_version = p_expected_version + 1, turn_state = p_public_turn_state,
|
|
evidence_draft = null, updated_at = now()
|
|
where id = p_case_id and user_id = p_user_id and turn_version = p_expected_version;
|
|
if not found then raise exception 'stale_birth_time_dynamic_scoring_job'; end if;
|
|
perform public.persist_birth_time_dynamic_private_state(p_case_id, p_user_id, p_private_state);
|
|
return p_expected_version + 1;
|
|
end;
|
|
$$;
|
|
|
|
revoke all on function public.upgrade_birth_time_legacy_case(uuid, uuid, bigint, jsonb, jsonb) from public, anon, authenticated;
|
|
revoke all on function public.complete_birth_time_dynamic_scoring_job(uuid, uuid, uuid, bigint, text, text, jsonb, jsonb, jsonb, jsonb) from public, anon, authenticated;
|
|
revoke all on function public.fail_birth_time_dynamic_scoring_job(uuid, uuid, uuid, bigint, text, text, text, jsonb, jsonb) from public, anon, authenticated;
|
|
grant execute on function public.upgrade_birth_time_legacy_case(uuid, uuid, bigint, jsonb, jsonb) to service_role;
|
|
grant execute on function public.complete_birth_time_dynamic_scoring_job(uuid, uuid, uuid, bigint, text, text, jsonb, jsonb, jsonb, jsonb) to service_role;
|
|
grant execute on function public.fail_birth_time_dynamic_scoring_job(uuid, uuid, uuid, bigint, text, text, text, jsonb, jsonb) to service_role;
|