会话日志在回合中断后因已提交 seq 回退而整条不可加载 #5103
|
中断-恢复后,turn/end 先提交了 seq,同一回合的流式输出仍按旧 seq 继续写入,读取器 fail-closed 拒载——一次错误的中间关闭帧让整条会话历史不可用。 复现、预期与验收
|
Replies: 6 comments
|
你的判断对:这是 写入竞态,不是文件偶然损坏。
已经坏掉的日志(你这条路径是对的)
最多损失当前被打断的那一回合;整条会话不该陪葬。你删帧后 681858 条连续,说明后面数据是好的。 产品上 只修读取器(把「已 DSH 0.1.1-rc.2 + web、长会话 + 重启/断连/压缩,足以作为复现条件。 |
|
这个问题本质上是“持久化游标”和“实时 chunk”混用了同一个序列空间。一个可行的契约是:
SandBase Harness 的事件设计采用 append-only durable event log,并将实时消息 chunk 与持久化 replay cursor 分开;其架构文档明确说明 transient live chunks 不推进 replay cursor,crash recovery 还会为 orphaned tool call 注入 placeholder result。事件序列设计、恢复测试。 这不是对当前 DSH 读取器的替代实现;建议把“中断后最多损失当前 turn”作为验收,而不是让整条历史 fail-closed。 |
|
从源码侧把「写入竞态」再钉一层:这个形态比「turn/end 与流式串行化」更具体,而且直接改变修复方向。 写入端:同一实例不可能产生 seq 回退
结论:单实例内 turn/end 与流式 chunk 的写出顺序天然串行,验收条件 1(「写入/终止串行化」)在单实例里已经成立,所以它修不掉这个 bug。 回退必然来自第二个「陈旧」写入者 用你贴的序列对一遍:读取报 候选入口:prepared session cache( 读取端:fail-closed 的精确触发条件
归类:与 #4274(同进程双实例游标分歧)同一机制类——本次是「陈旧第二 writer 与写后批窗竞态」的新实例,表现形态从重复 seq 变为已提交 seq 回退。 |
|
?"seq ????????????"?????????(?? dsh-permission-rules ????,???????): # ???????,???/??(frame-preserving zstd ??)
node node_modules/dsh-permission-rules/scripts/repair-session-logs.mjs scan <????>
node node_modules/dsh-permission-rules/scripts/repair-session-logs.mjs repair <????>
# 0.1.2-alpha ?????????????:
node node_modules/dsh-permission-rules/scripts/repair-session-logs.mjs strip <????>????: |
|
PerryLink 的修复脚本我拉下来核对了(dsh-permission-rules@0.6.1 的 需要澄清的一点:它不修本线程的 seq 回退形态。0.6.1 发布版里没有 不过你的 frame-preserving 重写机制( |
|
这是同一家族:已提交
dsh plugin --profile web add "github:xiaoshenming/dsh-session-surgeon#main"根因仍是第二个陈旧写者(desktop/web 双开,或 resume 时 write-behind 还没 drain)。修文件挡不住下一次双写。 |
PerryLink 的修复脚本我拉下来核对了(dsh-permission-rules@0.6.1 的
scripts/repair-session-logs.mjs, 332 行, frame-preserving zstd 逐帧重写 + 备份):这个工具修的是未知事件类型这一族(#4811/#5059 线——permissionRules/decision、autoReview/*等 out-of-repo 审计行在ignorable标记出现前被无标记追加, 新 build 读取端SessionFormatUnsupportedError拒载; 修复 = 给目标行加ignorable: true, 其余字节不动, 逐帧解压→过滤→重压, 帧边界存活)。scan/repair 的实现与读取端拒绝链对得上(KNOWN_SESSION_EVENT_TYPES+ envelope 的 ignorable 判别)。需要澄清的一点:它不修本线程的 seq 回退形态。0.6.1 发布版里没有
strip命令, 也没有任何 seq/truncate/rollback 逻辑。本线程的损坏是「已提交turn/end之后出现更小 seq 的assistant/chunk」(中间帧回退, committed-region gap)——不涉及未知类型行, 加ignorable: true救不了它, 因为读取端按event.seq !== events.length判 corrupt(format.ts:386-417), 与行是否 ignorable 无关。这是…