Files
happy-life-star/docs/superpowers/specs/2026-06-28-rollback-scriptview-temp-id-protection-design.md
T

3.9 KiB
Raw Blame History

author, created_at, purpose
author created_at purpose
Peanut 2026-06-28 回滚 ScriptView 的临时 conversationId 正则短路保护,修复历史剧本消息卡片不显示的回归

回滚 ScriptView 临时 ID 正则短路保护

背景

commit 19337b9"ScriptView loadMessages 对临时 conversationId 正则短路保护")引入了一个回归 bug: 用户从"历史剧本"列表点进详情再点"继续"进入 ScriptView看不到完整的消息卡片

根因

DB 中历史剧本的 conversation_id 字段值就是 conv-<ts>-<rand> 格式(前端在早期版本自造后写入):

conv-1782552967659-615gen
conv-1782228787632-fkifia
conv-1781497026473-7l8jco
...

这些 conversationId 完全匹配 commit 19337b9 加的正则 ^conv-\d+-[a-z0-9]{6}$。 并且这些 conversation 在 t_conversation 表中大多没有对应记录(current_version_message_id 字段全为 NULL,佐证了当时 conversation 没有完整落库)。

用户打开历史剧本的 ScriptView 时:

  1. 从 store 拿到 scriptconversationId = script.conversationId = conv-1782552967659-615gen
  2. 进入 loadMessages()
  3. 正则匹配 + backedByScript=falsescript 上没有 conversationId 背书?错,有背书但被误判)
  4. 实际上 currentResult.value.conversationIdopenScriptChat 里被赋值为 script.conversationId,但 openScriptChat 是在 ScriptView 页内调用的,详情页 "继续" 按钮走的是 continueCurrentuni.reLaunch({ url: '/pages/main/index?tab=script' })ScriptView 重新初始化时 currentResult.value 还未被赋值
  5. 正则保护触发 → messages.value = []所有消息卡片不显示

修复方案

删除 commit 19337b9mini-program/src/pages/main/ScriptView.vueloadMessages 中添加的正则短路保护代码。恢复为:

const loadMessages = async () => {
  if (!conversationId.value) return
  try {
    const res = await listMessagesByConversation({ conversationId: conversationId.value, includeVersions: false })
    messages.value = res.data || []
    const scriptMessages = messages.value.filter(m => m.type === 'script')
    if (scriptMessages.length > 0) {
      const rootMessage = scriptMessages[0]
      const versionRes = await listMessageVersions(rootMessage.id)
      versions.value = versionRes.data || []
    }
  } catch (error) {
    uni.showToast({ title: error.message || '加载消息失败', icon: 'none' })
  }
}

为什么可以直接回滚

  • commit e3eb1af 已让后端 listByConversation 在 conversation 不存在时返回空列表(不抛 500)
  • 所以前端调 API 时即使传了"不存在"的 conversationId,也只会得到空数据,不会再 500
  • 5xx 噪音问题已由后端修复兜底,前端的正则保护属于过度防御

验证步骤

  1. 修改 mini-program/src/pages/main/ScriptView.vue,删除正则短路保护
  2. 启动 H5python dev-services.py start mini-program(端口 5180
  3. 浏览器访问 http://localhost:5180,登录一个有历史剧本的账号
  4. 进入任一历史剧本的 ScriptView
  5. 验证:
    • 不再看到正则保护导致的"消息全空"
    • Network 面板有 /message/listByConversation 请求
    • 响应状态 200body 为 {"code":200,"data":[]}conversation 不存在)或有数据
    • Console 无报错

风险与回退

  • 回退方案:如果回滚后出现 500 噪音,可以再在前端加判断(但后端已兜底,不应再出现)
  • 影响面:仅影响 ScriptView.vue 的 loadMessages 函数,其他页面不受影响

长期改进(不在本次范围)

历史剧本的 conversation_id 是前端自造的临时 ID,但被当作"真实 conversationId"写入了 t_epic_script.conversation_id。这是数据模型上的不一致:

  • 要么在写入 epic_script 时同步创建 t_conversation 记录
  • 要么 epic_script.conversation_id 字段只存真实落库的 ID
  • 本次不处理,单独跟踪