现象
手机端离线(退后台、断网、切端)期间,桌面侧删除了消息(/clear 清理某时刻之前的历史、rewind 回撤、单行删除),删除 push 收不到。重连后即使拉了最新页对账,窗口里早于本页最旧行的那些已删除消息仍会留在界面上,直到整窗替换(options.replaceMessages)或会话被回收。
复现(单测形态,实测输出)
窗口 = t10, t20, t30(一页权威页拉回,覆盖区间 = [t10, t30])
手机离线 → 桌面删掉 t10(删除 push 收不到)
重连最新页(满页,moreBeyondWindow: true)= t20, t30
实际: t10, t20, t30 ← t10 已被服务端删除,仍在窗口里
预期: t20, t30
同一形状在 origin/main(#1210 之前)实测同样复现,所以这是既有缺口,不是 #1210 引入的回归。#1210 只是把它的触发条件从「缓存旧页与最新页有交集就整段保留」收窄到「旧行落在已验证覆盖区间内、且本页与该区间首尾相接」。
根因
setLatestMessageWindow 保留旧段的依据是「这段历史与本页连续」。#1210 加的事实自检能证伪一个方向——最新页在覆盖区间内带来了窗口没有的行 ⇒ 断言为假;但证伪不了反方向:窗口里有服务端已经删掉的行。满页时最新页到不了那些更早的行,页本身不构成证据。
修法方向
需要一条客户端能独立核对的「多行」信号,最现成的是总数对账:session._count.messages 对上窗口里已加载的服务端行数(仓内 hasOlderMessagesAfterReopen 已经在用这个比较,可复用它的过滤口径)。窗口里的服务端行数 > 服务端总数 ⇒ 窗口里有已删除的行 ⇒ 作废覆盖区间、丢弃早于本页的旧段(甚至整窗重来)。
落地前要先核实的坑:
_count.messages 与「窗口里被算作服务端行」的口径是否严格一致(本地系统卡、临时流式行、tool 行的取舍);
- 远程(SSH)会话与旧版被控端是否稳定给 count;不给时必须退化为「不对账」,不能当成 0;
- 误判方向是清空用户正在看的历史,比现状(多显示几条已撤回的消息)更糟,所以需要偏保守的判据与专门的回归测试。
影响
用户可见但范围有限:只影响「离线期间桌面删过消息」+「重连时最新页是满页」这一组合,且被删的行必须早于本页最旧行。下一次整窗替换或重新打开会话(触发 replaceMessages 的路径)即恢复。
发现于 #1210 的 review(codex 的 thread,它给出的例子形状不复现——isOlderLoadedPage 还要求「旧行早于本页最旧行」——但指出的方向有上面这个真变体)。
现象
手机端离线(退后台、断网、切端)期间,桌面侧删除了消息(
/clear清理某时刻之前的历史、rewind 回撤、单行删除),删除 push 收不到。重连后即使拉了最新页对账,窗口里早于本页最旧行的那些已删除消息仍会留在界面上,直到整窗替换(options.replaceMessages)或会话被回收。复现(单测形态,实测输出)
同一形状在
origin/main(#1210 之前)实测同样复现,所以这是既有缺口,不是 #1210 引入的回归。#1210 只是把它的触发条件从「缓存旧页与最新页有交集就整段保留」收窄到「旧行落在已验证覆盖区间内、且本页与该区间首尾相接」。根因
setLatestMessageWindow保留旧段的依据是「这段历史与本页连续」。#1210 加的事实自检能证伪一个方向——最新页在覆盖区间内带来了窗口没有的行 ⇒ 断言为假;但证伪不了反方向:窗口里有服务端已经删掉的行。满页时最新页到不了那些更早的行,页本身不构成证据。修法方向
需要一条客户端能独立核对的「多行」信号,最现成的是总数对账:
session._count.messages对上窗口里已加载的服务端行数(仓内hasOlderMessagesAfterReopen已经在用这个比较,可复用它的过滤口径)。窗口里的服务端行数 > 服务端总数 ⇒ 窗口里有已删除的行 ⇒ 作废覆盖区间、丢弃早于本页的旧段(甚至整窗重来)。落地前要先核实的坑:
_count.messages与「窗口里被算作服务端行」的口径是否严格一致(本地系统卡、临时流式行、tool 行的取舍);影响
用户可见但范围有限:只影响「离线期间桌面删过消息」+「重连时最新页是满页」这一组合,且被删的行必须早于本页最旧行。下一次整窗替换或重新打开会话(触发
replaceMessages的路径)即恢复。发现于 #1210 的 review(codex 的 thread,它给出的例子形状不复现——
isOlderLoadedPage还要求「旧行早于本页最旧行」——但指出的方向有上面这个真变体)。