Files
happy-life-star/docs/superpowers/specs/2026-07-26-detail-clarification-card-count-fix-design.md
T

4.1 KiB
Raw Blame History

author, created_at, purpose
author created_at purpose
AI Assistant 2026-07-26 修复详情页只显示 2 个澄清选项卡(应为 N 个)的后端累积丢失 bug

详情页澄清选项卡显示不全修复设计

问题

生成小说时,生成页显示 N 个澄清选项卡(clarification cards),但进入详情页后只显示前 2 个。必须保证详情页选项卡数量与生成页完全一致。

根因分析

通过数据库查询(t_message 按 conversation_id 分组统计)确认:3 个有 clarification 的 conversation 全部是 clarification_question=2 + clarification_answer=3。即用户回答了 3 次(3 个 answer),但后端只保存了 2 个 question。丢失的是第一个 clarification_cardQ1

DB 中 conversation 339751895901937665 的 messageOrder 分布:

order type content
1 clarification_answer 同事/上司
2 clarification_question 是什么具体事件让你决定不再讨好?
3 clarification_answer 功劳被抢
4 clarification_question 你希望主角如何反击?
5 clarification_answer 暗中布局
6 outline ...

根因链

  1. 上游 SSE 事件结构session_id 字段在事件顶层(与 type 同级),不在 payload 内。前端从顶层取(ScriptView.vue:1800 const { type, session_id, payload } = event)且工作正常。
  2. 后端 status 事件处理ShortNovelServiceImpl.forwardSse 行 312-314 从 payload.getString("session_id") 取,取不到
  3. 首次 stream 的 currentSessionId[0] 初始为 nullforwardSse 行 253 final String[] currentSessionId = {knownSessionId},首次 stream 调用时 knownSessionId=null
  4. 首次 stream 的 Q1 不累积:首次 stream 里第一个 clarification_card 事件到达时 currentSessionId[0] 仍为 null,行 346 的 if (currentSessionId[0] != null) 为 falseQ1 不被 accumulateStage 累积。
  5. followup 流正常followup 调用 forwardSseknownSessionId = request.getSessionId()(前端传的,非 null),后续 Q2/Q3 都正确累积。
  6. drainStages 取到不完整的 stagesHistorynovel_done 时 drainStages 取到 [A1, Q2, A2, Q3, A3, outline](缺 Q1),saveNovelResult 创建 2 question + 3 answer。
  7. 详情页只能渲染 2 个 card:从 DB 读到的 clarification_question 只有 2 条。

修复方案

修改文件server/src/main/java/com/emotion/service/impl/ShortNovelServiceImpl.java

修改点forwardSse 方法的事件循环(行 305 附近),在解析 event 后、status 处理之前,从事件顶层取 session_id 同步 currentSessionId[0](与前端 ScriptView.vue:1805-1806 取 sessionId 的方式对齐)。

新增代码(放在 String type = event.getString("type"); 之后、status 事件 if ("status".equals(type)) 之前):

// 从事件顶层取 session_id 同步 sessionId
// 上游事件结构与前端对齐:session_id 与 type 同级,不在 payload 内
// 修复:首次 stream 里 status 处理从 payload 取不到 session_id,导致 currentSessionId 保持 null
// 第一个 clarification_card 因 sessionId 为 null 不累积,详情页少显示第一个选项卡
String topSessionId = event.getString("session_id");
if (topSessionId != null && !topSessionId.isEmpty()) {
    currentSessionId[0] = topSessionId;
}

影响范围

  • forwardSse 方法新增 5 行代码
  • 零现有逻辑改动(status 处理保留原样作为次选,顶层取 sessionId 优先覆盖)
  • 零数据库变更
  • 零前端改动

预期效果

  • 新剧本:首次 stream 的 Q1 不再丢失,详情页显示全部 N 个选项卡(与生成页完全一致)
  • 老剧本3 个已有 conversation):保持现状,仍显示 2 个 card。DB 中 stagesHistory 缺失的 Q1 已永久丢失,无法真实恢复。

验收标准

  1. 在 H5 手动完成一次新的小说生成(包含至少 2 轮澄清)
  2. 进入该剧本的详情页
  3. 验证选项卡数量与生成页完全一致(生成 N 个,详情显示 N 个)
  4. Console 无新增错误
  5. 本地 mvn clean install 编译通过