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
[Bug] 0.2.2-rc.3 desktop: write path persists invalid mid-log system/message appends into headless legacy sessions; corruption is silent until the next cold load (#10619 follow-up)
#13324
Field data for the #10619 / #12065 / #11580 family. Same invariant, but a materially different — and quieter, more damaging — failure mode: in 0.2.2-rc.3 the invalid mid-log system/message append is accepted by the write path and persisted. The session stays fully usable for hours; only the next cold load rejects the log.
What happened (session session-6311cf99…, timestamps Asia/Hong_Kong)
Created 2026-10-13 under a build that did not persist system/message. Raw log opens turn/start(0) → step/start(1) → user/message(2) … — non-empty surface, no protected head. This shape loads fine on 0.2.2-rc.3 (validation only trips when a system/message is present after surface events).
Continued on 2026-11-14 15:07. The write path then persisted four mid-log system nodes into this headless legacy log:
The session ran 23 more turns / ~2,170 events over 7 hours. The last turn ended cleanly (turn/end reason completed, 22:12) — the writer never validated its own output against the fold invariant it enforces at read time. The next cold load fails:
stored session "session-6311cf99-…" is corrupt: stored log is corrupt:
SessionFormatError: system/message requires a protected first surface head
(raw log: …\session.v4.jsonl.zstd)
Contrast with #10619: there the projector's append is rejected during the failing open (loud, immediate, no data committed). Here the open itself succeeds and the corruption is committed by live turns afterwards — deferral makes it strictly worse: the user's whole day of work rides on a log the reader refuses to open. (No #12065-style frame-prefix truncation was observed on 0.2.2-rc.3; the file survived repeated failed loads byte-identical.)
Secondary observation
compaction/summary at seq 2239 recorded 445 in shadowedSeqs — the compaction path happily shadows system nodes on a headless log. On the repaired log 445 is the head, and the entry had to be stripped, or the fold rejects with compaction cannot shadow the protected system head (the #11580 class, which therefore also exists on this build).
Blast radius (one machine, 32 sessions)
Replaying the shipped fold rule offline over every session store:
1 session dead (this one);
9 headless legacy sessions (first surface user/message@2, no system/message persisted, created 2026-10-11 … 2026-10-28) currently load fine and are armed time bombs: seq 2313 shows the appender fires on ordinary new-turn starts, so the first continuation on this build corrupts each of them the same way.
The trigger is not "import" — plain upgrade-and-continue hits it.
Recovery actually performed (data restored, session loads again)
Re: PerryLink's caution in #10619 ("reordering events inside an existing v4 log is not a safe workaround") — correct only without a full remap; with one it is safe and verifiable:
move the first mid-log system/message (222) to head position (right after step/start), rewrite data.turn/step to 1/1;
renumber with k∈[2,221]→k+1, 222→2, k≥223→k and remap every sequence reference: seq, surfaceOp.startSeq/endSeq, sourceEventSeqs, data.sourceEventSeq, data.shadowedSeqs, data.messageSeqs;
drop the resulting head from all shadowedSeqs;
re-encode in the append-container shape (one line per frame), rescan with the shipped scanZstdFrames logic, replay the fold state machine: PASS.
The inert-placeholder repair from #10619 alone does not suffice for logs already corrupted this way — the mid-log appends/replacements must also be retargeted (or the first append lifted to the head as above).
Ask
Write path: before persisting the first system/message to a session with non-empty surface and no head, establish the head (insert-at-head intent) or refuse the append atomically — never commit a mid-log system node to a headless log.
Load path: one-shot lossless migration that inserts the inert placeholder head for headless v4 logs, backing up the original first.
Compaction: exclude system nodes from shadow lists regardless of head state.
中文摘要
桌面版 0.2.2-rc.3:无 system head 的旧会话(首 surface 是 user/message,历史上从未持久化 system/message)在本版本上能正常打开并续聊——但写入路径会把中途的 system/message append/replace 直接持久化进这份 headless 日志(实例:seq 222 append / 445 replace / 2243、2313 append),随后又跑了 23 轮、约 2,170 条事件、7 小时,全部写入成功且无任何告警,直到下一次冷加载才以 SessionFormatError: system/message requires a protected first surface head 拒绝整份日志。与 #10619 的关键差异:rc.2 中 projector 的非法 append 在打开阶段即被拒(当场失败、不落盘);rc.3 中非法序列被写入路径静默提交,损坏延迟爆发,期间用户全部工作成果都压在一份读端拒开的日志上。本构建未复现 #12065 的帧前缀截断(损坏文件在多次加载失败后仍字节不变)。同一文件还复现 #11580 类问题:compaction/summary(seq 2239) 把 system 节点写进了 shadowedSeqs。一台机器 32 个会话扫描:1 个已损坏,9 个同类旧会话被续聊后必然同样损坏(seq 2313 证明新回合开始就会触发 append)。已验证的救回方法:把首条中途 system/message 提升到 head 位(turn/step 改为 1/1),对 seq / surfaceOp.startSeq·endSeq / sourceEventSeqs / shadowedSeqs / messageSeqs 做完整重映射,剔除新 head 的 shadow 引用,按每行一帧重编码——折叠校验通过,会话恢复加载。#10619 的 inert placeholder 单独不足以救已混入中途 system 事件的日志。诉求:写入路径提交前做 head 校验/补位;加载路径对 headless v4 日志做带备份的一次性迁移;compaction 不再 shadow 任何 system 节点。
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.
Component: session log write path (
SystemPromptProjectionpersistence) +session-formatfold validationVersion: DeepSeek Harness Desktop
0.2.2-rc.3(win32 x64;resources/runtime/primary-runtime/runtime.json→desktopVersion)Artifact: one real session,
session.v4.jsonl.zstd, 2,500,258 B / 1,105 zstd frames / 2,374 lines — physically 100% intact (all frames decode, seq contiguous, times monotonic)Field data for the #10619 / #12065 / #11580 family. Same invariant, but a materially different — and quieter, more damaging — failure mode: in 0.2.2-rc.3 the invalid mid-log
system/messageappend is accepted by the write path and persisted. The session stays fully usable for hours; only the next cold load rejects the log.What happened (session
session-6311cf99…, timestamps Asia/Hong_Kong)Created 2026-10-13 under a build that did not persist
system/message. Raw log opensturn/start(0) → step/start(1) → user/message(2) …— non-empty surface, no protected head. This shape loads fine on 0.2.2-rc.3 (validation only trips when asystem/messageis present after surface events).Continued on 2026-11-14 15:07. The write path then persisted four mid-log system nodes into this headless legacy log:
The session ran 23 more turns / ~2,170 events over 7 hours. The last turn ended cleanly (
turn/end reason completed, 22:12) — the writer never validated its own output against the fold invariant it enforces at read time. The next cold load fails:Contrast with #10619: there the projector's append is rejected during the failing open (loud, immediate, no data committed). Here the open itself succeeds and the corruption is committed by live turns afterwards — deferral makes it strictly worse: the user's whole day of work rides on a log the reader refuses to open. (No #12065-style frame-prefix truncation was observed on 0.2.2-rc.3; the file survived repeated failed loads byte-identical.)
Secondary observation
compaction/summaryat seq 2239 recorded445inshadowedSeqs— the compaction path happily shadows system nodes on a headless log. On the repaired log 445 is the head, and the entry had to be stripped, or the fold rejects withcompaction cannot shadow the protected system head(the #11580 class, which therefore also exists on this build).Blast radius (one machine, 32 sessions)
Replaying the shipped fold rule offline over every session store:
user/message@2, nosystem/messagepersisted, created 2026-10-11 … 2026-10-28) currently load fine and are armed time bombs: seq 2313 shows the appender fires on ordinary new-turn starts, so the first continuation on this build corrupts each of them the same way.The trigger is not "import" — plain upgrade-and-continue hits it.
Recovery actually performed (data restored, session loads again)
Re: PerryLink's caution in #10619 ("reordering events inside an existing v4 log is not a safe workaround") — correct only without a full remap; with one it is safe and verifiable:
system/message(222) to head position (right afterstep/start), rewritedata.turn/stepto1/1;k∈[2,221]→k+1, 222→2, k≥223→kand remap every sequence reference:seq,surfaceOp.startSeq/endSeq,sourceEventSeqs,data.sourceEventSeq,data.shadowedSeqs,data.messageSeqs;shadowedSeqs;scanZstdFrameslogic, replay the fold state machine: PASS.The inert-placeholder repair from #10619 alone does not suffice for logs already corrupted this way — the mid-log appends/replacements must also be retargeted (or the first append lifted to the head as above).
Ask
system/messageto a session with non-empty surface and no head, establish the head (insert-at-head intent) or refuse the append atomically — never commit a mid-log system node to a headless log.中文摘要
桌面版 0.2.2-rc.3:无 system head 的旧会话(首 surface 是
user/message,历史上从未持久化system/message)在本版本上能正常打开并续聊——但写入路径会把中途的system/messageappend/replace 直接持久化进这份 headless 日志(实例:seq 222 append / 445 replace / 2243、2313 append),随后又跑了 23 轮、约 2,170 条事件、7 小时,全部写入成功且无任何告警,直到下一次冷加载才以SessionFormatError: system/message requires a protected first surface head拒绝整份日志。与 #10619 的关键差异:rc.2 中 projector 的非法 append 在打开阶段即被拒(当场失败、不落盘);rc.3 中非法序列被写入路径静默提交,损坏延迟爆发,期间用户全部工作成果都压在一份读端拒开的日志上。本构建未复现 #12065 的帧前缀截断(损坏文件在多次加载失败后仍字节不变)。同一文件还复现 #11580 类问题:compaction/summary(seq 2239) 把 system 节点写进了shadowedSeqs。一台机器 32 个会话扫描:1 个已损坏,9 个同类旧会话被续聊后必然同样损坏(seq 2313 证明新回合开始就会触发 append)。已验证的救回方法:把首条中途system/message提升到 head 位(turn/step 改为 1/1),对seq / surfaceOp.startSeq·endSeq / sourceEventSeqs / shadowedSeqs / messageSeqs做完整重映射,剔除新 head 的 shadow 引用,按每行一帧重编码——折叠校验通过,会话恢复加载。#10619 的 inert placeholder 单独不足以救已混入中途 system 事件的日志。诉求:写入路径提交前做 head 校验/补位;加载路径对 headless v4 日志做带备份的一次性迁移;compaction 不再 shadow 任何 system 节点。All reactions