Skip to content

[PR] fix: name every skipped DSH fork-adoption entry gate instead of returning silently (#4215) - #4223

Closed
ranxianglei wants to merge 2 commits into
masterfrom
2026-10-22_fork-adoption-gate-diagnostics
Closed

ranxianglei wants to merge 2 commits into
masterfrom
2026-10-22_fork-adoption-gate-diagnostics

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

What & why

C10a of the #3011 family checklist (#3025) — evidence instance: #4215.

#4215 showed a seeded fork child (isSeeded: true + correct parentSession) whose entire incident log contains ZERO adoption trace. The DSH native adoption entry had eight silent early returns (initiator threw/missing, no session, empty sid, no header, not-seeded, no parentSession, parent==self — plus the four pre-adopt gates), so after the fact there was no way to answer "was this not a fork, or a fork we failed to see?". This change makes the entry name itself on skip.

Changes (log-only)

No judgment, ordering, wire, or config changes. New lines appear only in the host log (bili.log, [dsh-client] origin); nothing reaches any client or model.

Not included (needs owner decision)

C10b — widening fork detection beyond ambient currentInitiator() (explicit branch identity carried by the host, or scoped-sid lookup once the host can expose header metadata by id). Options are on the table in the #3011 thread; until then the blind-spot line tells you exactly when detection was blind.

Residual: pi.ts maybeAdoptForkChild (:1359) and opencode-v2.ts httpRequestHook (:370) carry similar silent gates but different detection shapes — tracked under the #3011 family, out of scope here.

Tests

Ships no user-visible behavior change by design: it turns an unanswerable post-mortem into a one-line answer.

References #3011 (canonical issue), evidence instance #4215.

…ning silently (#4215)

C10a of the #3011 family checklist (#3025): the #4215 incident showed a
seeded fork child (isSeeded + correct parentSession) with ZERO adoption
trace in the whole log - eight silent early returns made "not a fork" vs
"a fork we could not see" unanswerable after the fact.

- forkChildOf() becomes exported forkChildVerdict(): names all eight
  shapes (initiator-threw/-missing, session-missing, sid-missing,
  header-missing, not-seeded, parent-missing, parent-is-self)
- a seeded candidate blocked at an entry gate (tools-ready / body-parse /
  side-shaped / proxy-base) logs once per session naming the gate
- malformed seeded lineage (isSeeded without a usable parentSession) logs
  a warn once per session
- ambient-blind shapes (fork status undeterminable) log ONE info notice
  per process, flagging whether scoped #4082 attribution was active - the
  C10b identity-route split named in the log
- plain non-fork traffic stays completely silent

Log-only change: no judgment, ordering, or wire behavior changes.
Regression suite: tests/issue4215-fork-gate-diagnostics.test.ts (verdict
matrix + both directions of every gate, #3617 discipline).

Identity-route widening (C10b) needs an owner decision and is NOT part
of this change.
@ranxianglei ranxianglei changed the title fix: name every skipped DSH fork-adoption entry gate instead of returning silently (#4215) [PR] fix: name every skipped DSH fork-adoption entry gate instead of returning silently (#4215) Oct 21, 2026
@github-actions

github-actions Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-10-22_fork-adoption-gate-diagnostics (2b5ede4)

Option A — Install this exact build (recommended)

npm install -g [email protected]

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

Option B — Download artifact

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

Install instructions are refreshed on each push.

@ranxianglei ranxianglei added bug Something isn't working dsh p2 scope/wiring labels Oct 21, 2026
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

查重: 不重复。 按失败签名(fork adoption / entry gate / #4215)检索 open+closed issue 与 PR:相关项为 #3011(canonical)、#3025(家族清单,服务端 completion window——不同机制)、#3024(409 SNAPSHOT_UNAVAILABLE 永久放弃——不同机制),均与本 PR 范围(entry-gate 命名诊断,C10a)不重叠。证据实例 #4215 已关闭。

标签: bug + dsh + scope/wiring + p2(dsh 车道协议接线的静默早退使 fork 收养失败事后不可诊断;影响面限于 fork 流、有绕行 → p2;pr 标签保留)。

审核方式:未复用 PR 描述结论,独立通读全量 diff(原单 commit fb54f6efd,2 文件 +312/-22:src/agent/dsh-native.ts + 新测试 tests/issue4215-fork-gate-diagnostics.test.ts),逐行对照改动前 master 代码验证判定表等价性,本地定向跑测试 + typecheck。

八问:

  1. 是什么问题:DSH fork 收养入口有 8 种静默早退 + 4 个 pre-adopt 门,像 [Bug][DSH] Fork loses fold inheritance without adoption diagnostics; interrupted preflight leaves child in repeated local 413 #4215 那样(seed 子会话、parentSession 正确、全日志零收养痕迹)事后无法区分「不是 fork」还是「fork 没看见」。本 PR 让每个 skip 路径在 bili.log 里自报家门。
  2. 什么原因导致的:原实现各门直接 return undefined 且零日志,触发谓词事后不可证。修法 = 判定函数结构化(forkChildOf()→导出 forkChildVerdict(),同一判定表拆成 8 个命名 shape)+ 调用方按严重度节流记日志(seed 候选被门挡:warn×1/session;畸形 lineage:warn×1/session;ambient-blind shape:info×1/process;not-seeded 普通流量:恒静默)。
  3. 影响范围与严重程度:只影响宿主日志(bili.log,[dsh-client] origin),客户端/模型/wire 零变化。用户可见面 = DSH fork 场景;底层风险(盲区/畸形 lineage 的子会话不带继承压缩态启动)限于 fork 流且有绕行 → p2。本 PR 自身按设计无用户可见行为变化。
  4. 怎么修复的:诊断分层——判定层纯函数返回结构化 verdict({ok:true,sid,parent} / {ok:false,reason,sid?,detail?}),调用层用 session 级 Set(forkGateNoted)+ process 级标志(noticedForkBlindSpot)节流;blind-spot 行会标注 Why did it spike to several M tokens: after dsh attribution was lost, requests bypassed bili and were sent directly, ren | 为什么会涨到几 M tokens:dsh 归因丢失后请求绕过 bili 直发,压缩与护栏全部失效 #4082 scoped attribution 是否激活(C10b 的 identity-route split 直接写进日志)。判定表与改动前逐条等价(旧复合条件 ↔ 新命名 shape 一一对应,ok 结果的 sid/parent 值不变)。
  5. 回归审查(触碰路径既有行为逐项):
    • 收养判定表:保持(等价性已逐条核对);
    • 四门(tools-ready/body-parse/side-shaped/proxy-base)延迟语义:保持——skip/defer 行为不变,仅加日志;sidecar 被 defer 后主请求仍能到达 adopter(测试钉住,断言真实协议行 "does not advertise the fork capability");
    • 普通/subagent 流量零输出:保持(负向测试断言 0 行);
    • 有意变更仅三处,均已在 PR 正文披露:seed 被门挡 静默→warn×1/session;畸形 lineage 静默→warn×1/session;ambient-blind 静默→info×1/process;
    • _resetRegisterForTest(base) 新增可选第二参 toolsReady=false:现有 10 个测试文件的单参调用全部不受影响;
    • 高危模式逐项过:无语义漂移、无 fail-fast 变吞错、无阈值/时序/输出格式漂移(纯加日志)、无缓存/重试策略变化;两种压缩模式都考虑过——变更仅在 plugin 车道(dsh native adapter),proxy mode 路径未触碰;skip 路径不触碰 init/body,wire 保真不受影响。
  6. 是否破坏缓存:不涉及——未触碰任何缓存/重试/增量游标/去重键逻辑,fork-adopt.ts 的 capability cache 未改。
  7. 是否改了设计方向:否。C10b(把检测扩出 ambient currentInitiator())明确不在本 PR,选项仍在 [Bug] Fork of DSH branch clone: inheritance permanently abandoned by 409 SNAPSHOT_UNAVAILABLE — zero-fold clone triggers context_length_exceeded 400 on first turn | [Bug] DSH 分支克隆的 fork 继承被 409 SNAPSHOT_UNAVAILABLE 永久放弃:克隆零折叠,首轮即 context_length_exceeded … #3011 线程等你拍板;在此之前 blind-spot 行精确告诉你检测何时是盲的。残余 pi.ts maybeAdoptForkChild(:1359)/opencode-v2.ts httpRequestHook(:370) 同类静默门继续挂在 [Bug] Fork of DSH branch clone: inheritance permanently abandoned by 409 SNAPSHOT_UNAVAILABLE — zero-fold clone triggers context_length_exceeded 400 on first turn | [Bug] DSH 分支克隆的 fork 继承被 409 SNAPSHOT_UNAVAILABLE 永久放弃:克隆零折叠,首轮即 context_length_exceeded … #3011 家族下。
  8. 是否引入新配置:无。

验证证据:

顺手修掉的小问题(独立 commit):新测试文件重复导入 node:fs(default + named 两行)——合并为一行,commit 2b5ede436(test: merge duplicate node:fs imports in the issue4215 suite (review nit)),修后复跑该套件 8/8 绿。

非阻塞观察:PR 正文只有 References 没有 Fixes/Closes 关键字——合理:C10a 只是 #3011 家族清单一项,C10b 与残余车道未完,关任何一个都过早;记录在此备查。

结论:可合——方向正确(根因是判定层缺证据面,修复正落在那里,不是症状拦截),回归干净,测试有牙。等 CI test shards 转绿后即可由你合并(合并是 human-only):#4223

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

CI 跟进:初跑最后一个 shard test (windows-latest, 22, 1) 假红,已定位并处理完毕,head 2b5ede436 现已全绿。

失败签名(job 119469067028):tests/issue4079-egress-window-fuse.test.ts 两例(1742/1743)failureType: 'cancelledByParent',error 'Promise resolution is still pending but the event loop has already resolved';TAP 汇总 pass 3933 / fail 0 / cancelled 2——零断言失败,是事件循环提前排空把挂起的 Promise 取消了,不是行为回归。

与本 PR 无关的证据链:

  1. 本 PR diff 只碰 src/agent/dsh-native.ts(dsh plugin 车道 before-send 钩子的日志)与新增测试文件;Context Window Overflow Issue Summary: Raw Requests Sent Directly to Upstream Rejected + Local Intercept Cooldown Lockin | 上下文超窗问题汇总:请求裸冲上游被拒 + 本地拦截冷却锁死会话(统一分析入口) #4079 直接驱动 proxy 出站 fuse 路径,不经过 dsh 车道,无交互面;
  2. 同一 run 里该套件在 ubuntu-22/24、windows-24 三个 lane 全部通过,仅 windows-node22 这一个 runner 命中;
  3. PR head 本地定向复跑该文件:2/2 绿(exit=0)。

已知家族:与 #3665(closed,Flaky Windows CI:event-loop drain 取消)同签名——那次是 issue1993-preflight-400,这次是 issue4079-egress-window-fuse。harness(#3665 的排水重试机制)已在原 runner 内重试一次并复现相同签名,判「persistent condition on this runner」,按机制指引重跑取新 runner。

处置:已触发 failed-job rerun(HTTP 201)→ 新 runner 上该 shard 通过,整个 run 21 success / 1 skipped(条件跳过)/ 0 failure。

结论维持上一条:可合,合并是 human-only:#4223

@ranxianglei

Copy link
Copy Markdown
Owner Author

(ai: zhipuai-lb/glm-5.3)

已并入合并列车 #4525(master 6d7c587,合并方式 merge commit,提交保留原作者署名)。本 PR 关单收尾;若列车中对应提交出问题,回滚点为 #4525 单提交 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 p2 scope/wiring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant