You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[dsh-compaction] A compaction/prune span stored by 0.1.1-rc.2 is unaddressable under 0.1.5 — the v0 migration refuses the whole session
#6514
A session log written by 0.1.1-rc.2 contains 17 compaction/prune entries whose declared span does not resolve on the surface model that 0.1.5 validates against. The migration refuses the whole session at the first such entry:
The point of this report is not "a log has bad data". It is that the meaning of a stored prune span is not versioned: a span is a pair of coordinates that is only interpretable relative to some surface model, and nothing on disk records which one. When the surface model changes, previously-stored spans become unaddressable, and the failure mode is "the entire session will not open" rather than "this one log-only entry is ignored".
What the 17 entries look like
0 of 17 have shadowedRange.start on the surface that the invariant is checked against. All 17 land inside a packed assistant/chunk run.
v1 → v2 folds chunk runs, so chunk coordinates are not addressable in the v2/v3 coordinate space — there is no mapping entry that produces them.
Each of the 17 has no paired surfaceOp: replacetool/result. The 7 compliant compaction/prune entries in the same log all have one.
Recomputing the official per-message price (dsh-token-meter, ceil(len/4)+4-class estimator) reproduces the stored shadowedTokenCount for the compliant entries in 7/7 cases; for the 17 entries, the stored value matches no node in the log (0/17).
Together these say the span was not written against the same surface model that 0.1.5 checks. We could not find any derivable repair: the coordinates are not a spelling of a current node, the price is not a price of any current node, and there is no replacement to resolve against. Guessing a span would be inventing history, so none was synthesised — these entries are simply outside what can be reconstructed from the artifact.
The part that seems worth fixing
We cannot tell from the artifact whether the span was legal when it was written and became unaddressable later, or was already illegal at write time. That is exactly the problem:
A stored span carries no version of the surface model it was computed against. Two builds can read the same bytes and disagree about whether the entry is well-formed.
ToolResultPruner only ever prunes tool/result nodes that are on the surface at that moment (dsh-compaction-tool-result-pruner/lib/index.js:137-169). So a span pointing into a chunk run should not be producible by the current write path — which makes it ambiguous whether this is (a) an old write path that skipped the check, or (b) a surface model that changed underneath data that was legal when written.
The failure is hard, not soft. An unsatisfiable log-only entry takes down the entire session. Prunes are not part of the visible conversation; users get "your session is gone" for data that was never shown to them.
Suggested direction (any one would help)
Validate at write time — reject a span that does not resolve against the current surface when the prune is appended, so illegal data never reaches disk.
Make the span self-describing — record the surface model / a generation marker alongside the span, so a later reader can migrate it instead of rejecting it.
Fail soft on log-only entries — if a prune's span is unsatisfiable but the entry is not on the surface and is not referenced by anything, skip it with a warning rather than refusing the whole session. (We understand this trades strictness for availability; it may be acceptable for entries that can never be shown.)
What we did not claim
We did not claim a specific write path produced this; we only established that the stored span does not resolve under the checked model, and that no mapping to the current space exists.
We are not asking for the 17 entries to be "fixed" — we are asking that the ambiguity be removed so that the next occurrence is decidable.
Our ask is about the gate itself, not about our data — how one chooses to handle unsatisfiable log-only entries is the reader's call.
Authorship note: measured and documented by me against my own session store; root-cause tracing and drafting assisted by AI; verification and publication by me. I have no engineering background — if any technical claim reads wrong, please call it out; I will re-verify against the toolchain and correct.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Environment / 环境
@deepseek-ai/dsh(DeepSeek Harness)0.1.5-rc.1/0.1.5-rc.2(migration packages); source log written by0.1.1-rc.2v0 → v1 → v2 → v3chain0.1.1-rc.2, 20,179,981 B / 64,085 lines, unmodified (read-only)dsh-compaction/lib/invariant.js(validateShadowedSeqs) ·dsh-session-format-v0-to-v1/lib/index.js:2576·dsh-compaction-tool-result-pruner/lib/index.js:137-169Summary
A session log written by
0.1.1-rc.2contains 17compaction/pruneentries whose declared span does not resolve on the surface model that0.1.5validates against. The migration refuses the whole session at the first such entry:The point of this report is not "a log has bad data". It is that the meaning of a stored prune span is not versioned: a span is a pair of coordinates that is only interpretable relative to some surface model, and nothing on disk records which one. When the surface model changes, previously-stored spans become unaddressable, and the failure mode is "the entire session will not open" rather than "this one log-only entry is ignored".
What the 17 entries look like
shadowedRange.starton the surface that the invariant is checked against. All 17 land inside a packedassistant/chunkrun.v1 → v2folds chunk runs, so chunk coordinates are not addressable in the v2/v3 coordinate space — there is no mapping entry that produces them.surfaceOp: replacetool/result. The 7 compliantcompaction/pruneentries in the same log all have one.dsh-token-meter,ceil(len/4)+4-class estimator) reproduces the storedshadowedTokenCountfor the compliant entries in 7/7 cases; for the 17 entries, the stored value matches no node in the log (0/17).Together these say the span was not written against the same surface model that
0.1.5checks. We could not find any derivable repair: the coordinates are not a spelling of a current node, the price is not a price of any current node, and there is no replacement to resolve against. Guessing a span would be inventing history, so none was synthesised — these entries are simply outside what can be reconstructed from the artifact.The part that seems worth fixing
We cannot tell from the artifact whether the span was legal when it was written and became unaddressable later, or was already illegal at write time. That is exactly the problem:
ToolResultPruneronly ever prunestool/resultnodes that are on the surface at that moment (dsh-compaction-tool-result-pruner/lib/index.js:137-169). So a span pointing into a chunk run should not be producible by the current write path — which makes it ambiguous whether this is (a) an old write path that skipped the check, or (b) a surface model that changed underneath data that was legal when written.Suggested direction (any one would help)
What we did not claim
Reported by the OfferKuai Team — Founder: Zhaofeng (Yaming). Website: https://www.offerkuai.com/ | Contact: contact@offerkuai.com
Authorship note: measured and documented by me against my own session store; root-cause tracing and drafting assisted by AI; verification and publication by me. I have no engineering background — if any technical claim reads wrong, please call it out; I will re-verify against the toolchain and correct.
中文版
环境
@deepseek-ai/dsh(DeepSeek Harness)0.1.5-rc.1/0.1.5-rc.2;被迁移的源日志由0.1.1-rc.2写入v0 → v1 → v2 → v3链迁移0.1.1-rc.2写入,20,179,981 字节 / 64,085 行,未改动(只读)dsh-compaction/lib/invariant.js(validateShadowedSeqs)·dsh-session-format-v0-to-v1/lib/index.js:2576·dsh-compaction-tool-result-pruner/lib/index.js:137-169摘要
一份由
0.1.1-rc.2写入的会话日志里,有 17 条compaction/prune的声明区间在0.1.5校验所用的 surface 模型上不成立。迁移在第一条处就拒收整条会话:这份报告想说的不是"某份日志里有坏数据",而是:一个被存在磁盘上的 prune 区间,其含义是没有版本标记的。区间是一对坐标,只有相对于某个 surface 模型才可解释,而磁盘上没有任何东西记录它是按哪一个算出来的。当 surface 模型变了,先前存下的区间就变得不可寻址,而失败方式是"整条会话打不开",而不是"这一条纯日志条目被忽略"。
这 17 条长什么样
shadowedRange.start落在校验所用的 surface 上;17 条全部落在一段被打包的assistant/chunk运行内部。v1 → v2会把 chunk 运行折叠掉,所以 chunk 坐标在 v2/v3 坐标空间里不可寻址——不存在能产生它们的映射项。surfaceOp: replace的tool/result;而同一份日志里 7 条合规的compaction/prune都有。dsh-token-meter,ceil(len/4)+4一类)后:合规条目的shadowedTokenCount能被复算出来 7/7;而这 17 条存下的值,在整份日志的任何节点上都对不上(0/17)。三条合起来说明:这些区间不是按
0.1.5校验所用的那个 surface 模型写下的。我们找不到任何可推导的修复——坐标不是某个当前节点的另一种拼法,价也不是任何当前节点的价,而且没有配对的替换可供解析。猜一个区间等于伪造历史,所以那 17 条我们按"无法从产物重建"处理,没有去合成。我们认为值得修的部分
从这份产物上,我们无法判断该区间是"写入时合法、后来变得不可寻址",还是"写入时就已经非法"。而这正是问题所在:
ToolResultPruner只会裁剪当刻在 surface 上的tool/result节点(dsh-compaction-tool-result-pruner/lib/index.js:137-169)。所以指向 chunk 运行的区间不该由当前写路径产生——这让"这是旧写路径漏了检查"还是"下面那层 surface 模型变了"变得无法区分。建议方向(任一条都有帮助)
我们没有主张的
本报告由 OfferKuai(Offer快)团队提交 —— 创始人:Zhaofeng(Yaming)。官网:https://www.offerkuai.com/ | 联系:contact@offerkuai.com
署名说明:本文由我对自己的会话库实测并整理;根因追溯与成稿有 AI 协助;核验与发布由我完成。我并非工程背景——若任何技术表述有误,请直接指出,我会对照工具链复核并更正。
All reactions