Skip to content

PR-2: 消息窗口正确性 + Reply/Edit 互斥 - #55

Draft
DeliciousBuding wants to merge 1 commit into
masterfrom
pr-2/message-window-fix
Draft

PR-2: 消息窗口正确性 + Reply/Edit 互斥#55
DeliciousBuding wants to merge 1 commit into
masterfrom
pr-2/message-window-fix

Conversation

@DeliciousBuding

Copy link
Copy Markdown
Collaborator

概述

修复 #52 中两个数据正确性 bug:

  1. 消息窗口策略不一致:addMessage 上限 500 从头部截断,prependHistory 上限 1000 从尾部截断(旧 bug 截断方向正确保留但策略不统一),setHistory/addSystemMessage 无上限。满 cap 时滚动恢复卡 5 秒超时。
  2. Reply 状态双源:ChatInput 的 reply 指示器依赖未传入的 prop,useWebSocket.sendMessage 从 Zustand 读取 replyTo——发得出但看不到。

改动

纯函数:mergeMessageWindow(新增)

  • frontend/src/stores/mergeMessageWindow.ts — 统一 prepend/append 窗口策略
  • prepend:从尾部截断(keep newest),HISTORY_CAP=1000
  • append:从头部截断(keep newest),MESSAGE_CAP=500
  • 12 个单元测试:重复 ID 去重、乐观回显替换、cap 方向、revision 单调递增

Store 集成

  • addMessage/prependHistory/setHistory/addSystemMessage 全部改用 mergeMessageWindow
  • 添加 messageWindowRevision 单调计数器
  • prepend 返回 addedCount=0 时触发 tdchat:no-more-history 事件

滚动恢复修复

  • MessageTranscript 滚动恢复依赖 messageWindowRevision + 首消息 ID
  • 不再仅依赖 effectiveMessages.length(满 cap 时长度不变)

Reply/Edit 互斥

  • ChatInput 移除 replyTo prop,统一从 Zustand store 读取
  • ArrowUp 进入编辑模式时自动 setReplyTo(null)
  • ChatLayout 不再传递 replyTo prop

验证

  • 671 测试全部通过(35 文件)
  • tsc --noEmit 0 错误
  • npm run build 成功

范围禁止

不夹带:AuthState、OIDC、UI 重画、CI/CD、Core/Compat 协议清理、Emoji/Webhook/legacy WS 清理。

Tracks #50

- mergeMessageWindow 纯函数:统一 addMessage/prependHistory/setHistory/
  addSystemMessage 窗口策略,MESSAGE_CAP=500(append 从头部截断),
  HISTORY_CAP=1000(prepend 从尾部截断)
- 修复 prependHistory 旧 bug: 截断方向正确保留
- 修复 setHistory/addSystemMessage 无上限问题
- 满 cap 时 prepend 返回 addedCount=0 触发 tdchat:no-more-history 事件
- 滚动恢复依赖 messageWindowRevision(monotonic),不再仅依赖数组长度
- ChatInput 移除 replyTo prop,统一从 Zustand store 读取
- Edit 模式进入时自动取消 reply(setReplyTo(null))
- 12 个纯函数单元测试 + 64 个 store 集成测试 + 43 个 ChatInput 测试
- 全部 671 测试通过,tsc 0 错误,npm run build 成功
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0e787aab-7358-4407-8cd1-7857a5871195

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Collaborator Author

Leader review:当前 BLOCK,核心不变量被写反

本 PR 边界总体正确,且只改了 #52 允许的 7 个前端文件;backend-test、frontend-test、public-preview-smoke 已通过。但目前不能合并,原因不是 lint 一项,而是 mergeMessageWindow 把最关键的数据正确性目标实现反了。

Blocking 1:prepend 超 cap 时仍然删除最新 live tail

#52 的硬约束是:加载旧历史不得删除最新实时消息;prepend 超 cap 后必须保留 newest cap 条。当前实现却在 prepend 后执行 messages.length = cap,会保留最旧 head、删除最新 tail。测试也把错误行为固化成了期望:removes newest messages when cap is exceeded

必须改为统一不变量:无论 incoming 来自 prepend、append、initial history 或 system,最终窗口都保留 newest cap 条。回归例:当前 [a,b,c] + prepend [z], cap=3,结果必须保持 [a,b,c]z 因窗口已饱和而不进入,绝不能删除 c

Blocking 2:optimistic echo 替换不 bump revision

helper 完成 optimistic→server echo 替换后,用 newMessages.length === 0 && messages.length === current.length 判断 no-op。替换前后长度相同,因此返回已变化数组却不递增 revision。请显式跟踪 changed;替换、增添、裁剪任一发生都递增,纯重复/空 incoming 才不变。补测试:echo 替换后 ID 变化且 revision 增长。

Blocking 3:module-global revisionCounter 破坏纯函数

let revisionCounter = 0 是隐藏全局状态,会受测试顺序、HMR、多 store 实例影响。helper 只返回 changed/windowExhausted/addedCount/droppedSide;revision 应由 Zustand store 自增。

Blocking 4:仍有 500/1000 两套 cap

PR body 声称统一策略,但实时与 history 仍使用不同上限。#52 要求统一 addMessage、setHistory、prependHistory、addSystemMessage 的窗口上限,除非给出明确且被测试的 deliberate exception。当前没有。

Blocking 5:CI 失败

run 30792341106 中 backend、frontend、preview 成功,lint 失败。修完逻辑后同时修 eslint,并让 CI 全绿。

必须补的反向证据

  1. 恢复 tail truncation 后,live tail remains present after prepend over cap 必须红;
  2. 移除 echo replacement 的 revision bump 后,对应测试必须红;
  3. 满 cap prepend 长度不变时,store revision 仍变化,MessageTranscript 能结束 loading;
  4. reply/edit 互斥与 ChatInput remount 恢复 reply indicator 测试必须保留。

保持 Draft,只修 #52 范围,不得夹带 Emoji、Webhook、Auth 或 legacy 清理。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant