Skip to content

[PR] fix(#4438): stop dsh auto-review side requests from corrupting the main session (false rebase wipe + skipped clamp → permanent 400) - #4453

Closed
ranxianglei wants to merge 3 commits into
masterfrom
2026-10-24_4438-dsh-review-lane-isolation
Closed

ranxianglei wants to merge 3 commits into
masterfrom
2026-10-24_4438-dsh-review-lane-isolation

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Closes #4438

查重: 与 #3712/#3722 同属 native-compaction rebase 机制家族,但触发面不同(本单是 aux 请求的车道隔离缺口把 review 请求放进主管道,#3712 是真实 checkpoint 落地后的恢复质量)、后果不同(本单经 usage clobber 跳过 #453 clamp → 会话硬砖;#3712 是压缩能力软退化);#3681(closed)症状不同(review 车道自身超窗)。相关家族:#1916/#2203(persona fork 设计,本 PR 部分取代)、#2156/#2160、#2503(title sidecar 先例)、#388(side passthrough 契约)。

问题(人话版)

DSH 的自动审查扩展在每次执行工具前发一个「审查请求」(固定 REVIEW_POLICY system + 一条拍平的历史快照 user 消息,复用主会话 id)。在 bili 0.1.204 + DSH 0.2.1-rc.2(web profile, openai wire)上,这样一个请求就能把整个会话砖掉:之后每个主请求都带 max_tokens=384000 撞上游 400,永不恢复。三个叠加缺陷,同一失败域(aux 流量与主会话的隔离):

A — 车道隔离缺口(根因)。rebase 资格判定读的是粘性 session.metadata.pluginAgent(prepare-openai.ts 的 resolveLaneDecisions 输入),而所有 persona-fork / side-passthrough 身份门读的是实时 x-bili-plugin header(session-id.ts dshPersonaFingerprintApplies)。一个不带 header 的 auto-review 请求落在已绑定 dsh 的会话上时:所有 fork/passthrough 门全部错过(verbatim 主 key、走完整管道),rebase 门却仍然生效(粘性绑定给出 dsh profile)。

B — checkpoint 框架误报。carriesDshLocalCompactionSummary 原来匹配「新 user 消息任意位置出现 <compacted-summary>」。审查快照在自己的 FILTERED_HISTORY 段里引用了更早一次真实落地的 checkpoint 框架 → guard 把「0/112 covered ids retained + checkpoint framing」当成真实 compaction 落地 → reconcileNativeCompactionBoundary 清空了全部 refs/blocks/fold 状态;模型当时挂起的 compress 调用随之 none-resolved 失败。

C — usage clobber 跳过 #453 clamp。主车道上的审查响应正常结算 usage,把会话的 usage-grade baseline 从 676541 覆盖成 127497;rebase 后又叠加 chars/4 本地估算低估(≥65K),输入估计 ≤ ~633K ⇒ cap ≥ 384K ≥ 请求的 384000 ⇒ clamp no-op ⇒ #3438 把完整 384000 恢复出去 ⇒ 永久 400。算术钉死:同会话 rebase 前 384000 -> 338207 与 est=676541、5% margin 精确吻合——缺掉的那次 clamp 就是致命步骤。

修法(仅 host 侧,不动 kernel/)

  1. 结构性 aux 车道识别(src/server/side-request.ts + handle.ts):新增形状检测器 isDshAutoReviewRequest —— 版本钉死的 REVIEW_POLICY 前缀(已从 DSH 0.2.1-rc.2 lib/index.js:20 确认字面量)+ 无 tools + 恰好一条非 system 消息。接入两条腿、证据不对称:身份腿要求实时 dsh stamp(保证带 stamp 的 review 不再走旧 |sub: fork 路径);车道腿接受实时 stamp 或粘性绑定(接住无 stamp 的扩展流量——即事故形态——同时非 dsh agent 不受影响,allowlist 测试钉住)。命中即走 标题生成等侧请求污染主会话状态:prepareAnthropic 缺 isTitleGen 守卫、快照无条件覆盖、survivedCount 每请求空转 #388 side passthrough:verbatim 转发、kernel 状态不碰、不跑 rebase 检测、不结算 usage(side 响应走 undefined session——relay useRewriter 门,proxy 模式 SSE 出站不 strip 模型 emit 的渲染标签(openai/anthropic wire)— #457 分析发现的同类遗漏 #460/nudge: no-usage recovery leaves stale reference after network or 5xx failure #1595 既有契约)、不污染 nudge。
  2. standalone-checkpoint carrier(src/server/dsh-compaction-guard.ts):guard 现在要求 checkpoint 框架位于 user 消息开头(真实落地 = 一条以 preamble/tag 开头的独立消息)。消息中段引用旧框架不再算数。漂移取舍按文件头 version-pin 教义接受:模板改写降级为 miss(走 archive/detection 路径),绝不做成误报清场。

行为变更披露(Deliverable #4)

带 stamp 的 dsh auto-review 请求:旧行为 = fork 到持久化 |sub:<fp> persona 会话(#1916/#2203 设计);新行为 = 一律 stateless side passthrough(无论是否带 stamp)。原因:每次 review blob 都是新鲜序列化、id 全换 → 持久状态零折叠收益;#3681 证明 review 车道自身会超窗;统一处理不再依赖不可靠的 stamping。主轮行为不变(检测器要求 no-tools + 单消息形状;负例测试钉住「多轮历史引用 policy 文本」仍走完整管道)。

Config surface: 无。kernel-change: 无。

测试

本地定向(绿):tests/issue4438-dsh-review-lane-isolation.test.ts(新增:检测器双向 truth-table、aux-snapshot carrier 双向 pin、e2e 事故复现——无 stamp review 落在粘性绑定的已折叠会话上:无 boundary/conflict、refs+baseline 原样、无 |sub: 铸造、逐字节 verbatim 转发、事后主轮健康且 fold 存活;带 stamp 变体;负例)、tests/issue2432-dsh-local-compaction.test.ts(carrier 双向翻转)、tests/dsh-persona-fingerprint.test.ts(四条 wire 上的契约由 #1916/#2203 fork 改写为 #4438 stateless)、tests/side-lane-invariants.test.ts、title-sidecar/side-lane 套件 —— 93/93 pass;typecheck clean。全量回归看 CI。

残余(代码内已注明):零证据全新会话(无 stamp、无绑定、无折叠块)落到完整管道——在该状态下无害(#2432 门需要 active blocks)。

相邻已知缺口(不并入本 PR,另行跟踪):网关把 400 报文改写成通用错误体时,溢出校准环收不到任何数据(#4093/#4090 均依赖报文里的 stated counts)→ 见 #4452。

… checkpoint-framing quotes from triggering rebases

Incident (v0.1.204, dsh web profile + Cherry Studio gateway): an UNSTAMPED
dsh auto-review request (fixed REVIEW_POLICY system + one freshly-flattened
history blob, no tools) arrived on a session already sticky-bound to dsh by
earlier main turns. Every isolation gate keyed on the LIVE x-bili-plugin
header missed it, so it rode the raw main session key through the full
pipeline: its blob quoted an old compaction checkpoint mid-text, which
false-positived the #2432 native-compaction rebase (0/112 ids retained ->
total refs/blocks/fold-state wipe), and its tiny usage sample clobbered the
usage-grade baseline the #453 output clamp anchors on (676541 -> 127497) —
max_tokens stayed 384000 against real inputs past the window edge, producing
permanent upstream 400s.

- side-request.ts: new isDshAutoReviewRequest() shape detector (fixed
  REVIEW_POLICY system prefix + exactly one user entry + no tools),
  version-pinned like DSH_TITLE_SYSTEM_PREFIX (#2503).
- handle.ts: review shape joins sideRequestLike and rides the #388 stateless
  side passthrough on every wire — no refs/blocks, no rebase detection, no
  usage settle (relay useRewriter gate keeps side responses off the ledger).
  Gate is asymmetric by design: identity side requires the LIVE dsh stamp
  (unstamped reviews already key verbatim there); lane side accepts dsh
  evidence = live stamp OR sticky session binding — the sticky leg is what
  catches the incident's unstamped extension traffic.
- dsh-compaction-guard.ts: carriesDshLocalCompactionSummary now requires the
  standalone-checkpoint shape (message STARTS with the preamble or the open
  tag); framing QUOTED mid-message no longer counts — per the file's
  version-pin doctrine, template drift degrades to a miss, never a false
  positive that wipes a live session.

Behavior change (disclosed): dsh auto-review requests that used to fork onto
persisted |sub:<fp> sessions (#1916/#2203) now ride the stateless passthrough
regardless of stamping. The forked lane had no functional value (each review
re-serializes the whole blob, so ref ids churn and nothing ever folds) and
#3681 showed it overflowing its own window.

Tests: new tests/issue4438-dsh-review-lane-isolation.test.ts (unit both
directions + e2e incident repro: unstamped review on a sticky-bound folded
session leaves refs/boundary/baseline intact and forwards byte-exact);
tests/issue2432-dsh-local-compaction.test.ts carrier pins flipped to the
standalone contract; tests/dsh-persona-fingerprint.test.ts rewritten from the
superseded fork contract to the stateless-passthrough contract on all four
wires; side-lane-invariants allowlist extended with justification.

Fixes #4438
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-10-24_4438-dsh-review-lane-isolation (a552b0c)

Latest build — install this exact version

npm install -g [email protected]

This exact version is immutable and reproducible. The rolling pr tag tracks the newest test build across all PRs.

Recent builds (commit → version)

commit version build
a552b0c [email protected] build
b306aa6 [email protected] build
bfe25bf [email protected] build

Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf billion-context-pr4453.tgz
npm install -g package

Install instructions are refreshed on each push.

@ranxianglei ranxianglei changed the title fix(#4438): stop dsh auto-review side requests from corrupting the main session (false rebase wipe + skipped clamp → permanent 400) [PR] fix(#4438): stop dsh auto-review side requests from corrupting the main session (false rebase wipe + skipped clamp → permanent 400) Oct 23, 2026
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

查重:不重复。 独立扫了 open issue + open PR(约 50 个在途):没有第二个条目触碰 dsh auto-review 的车道隔离。最近的邻居都不重叠——#4409(claude 无头 subagent 分裂,不同客户端、不同机制)、#4452(网关吞掉 400 报文后溢出校准环收不到数据,本 PR 已在正文中声明另行跟踪)。与 PR 正文的家族分析(#3712/#3722/#3681/#1916 族)方向一致,我按 diff 独立复核。

标签:bug / dsh / scope/wiring / p1(aux 流量与主会话的隔离缺口属协议接线层;后果是会话硬砖、永久 400,按 2026-10-19 规则定 p1)。

审核进行中:正在逐段读全量 diff(3 个 src 文件 + 4 个测试文件)、核对管道顺序(rebase 检测 vs side-lane 判定的先后)、跑定向测试;CI test 分片还在跑。结论会按结构化八问单独回复。

…passthrough

tests/dsh-persona-continuity.test.ts still pinned the superseded fork behavior (review request mints a |sub: session) that this PR replaces: the openai-lane e2e now asserts no fork minted, main session requests/refs untouched, 200 verbatim forward. The gated real-dsh twin (e2e-native-dsh-persona scenario B) flips its acceptance from forks>=1 to zero forks for the same reason. Resolver-level unit blocks are unchanged by design: the resolver itself still forks a discontinuous shape — only the wiring keeps auto-review blobs off it.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

CI caught one file my local targeted run missed: tests/dsh-persona-continuity.test.ts (the #2241 continuity lane — a different file from the dsh-persona-fingerprint suite, which had been migrated already). Its openai-lane e2e still pinned the pre-#4438 contract ("review request still forks onto its own session"), so all three test shards failed on that single assertion. Reproduced locally before fixing.

Fixed in b306aa6da (test-only):

  • tests/dsh-persona-continuity.test.ts: the review phase now asserts the post-fix contract — review forwards 200 through the side passthrough, no |sub: session minted, main session's request count and refs byte-for-byte untouched; the file-header contract note updated to match.
  • tests/e2e/e2e-native-dsh-persona.test.ts (gated real-dsh scenario B, skipped in CI but pinning the same superseded contract): acceptance flipped from forks >= 1 to zero forks minted.
  • Resolver-level unit blocks in the continuity file deliberately unchanged: the resolver itself still forks a history-discontinuous shape — this PR only keeps auto-review blobs off it at the wiring layer.

Local evidence at b306aa6da: 97/97 pass across the nine targeted suites (continuity, issue4438, issue2432, persona-fingerprint, side-lane-invariants, side-lane-truth-table, title sidecar/side-lane, side-request-isolation); typecheck clean. Full-suite verdict = the CI lanes on this head.

@ranxianglei ranxianglei added bug Something isn't working dsh p1 scope/wiring labels Oct 23, 2026
Cosmetic follow-up on b306aa6: six header lines carried a stray leading
space, inconsistent with the rest of the file's column-0 // block. No
content change.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

CI verdict on the current head a552b0c4f: fully green — all 9 test shards (ubuntu 22/24 × 3, windows 22 × 3) passed, static gates (ubuntu + windows) passed, every guard job passed; 51 check runs total = 37 success + 14 skipped (gate-skips only), zero failures. The previously failing dsh-persona-continuity test now passes on all shards.

One transparency note on branch history: between my push and the CI run, an additive cosmetic commit a552b0c4f (author ci-check) landed on the branch — it normalizes six header-comment lines in tests/dsh-persona-continuity.test.ts (stray leading space → column-0 //, matching the rest of the file). No content change; the green run above covers it.

Nothing further from my side — the PR is ready for human review/merge whenever.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b)

PR review 结论(独立审 diff,不复用 #4438 侧结论;本地定向验证 + CI 全量)。

审核中发现并已在分支上修复的问题(重要):首推的 head 上 CI 三个 test shard 全红,同一根因——tests/dsh-persona-continuity.test.ts:231 的 #2241 e2e 仍钉着 #4438 之前的旧契约(「stamped review 必须 fork 出 |sub: 会话」),而本 PR 把 stamped review 改为 stateless passthrough,断言 forkSession 存在必然失败。本 PR 改写了 dsh-persona-fingerprint.test.ts 却漏了这个姊妹文件(正文声称的本地 93/93 未覆盖它)。已按「小问题直接修」在分支补两个标注 commit:

  • b306aa6da(并行 daemon 会话先推):把该 e2e 的 review 阶段改写为新契约(无 |sub: 铸造、上游仍 200、主会话 stats/refs 原样),文件头注释同步;并顺带更新了 gated 的 real-dsh tests/e2e/e2e-native-dsh-persona.test.ts(默认 skip,但启用后必红,一并翻转为 forks.length === 0)——这处扫得比我全;
  • a552b0c4f(我):纯缩进对齐(上述 commit 的 6 行头注释多了一个前导空格),无内容变更。

修复后逐 shard 验证:本地 4/4 + typecheck clean;CI 全绿。


独立核验过的关键点(对代码逐行钉过,不是转述 PR 描述):


结构化八问

  1. 是什么问题:DSH 自动审查扩展在每次执行工具前发一个「审查请求」(固定 REVIEW_POLICY system + 一条拍平历史快照的 user 消息,复用主会话 id)。在 0.1.204 上这一个请求会清空主会话全部压缩状态并污染其 token 基线,此后每个主请求都带 max_tokens=384000 撞上游 400,永不恢复。
  2. 什么原因导致的:同一失败域(aux 流量与主会话隔离)三层叠加——A 根因:rebase 资格判定读粘性绑定,身份门读实时 header,无头审查请求穿过全部隔离门;B:checkpoint guard 把消息中段引用的旧框架当成真实落地 → 清 refs/blocks/fold;C:审查响应在主车道结算 usage(baseline 676541→127497)+ 本地估算低估 ⇒ plugin mode: no hard backstop when the agent ignores the compress nudge — context grows past the window and upstream 400s #453 clamp 判 fits 变 no-op ⇒ 384000 原样送出。
  3. 影响范围与严重程度:p1——会话永久不可用(后续全 400),需人工干预。触发条件窄但后果硬砖:dsh 会话开 auto-review + 已有折叠状态 + 审查请求无 x-bili-plugin 头 + 快照引用过旧 checkpoint 框架。
  4. 怎么修复的:修决策点不堵症状。① 结构性识别 auto-review 形状(版本钉死 policy 前缀 + 无 tools + 恰好一条非系统消息)→ 一律走 标题生成等侧请求污染主会话状态:prepareAnthropic 缺 isTitleGen 守卫、快照无条件覆盖、survivedCount 每请求空转 #388 side passthrough:verbatim 转发、kernel 状态不碰、usage 不结算、不跑 rebase 检测;② checkpoint 载体收紧为「框架位于消息开头」。
  5. 是否有回归问题:逐项审过既有行为——title sidecar(dsh 0.2.1 Alpha.2更新了检查适配情况 #2503)不变(9/9 + allowlist);真实 checkpoint 落地的 rebase 门不变(双向测试);多轮主轮引用 policy 文本仍走完整管道(负例钉住);非 dsh agent 不受影响(allowlist);非 review 型不连续系统的 persona fork 不变(resolver 层 unit pins 有效,代码未动)。唯一实际发现的回归风险(上文 CI 红的旧契约测试)已当场修复,修复后全绿;无阈值/时序/输出格式静默变化。
  6. 是否破坏缓存:不涉及——prefix cache 策略未动,主车道字节流不变;会话状态从「被误报清空」变为「不被触碰」,是恢复不是破坏。
  7. 是否改了设计方向:一处,PR 正文已披露——带 stamp 的 dsh auto-review 从持久化 |sub:<fp> persona fork(并发同 session-id 流互相覆盖 lastInputTokens 基线:#388 侧请求分类漏掉「整段上下文单消息」形态,#1595 re-anchor 放大覆盖 #1916/[design/bug] DSH auto-review 与主会话共用 session 持续制造 CACHE SEAM;建议拆分为可压缩的 derived review lane #2203)改为一律 stateless passthrough。理由成立:blob 每次新鲜序列化、id 全换,持久态零折叠收益;[BUG][dsh] auto-review's own review request exceeds the context window (794K msgs + 256K completion > 1,048,576) → fail- | [BUG][dsh] auto-review 的评审请求自身越窗(794K msgs + 256K completion > 1,048,576)→ fail-closed,之后所有工具调用被拒 #3681 证明 review 车道自身会超窗;统一处理不再依赖不可靠 stamping。主轮行为不变(检测器要求 no-tools + 单消息形状,负例钉住)。
  8. 是否引入新配置:无。kernel-change: 无。

残余(代码内已注明):零证据全新会话(无 stamp、无绑定、无折叠块)落到完整管道——该状态下无害(#2432 门需要 active blocks);DSH 未来若改 REVIEW_POLICY 前缀措辞,检测器按版本钉死纪律降级为 miss(同 #2503),但缺陷 B 已独立堵掉,完整砖链不会复发。相邻校准饥饿缺口跟踪于 #4452,正确未并入。

收工判定:head a552b0c4f 全部 51 个 check-run 完成(37 success / 14 skipped / 0 failure,含 ubuntu/windows × node 22/24 全部 test shard),mergeable——可人工合并。合并后 #4438 自动关闭。

@ranxianglei

Copy link
Copy Markdown
Owner Author

(ai: zhipuai-lb/glm-5.3)

已并入合并列车 #4551(master 合并,merge commit 保留原作者署名)。本 PR 关单收尾;回滚点为 #4551 单提交 revert。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working dsh p1 scope/wiring

Projects

None yet

1 participant