BUG-699 / BUG-704 的数据修补原先只存在于 frontend/scripts/repair-rectification-session-titles.mjs,需要 SCHEMA_DATABASE_URL 才能跑,产品负责人没有任何按钮能执行它,所以那批 错日期的会话标题一直没修。 脚本里本来就是纯 SQL,搬进一次性迁移即可复用现成的 `Migrate Staging Database` 按钮: - 新增 20260916020000_rectification_session_title_repair.sql,两段 update 逐字取自脚本(合同测试比对,改了哪边都会红);权限守卫沿用 20260915010000 的 schema_owner 写法。 - 幂等:改完之后两段 where 都不再匹配同一行,重复应用影响 0 行。 - 各自 get diagnostics + raise notice 打出行数;db-migrate.mjs 加 notice 转发,否则 node-postgres 会把 NOTICE 丢掉,迁移日志里一个数字都看不到。 - 脚本降级为只读核对工具:--apply 改为报错并指向迁移;导入不再连库。 生产停在 7b620c7a(没有 use-rectification-surface.ts,标题固定且不写库), 两段 where 自然匹配 0 行,是预期内的 no-op。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
80 lines
3.2 KiB
PL/PgSQL
80 lines
3.2 KiB
PL/PgSQL
-- 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;
|