Files
Jyotisha/frontend/supabase/migrations/20260925010000_rectification_session_title_result.sql
T
jesse-ux a94a1d6748 fix(sessions): keep rectification result titles when a new chat opens
The case insert trigger writes the result time, then the existing open persist sends the minted title back. A before-update guard keeps that result unless the user chose a non-automatic name, and a new session reads the stored title into the sidebar.
2026-09-25 02:04:56 +08:00

151 lines
5.6 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- BUG-1001: rectification titles carry the result, not a date.
-- One formula and one automatic-title predicate. The trigger and the backfill
-- both call them. Do not assign chat_sessions.updated_at (BUG-988 / BUG-704).
-- Open / GET / metadata PATCH still must not retitle (BUG-699): this trigger
-- listens only to accepted_time, confirmed_time, and candidate_range.
begin;
do $migration$
begin
if current_user <> 'schema_owner' then
raise exception 'rectification_session_title_result_requires_schema_owner'
using errcode = '42501';
end if;
end
$migration$;
create or replace function public.rectification_session_title(
p_accepted time,
p_confirmed time,
p_range jsonb
) returns text
language sql
immutable
parallel safe
set search_path = ''
as $$
select case
when p_confirmed is not null then
'生时校正 · ' || to_char(p_confirmed, 'HH24:MI')
when p_accepted is not null then
'生时校正 · ' || to_char(p_accepted, 'HH24:MI')
when public.agentic_rectification_is_clock(p_range ->> 'start_time')
and public.agentic_rectification_is_clock(p_range ->> 'end_time') then
'生时校正 · ' || (p_range ->> 'start_time') || '–' || (p_range ->> 'end_time')
else
'生时校正'
end;
$$;
-- The dash in the range alternative is U+2013 EN DASH, not a hyphen.
-- frontend/src/lib/session-title.ts DATED_ENTRY_TITLE must agree with this
-- predicate. The parity test reads this pattern from this file.
create or replace function public.rectification_session_title_is_automatic(
p_title text
) returns boolean
language sql
immutable
parallel safe
set search_path = ''
as $$
select p_title is not null
and p_title ~ '^(?:(?:生时校正|今日节奏)\s*·\s*[0-9]{1,2}月[0-9]{1,2}日|[0-9]{1,2}月[0-9]{1,2}日\s*·\s*(?:今日节奏|生时校正))(?:\s+[0-9]{2}:[0-9]{2})?$|^生时校正$|^生时校正\s*·\s*[0-9]{2}:[0-9]{2}$|^生时校正\s*·\s*[0-9]{2}:[0-9]{2}–[0-9]{2}:[0-9]{2}$';
$$;
create or replace function public.sync_rectification_session_title_from_case()
returns trigger
language plpgsql
security definer
set search_path = ''
as $$
begin
update public.chat_sessions
set title = public.rectification_session_title(new.accepted_time, new.confirmed_time, new.candidate_range)
where id = new.session_id
and user_id = new.user_id
and session_type = 'birth_time_rectification'
and title is distinct from public.rectification_session_title(new.accepted_time, new.confirmed_time, new.candidate_range)
and public.rectification_session_title_is_automatic(title);
return new;
end;
$$;
revoke all on function public.rectification_session_title(time, time, jsonb)
from public, anon, authenticated;
revoke all on function public.rectification_session_title_is_automatic(text)
from public, anon, authenticated;
revoke all on function public.sync_rectification_session_title_from_case()
from public, anon, authenticated;
grant execute on function public.rectification_session_title(time, time, jsonb)
to schema_owner;
grant execute on function public.rectification_session_title_is_automatic(text)
to schema_owner, authenticated, service_role;
grant execute on function public.sync_rectification_session_title_from_case()
to schema_owner;
drop trigger if exists agentic_rectification_cases_title_from_result
on public.agentic_rectification_cases;
create trigger agentic_rectification_cases_title_from_result
after insert or update of accepted_time, confirmed_time, candidate_range
on public.agentic_rectification_cases
for each row
execute function public.sync_rectification_session_title_from_case();
-- Client PATCH runs as authenticated and would otherwise write the minted
-- title "生时校正" back over the result the insert trigger just stored.
-- This function stays security invoker so current_user is the updating role.
-- The result trigger is security definer, owned by schema_owner, so its
-- update still sees current_user = schema_owner and is allowed.
create or replace function public.keep_rectification_result_title()
returns trigger
language plpgsql
set search_path = ''
as $$
begin
if current_user <> 'schema_owner'
and new.session_type = 'birth_time_rectification'
and public.rectification_session_title_is_automatic(new.title)
and new.title is distinct from old.title then
new.title := old.title;
end if;
return new;
end;
$$;
revoke all on function public.keep_rectification_result_title()
from public, anon, authenticated;
grant execute on function public.keep_rectification_result_title()
to schema_owner;
drop trigger if exists chat_sessions_keep_rectification_result_title
on public.chat_sessions;
create trigger chat_sessions_keep_rectification_result_title
before update of title on public.chat_sessions
for each row
execute function public.keep_rectification_result_title();
do $backfill$
declare
retitled integer;
begin
-- BEGIN rectification_session_title_backfill
update public.chat_sessions as session
set title = public.rectification_session_title(case_row.accepted_time, case_row.confirmed_time, case_row.candidate_range)
from public.agentic_rectification_cases as case_row
where case_row.session_id = session.id
and case_row.user_id = session.user_id
and session.session_type = 'birth_time_rectification'
and session.title is distinct from public.rectification_session_title(case_row.accepted_time, case_row.confirmed_time, case_row.candidate_range)
and public.rectification_session_title_is_automatic(session.title);
-- END rectification_session_title_backfill
get diagnostics retitled = row_count;
raise notice 'rectification_session_title_result retitled=%', retitled;
end
$backfill$;
commit;