Repository navigation
Replies: 3 comments
|
Minimal synthetic reproduction (contents are placeholders; verified with the shipped validator A valid turn is opened and closed, then the idle pruner appends a [{"type":"turn/start","seq":0,"time":1,"data":{"turn":1}},{"type":"step/start","seq":1,"time":1,"data":{"turn":1,"step":1}},{"type":"assistant/message","seq":2,"time":1,"data":{"turn":1,"step":1,"message":{"role":"assistant","source":{"kind":"model","provider":"p","model":"m"},"content":[{"type":"tool-call","id":"c1","name":"t","arguments":"{}"}]}},"surfaceOp":"append"},{"type":"tool/call","seq":3,"time":1,"data":{"turn":1,"step":1,"callId":"c1","name":"t","arguments":"{}"}},{"type":"tool/result","seq":4,"time":1,"data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"c1"},"toolCallId":"c1","content":[{"type":"text","text":"original"}]}},"surfaceOp":"append"},{"type":"step/end","seq":5,"time":1,"data":{"turn":1,"step":1}},{"type":"turn/end","seq":6,"time":1,"data":{"turn":1}},{"type":"compaction/prune","seq":7,"time":1,"data":{"shadowedRange":{"start":4,"end":4},"shadowedSeqs":[4]}},{"type":"tool/result","seq":8,"time":1,"data":{"turn":1,"step":1,"message":{"role":"tool","source":{"kind":"tool","callId":"c1"},"toolCallId":"c1","content":[{"type":"text","text":"pruned"}]}},"surfaceOp":{"op":"replace","startSeq":4,"endSeq":4},"sourceEventSeqs":[4]}]
So the single defining cause is a replacement |
|
你那条 workaround 已经是可判定的修复了,我把它做成了工具里的一等修复,并按你的合成样例在桌面端自带的 0.2.0-rc.2 验证器上跑通了。 先说一个和 0.1.7 不同、容易看走眼的点:这段在两个发布包里不是同一份代码。
为什么我同意这条能修、而 #7824「回合关了还在继续写」不能:replacement 是纯 surface 元数据 —— 我实现的判据(新 health code
实测(都在本机跑过,不是转述):
你提的三条建议我一条没做(那是上游的事):读端放宽、修剪器在回合内提交、产品内建隔离/修复。我们只是在文件这一侧把用户从「只能手改 zstd 日志」里救出来。 一个提醒沿用你的结论:修完如果界面里还显示被裁掉的旧文本,要删掉那条会话的投影缓存 要试的话: |
|
Scope note, checked in the published npm 0.2.0-rc.2 packages ( So with the npm packages, prune replacements land inside a turn and pass the validator. The turn-outer pass in the report must come from code outside those packages, presumably the desktop build named in the environment line. That narrows where the fix belongs: either the reader accepts a turn-less replace (option 1), or that caller opens a turn (option 2). |
Uh oh!
There was an error while loading. Please reload this page.
Environment
0.2.0-rc.2(npmlatest/nextat the time of writing), Windows 11, desktop app (the web UI shows the same error).@deepseek-ai/dsh-sessionSESSION_FORMAT_VERSION = 4).Symptom
Opening a session that had been running normally fails at load:
There is no in-product way to open or repair it afterwards.
Root cause — a writer/reader mismatch in the same release
The tool-result pruner rewrites old tool results in a background/idle pass, i.e. outside any open turn. It appends, after the last
turn/end:compaction/pruneevents (data.shadowedRange/data.shadowedSeqs), andtool/resultevents carrying"surfaceOp": {"op":"replace","startSeq":N,"endSeq":N}.The reader validates exactly this class in
assertReleasedV4Relationships→Relationships.tool():Since the pruner emits these after
turn/end,this.turn === null, so the reader rejects a log its own writer produced.The check runs in
SessionLogScanner.finish()(dsh-session-persistence-jsonl) and is not covered by the recoverable-row path, so the whole session becomes unloadable.This is consistent with the writer:
dsh-compaction-basic's idle/manual path deliberately runs with no open turn —— so a turn-outer prune pass is by design; the reader simply does not allow its output.
Evidence (single machine, 0.2.0-rc.2)
assertReleasedV4Relationshipswith this message, the other 14 pass.turn/end(seq 3426); then 301compaction/prune+ 301 replacementtool/resultevents follow (seq 3427–4028), all withturn === null.{type, seq, time, data}is intact and each replacement references an existing earlier seq — so the log content itself is not damaged, only the relationship state machine rejects it.Impact
Any long session that the pruner rewrites while idle can become permanently unloadable, with no product recovery. Related: #8153 (tool-result pruner), #6236 / #6921 (unreadable sessions), #6274 (
surfaceOpeligibility).Workaround that restored the session
Truncate the log after the last
turn/end(drop the trailingcompaction/prune+ replacementtool/resultrows). This loses no messages or turns — only the pruning metadata; the original (unpruned) tool results remain — and the log then passesassertReleasedV4Relationships. Removing the session's projection cache ($DSH_HOME/storages/session_projcache*) lets the projection rebuild.Suggested fix (any one)
tool/resultas a pure surface op that does not require an open turn, orHappy to provide a redacted excerpt or a minimal synthetic log if that helps.
All reactions