-- BUG-699 / BUG-704 的一次性数据修补,搬成迁移,好让产品直接用现成的 -- `Migrate Staging Database` 按钮跑,不必 SSH、不必拿库口令。 -- -- 两段 SQL 逐字来自 frontend/scripts/repair-rectification-session-titles.mjs -- (该脚本自此降级为只读核对工具): -- 1. 标题:把 `M月D日 · 生时校正` 里与 created_at 对不上的日期按 -- Asia/Shanghai 的月日修回;取不到 created_at 就退回不带日期的 -- 「生时校正」,不猜日期。不匹配该正则的手改标题一律不动。 -- 2. 活跃时间:把历史冻结的 chat_sessions.updated_at 按最后一条 turn / -- last_activity_at 回填,`updated_at <` 是单调守卫,只前进不回拨。 -- -- 幂等:两段 where 在改完之后都不再匹配被改过的行——标题改完月日即与 -- created_at 相等(created_at is null 的改成「生时校正」,连正则都不再匹配), -- updated_at 回填后不再小于目标值。重复应用影响 0 行。 -- -- 生产(停在 7b620c7a,没有 use-rectification-surface.ts,标题固定为 -- 「生时校正」且不写库)上不存在被改坏的标题,两段 where 自然匹配 0 行, -- 是预期内的 no-op,不是失败。 -- -- 行数由 RAISE NOTICE 打出,产品在迁移日志里能直接看到修了多少行。 begin; do $migration$ begin if current_user <> 'schema_owner' then raise exception 'rectification_session_title_repair_requires_schema_owner' using errcode = '42501'; end if; end $migration$; do $repair$ declare repaired_titles integer; refreshed_activity integer; begin update public.chat_sessions set title = case when created_at is null then '生时校正' else to_char(created_at at time zone 'Asia/Shanghai', 'FMMM') || '月' || to_char(created_at at time zone 'Asia/Shanghai', 'FMDD') || '日 · 生时校正' end where session_type = 'birth_time_rectification' and title ~ '^[0-9]{1,2}月[0-9]{1,2}日[[:space:]]*·[[:space:]]*生时校正([[:space:]]+[0-9]{2}:[0-9]{2})?$' and ( created_at is null or (substring(title from '^([0-9]{1,2})月'))::int is distinct from extract(month from created_at at time zone 'Asia/Shanghai')::int or (substring(title from '月([0-9]{1,2})日'))::int is distinct from extract(day from created_at at time zone 'Asia/Shanghai')::int ) ; get diagnostics repaired_titles = row_count; update public.chat_sessions as session set updated_at = coalesce(turns.last_turn_at, case_row.last_activity_at) from public.agentic_rectification_cases as case_row left join lateral ( select max(turn.created_at) as last_turn_at from public.agentic_rectification_turns as turn where turn.case_id = case_row.id ) as turns on true where case_row.session_id = session.id and case_row.user_id = session.user_id and session.session_type = 'birth_time_rectification' and session.updated_at < coalesce(turns.last_turn_at, case_row.last_activity_at) ; get diagnostics refreshed_activity = row_count; raise notice 'rectification_session_title_repair repaired_titles=%', repaired_titles; raise notice 'rectification_session_title_repair refreshed_activity=%', refreshed_activity; end $repair$; commit;