Files
Agent-System/deploy/postgres/goose/00027_2026-09-13-chat-message-scope-backfill.sql
weichenandCursor 1abafa3176 fix(chat): add message scope columns and write-path resolution
Persist workflow_instance_id, stage_instance_id, scope_kind on chat
messages and task runs; resolve scope from live instance for chat and
document tasks so refresh can apply consistent stage authorization.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-13 03:06:08 +00:00

80 lines
3.0 KiB
SQL

-- +goose Up
-- 受控回填历史消息作用域(零正文删除)
-- 1. 任务消息:通过 task_runs 唯一匹配回填 workflow_stage
UPDATE chat_messages cm
SET
scope_kind = 'workflow_stage',
workflow_instance_id = tr.workflow_instance_id,
stage_instance_id = tr.stage_instance_id,
stage_key = tr.workflow_stage_key,
metadata = cm.metadata || jsonb_build_object(
'scope_kind', 'workflow_stage',
'workflow_instance_id', tr.workflow_instance_id,
'stage_instance_id', tr.stage_instance_id,
'stage_key', tr.workflow_stage_key
)
FROM task_runs tr
WHERE cm.scope_kind = 'legacy_unscoped'
AND cm.deleted_at IS NULL
AND cm.metadata->>'task_key' IS NOT NULL
AND cm.metadata->>'task_key' = tr.task_key
AND cm.session_id = tr.session_id
AND tr.workflow_instance_id IS NOT NULL
AND tr.stage_instance_id IS NOT NULL
AND tr.workflow_stage_key IS NOT NULL;
-- 2. 激活前 owner 私聊:项目有 live 实例且消息创建于激活之前
UPDATE chat_messages cm
SET
scope_kind = 'pre_activation',
workflow_instance_id = pwi.id,
metadata = cm.metadata || jsonb_build_object(
'scope_kind', 'pre_activation',
'workflow_instance_id', pwi.id
)
FROM chat_sessions cs
JOIN projects p ON p.id = cs.project_id
JOIN project_workflow_instances pwi ON pwi.project_id = p.id AND pwi.status = 'active'
WHERE cm.session_id = cs.session_id
AND cm.scope_kind = 'legacy_unscoped'
AND cm.deleted_at IS NULL
AND cm.metadata->>'task_key' IS NULL
AND pwi.activated_at IS NOT NULL
AND cm.created_at < pwi.activated_at
AND cs.user_id IS NOT NULL
AND cm.user_id = cs.user_id;
-- 3. 已有 metadata.stage_key 但缺 scope_kind 的普通聊天(live 实例存在)
UPDATE chat_messages
SET
scope_kind = 'workflow_stage',
stage_key = chat_messages.metadata->>'stage_key',
workflow_instance_id = src.workflow_instance_id,
stage_instance_id = src.stage_instance_id,
metadata = chat_messages.metadata || jsonb_build_object(
'scope_kind', 'workflow_stage',
'workflow_instance_id', src.workflow_instance_id,
'stage_instance_id', src.stage_instance_id
)
FROM (
SELECT cm.id AS message_id, pwi.id AS workflow_instance_id, psi.id AS stage_instance_id
FROM chat_messages cm
INNER JOIN chat_sessions cs ON cm.session_id = cs.session_id
INNER JOIN project_workflow_instances pwi ON pwi.project_id = cs.project_id AND pwi.status = 'active'
INNER JOIN project_stage_instances psi ON psi.workflow_instance_id = pwi.id
AND psi.stage_key = cm.metadata->>'stage_key'
WHERE cm.scope_kind = 'legacy_unscoped'
AND cm.deleted_at IS NULL
AND cm.metadata->>'stage_key' IS NOT NULL
AND cm.metadata->>'stage_key' <> ''
AND cm.metadata->>'task_key' IS NULL
) AS src
WHERE chat_messages.id = src.message_id;
-- +goose Down
-- 回填不可逆;Down 仅重置为 legacy_unscoped(不含正文删除)
UPDATE chat_messages
SET scope_kind = 'legacy_unscoped'
WHERE scope_kind IN ('workflow_stage', 'pre_activation');