Skip to content

侧边对话:模型切换重写 system prompt 后也按最后一次压缩切尾 - #1035

Merged
Menghuan1918 merged 1 commit into
omdsh-dev:devfrom
NolanHo:fix/sidechat-head-replacement-tail
Oct 23, 2026
Merged

Menghuan1918 merged 1 commit into
omdsh-dev:devfrom
NolanHo:fix/sidechat-head-replacement-tail

Conversation

@NolanHo

@NolanHo NolanHo commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

背景

侧边对话(sidechat fork)从父会话最后一次 summarizing compaction 起种,是 v0.28.0 已合入的行为。但真实会话里还有一个常见形状没有覆盖:最后一次 compaction 之后发生模型切换时,宿主会追加一条 system/message,用 surfaceOp: { op: 'replace', startSeq, endSeq } 重写受保护的 system prompt。这条替换事件在日志里位于 checkpoint 之后,但在 surface 上占据 checkpoint 之前的 head 槽;当前构建器把「checkpoint 前出现 post-cut 节点」视为不可证明,直接回退为全量复制。结果:这些父会话的侧边对话仍然复制整份父日志,切尾收益完全丢失。

改了什么

  • headSlotOf:把 head 槽解析为「surface 上的最新替换 → 单节点 replace 链 → 原始 anchor」。链的每一跳都必须是 system/message、单节点、向后引用;anchor 必须早于 cut。
  • 成员判定使用 fold 实际记录的 replacements[].shadowedSeqs,而不是 checkpoint 声明的 [startSeq,endSeq]:v2→v3 的多跳 prompt 链里,中间节点的 seq 可能落在声明区间内,但并未被 checkpoint 移除;用数值区间会误拒这些链。
  • headSkeleton:骨架和 closers 取自 anchor 的 turn/step,发射 effective(最新 prompt),并把 envelope 归一化到 turn 1 / step 1;链上其余节点在 keep/tail/replaceCovered 中消费掉,避免重复发射。
  • 安全边界不变:范围替换、checkpoint 已移除的目标、非 system/message 节点、前向/循环链、缺失 anchor 仍然回退为完整拷贝。

验证

  • 聚焦 spec:20/20;新增 4 个用例(单次切换、二次切换、多跳链且中间节点位于声明区间内、合法范围回退)。旧代码在 trim 用例上失败。
  • tsc --noEmit、eslint .、pnpm run build 通过。
  • 全量测试:220/221 文件通过;唯一失败是本地 git 2.34.1 的既有环境用例(--end-of-options),与本改动无关。
  • 真实会话日志抽查(只读,宿主 fold + Session.create):此前回退的会话现在可切尾,例如 6036→187、8329→2479、5603→2279、3504→1444、7897→3191、8941→4234、6364→2943、5793→2551;全部 surface-equivalent,且 Session.create 接受;此前已能切尾的 35992→3456 不变。带未完成 turn 的 snapshot 路径按前缀等价校验。

兼容性

  • 不新增/修改宿主 API、会话格式或配置项;仍然只依赖 v0.28.0 的 peer 基线(DSH ^0.2.1-rc.1)。
  • 回退路径保持逐字节全量复制,失败模式不变。

A model switch after the last compaction replaces the protected system
prompt with a system/message whose seq sits after the cut but whose
surface slot is the head before the checkpoint. The builder refused that
shape, so every such sidechat copied the parent log in full.

Resolve the single-node replacement chain to its pre-cut anchor using the
checkpoint's recorded shadowed set (not its declared numeric range, which
misclassifies keep-window replacements), carry the latest replacement in
the head slot with the anchor's turn/step scaffolding, and consume the
chain so the keep window and tail never re-emit it. Range replacements,
targets the checkpoint removed, non-system nodes, and broken or forward
chains still fall back to the verbatim copy.

Tests cover a single switch, a two-switch chain, a multi-hop chain whose
intermediate sits inside the declared range but not in the shadowed set,
and a valid range fallback. The trim fixtures fall back on the old code.
Real parent logs now trim (6036->187, 8329->2479, 16458->4359, ...) with
surface equivalence and Session.create acceptance; the previous
35992->3456 trim is unchanged.
@Menghuan1918
Menghuan1918 merged commit f418302 into omdsh-dev:dev Oct 23, 2026
3 checks passed
@NolanHo
NolanHo deleted the fix/sidechat-head-replacement-tail branch October 23, 2026 03:42
davidLi17 added a commit to davidLi17/DSH-better-sidebar that referenced this pull request Oct 23, 2026
Port upstream PR omdsh-dev#1035 (e5f96b8).
Release 0.28.1-lhg.2. Preserve LHG draft handoff and native image attachments, with prebuilt scriptless Git installs.

Verified: 2707 tests pass; typecheck, build, consumer declarations and package checks pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants