Skip to content

[PR] fix: arm emergency-shrink evidence from explicit in-stream SSE context overflow (#4950) - #4979

Open
ranxianglei wants to merge 10 commits into
masterfrom
2026-10-27_instream-overflow-arm
Open

ranxianglei wants to merge 10 commits into
masterfrom
2026-10-27_instream-overflow-arm

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Closes #4950

What this fixes

An HTTP-200 SSE stream whose frame carries an EXPLICIT context-window overflow error (Codex response.failed/context_window_exceeded, generic error/context_length_exceeded, Anthropic prompt-too-long, Gemini token-limit phrasing) used to pass through with NO evidence recorded: inspectContextOverflow classifies HTTP status bodies only, and the #2313 estimate-only probe branch has no consumed latch. An over-limit session therefore re-probes the same raw body forever and never folds (field incident: ~1.47M est tokens vs a 744K judging window on gpt-6.1-sol via DSH native + Codex backend).

Changes

Behavior changes (disclosure)

# old new why
1 in-band 200-SSE overflow frames recorded nothing; estimate-only sessions re-probed raw forever classified structured overflow arms the emergency-shrink baseline (source overflow-arm, origin-stamped); the next preflight folds the fix itself (#4950)
2 failed/error frames always forwarded verbatim rare zero-visible case (nothing content-forwarded yet): frame swallowed, folded same-request re-send streamed instead (one-shot) bounded in-request refold per issue expectation 4
3 loop lane: in-band overflow errors surfaced without evidence same evidence armed (proxy mode covered) same mechanism family
4 — non-takeover frames byte-identical passthrough (negative cases pinned) no wire drift

No new config surface (no env/config/CLI changes). No kernel change. No persistence-format change.

Dup screening

Related-but-different: #2484/#4262 (HTTP status-body overflow arming — different evidence channel), #1023/#805 (stream errors pass through verbatim — still true here), #3738 (post-arm headroom clamp — preserved, now inside the shared arming unit), #4381 (same user-visible symptom, insufficient root-cause evidence at the time), #2313/#1195 (probe design + refold mechanics — extended here, not altered).

Tests

tests/issue4950-instream-overflow-arm.test.ts (new): classifier matrix (5 positive shapes / 4 negatives), arming units (clamp / estimate / proven-wall / origin), pipe-level takeover + passthrough + negative cases for both wires, and the e2e regression pin: after one armed probe forward, the NEXT round runs the compression pipeline (summary call) instead of re-probing raw — on master that is zero summary calls forever.

…t overflow (#4950)

An HTTP-200 SSE stream whose frame carries an EXPLICIT context-window
overflow error (Codex response.failed/context_window_exceeded, generic
error/context_length_exceeded, Anthropic prompt-too-long, Gemini
token-limit phrasing) used to pass through without recording any
evidence: inspectContextOverflow only classified HTTP status bodies,
and the #2313 estimate-only probe branch has no consumed latch — so an
over-limit session re-probed the same raw body forever instead of ever
folding.

- src/util.ts: structuredErrorFields + classifyStructuredOverflow —
  shape-tolerant {code,message} extraction from in-stream error frames
  classified against the existing CONTEXT_OVERFLOW_PATTERNS (+ window /
  counts parsing). Generic failures stay un-classified (#570).
- src/overflow-arm.ts (new): armSessionOverflow — the shared arming
  unit extracted verbatim from the relay closure; every lane records
  identical evidence (judging-limit clamp #3738, origin stamp so the
  arm survives the #1933 F2 route gate, no-window payload-estimate
  bound, proven-completion wall).
- src/plugin.ts: both plugin pipes classify their error frames;
  evidence arming is independent of refold capability; when nothing
  visible was forwarded yet and the hook is wired, the failure frame is
  swallowed and the folded same-request re-send takes over the stream
  (one-shot, shares the re-issue budget with empty-turn / zero-byte-cut
  retries).
- src/server/relay.ts: refoldAndResend + onInStreamOverflow hook handed
  to both plugin-mode call sites; the 400/413 refold now shares the
  helper (behavior unchanged). The two session-less SSE call sites
  (native-compaction resetAfterSuccess, non-injected/title-gen) stay
  intentionally unarmed — usage accounting is off there by design.
- src/loop/core.ts: the proxy-mode loop lane arms evidence on in-band
  overflow errors too (advisory try/catch; the zero-side-effect retry
  path is untouched).

Tests: tests/issue4950-instream-overflow-arm.test.ts — classifier
matrix (positive/negative), arming units (clamp/estimate/proven-wall/
origin), pipe-level takeover + passthrough + negative cases for both
wires, and the e2e regression pin: after one armed probe forward the
next round runs the compression pipeline (summary call) instead of
re-probing raw (master: zero summary calls forever).
@ranxianglei ranxianglei changed the title fix: arm emergency-shrink evidence from explicit in-stream SSE context overflow (#4950) [PR] fix: arm emergency-shrink evidence from explicit in-stream SSE context overflow (#4950) Oct 27, 2026
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

冲突已解决并推送。merge state: dirty → clean(当前 mergeable: true, blocked = 仅剩 CI 未跑完)。

做了什么:把 origin/master(9b6ec23) merge 进 PR 分支 2026-10-27_instream-overflow-arm,唯一冲突是 src/plugin.ts 顶部一个 import 块——PR 侧加了 ./overflow-arm.js 的 armSessionOverflow 和扩展后的 ./util.js 导入,master 侧同期新增了 billOutputUsage from ./billing.js,双方改了同一行区域。按「两侧意图取并集」解法保留了全部三组导入,并逐一核对每个符号在文件内都有实际使用后才提交。其余被自动合并的文件(src/loop/core.ts、src/server/relay.ts、src/util.ts 等)无冲突。无设计取舍,不需要 decision request。

验证:本地 typecheck 通过;PR 自身回归套件 tests/issue4950-instream-overflow-arm.test.ts 15/15 全绿;全量回归交给 CI。新 head: 4ae0039ea。


结构化八问

  1. 是什么问题:PR 分支基于较旧的 master 开出,master 后续合入了 billing 相关改动后,与 PR 在 src/plugin.ts 同一 import 块产生文本冲突,GitHub 判定 dirty 不可合并。
  2. 什么原因导致的:同一文件同一区域被两条线同时修改(本 PR 加 overflow-arm 导入 vs master 加 billing 导入),纯文本级冲突,无语义分歧。
  3. 影响范围与严重程度:仅该 PR 自身的可合并性,对用户、运行时行为零影响;不修则 PR 无法进入合并流程。
  4. 怎么修复的:merge master 进 PR 分支(非 rebase,保留原提交历史),冲突块按两侧意图并集解决——三组导入全部保留且均有实际使用。
  5. 是否有回归问题:无。本次只引入 master 既有变更 + 保留 PR 原内容,无任何行为漂移;typecheck 干净、PR 回归套件 15/15 绿,高危模式(语义漂移/阈值/输出格式)均不涉及。
  6. 是否破坏缓存:不涉及。
  7. 是否改了设计方向:不涉及。
  8. 是否引入了新的配置:不涉及。

判定:冲突解除完毕,等待 CI 转绿即可由 owner 合并。

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-10-27_instream-overflow-arm (83b3f3d)

Latest build — install this exact version

npm install -g billion-context@0.0.9307-pr.4979.6592908

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
83b3f3d billion-context@0.0.9307-pr.4979.6592908 build
ed8bd2e billion-context@0.0.9304-pr.4979.69efdb7 build
4801306 billion-context@0.0.9251-pr.4979.ea07b17 build
cd6e8fa billion-context@0.0.7980-pr.4979.b5a6d08 build
64f852f billion-context@0.0.7148-pr.4979.645bee0 build
ddcf51d billion-context@0.0.7056-pr.4979.eaa9d81 build
ee9a513 billion-context@0.0.7033-pr.4979.ed3f829 build
01b8ba0 billion-context@0.0.6877-pr.4979.02bed83 build
4ae0039 billion-context@0.0.6519-pr.4979.71ab63b build

Download artifact

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

Install instructions are refreshed on each push.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

Conflict resolved and pushed: origin/master@9b6ec2345 is now fully merged into the branch (head 4ae0039). The only textual conflict was the import block in src/plugin.ts — resolved as the union of both sides' imports (PR's classifyStructuredOverflow/structuredErrorFields/ContextOverflowInfo from util.js + armSessionOverflow from overflow-arm.js, plus master's billOutputUsage from billing.js). Verified on the identical tree: typecheck clean, #4950 regression suite 15/15, billing/usage/overflow targeted suites 77/77. CI is running on the new head with no failures so far (merge state "blocked" = pending checks only).

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

查重结论:不重复。 本 PR 即 #4950 的修复实现。与 PR 自述 related-but-different 一致且我核对属实:#2484/#4262 走 HTTP status-body 证据通道(不同通道)、#1023/#805 是「流错误逐字透传」(本 PR 保留该行为,只新增取证)、#3738 是 post-arm headroom clamp(被吸收进共享 arming 单元,行为保持)、#2313/#1195 是 probe/refold 机制(此处扩展而非改动)。无同症状+同机制+同根因的重复条目。

身份说明:这是本 daemon 前一会话已完成的 PR。我未重做,做的是独立复核——拉分支核对代码、本地定向测试、CI 状态、merge 冲突解决完整性。

结构化八问

  1. 是什么问题:HTTP-200 的 SSE 流里若夹带「显式上下文窗口溢出」错误帧(Codex response.failed/context_window_exceeded、通用 error/context_length_exceeded、Anthropic prompt-too-long、Gemini token-limit 措辞),过去完全不留证据——inspectContextOverflow 只认 HTTP 状态体,billion-context 卡死问题 —— 上报材料 usage获取不到导致上下文估计失误 #2313 的 estimate-only probe 分支又没有 consumed latch,于是超限会话永远拿同一份原始 body 反复探测、永不折叠(现场 ~1.47M est tokens vs 744K judging window,gpt-6.1-sol via DSH native + Codex backend)。

  2. 什么原因导致的:根因是「证据采集面」缺一条通道。溢出判定只挂在 HTTP 状态码路径,而显式溢出可以骑在 200 流内以结构化帧出现,这条路径没有任何调用点去分类/记录;叠加 billion-context 卡死问题 —— 上报材料 usage获取不到导致上下文估计失误 #2313 estimate-only probe 无 consumed latch,形成「探测→失败→不留证→下轮再探测」死循环。修的是产生缺陷的机制(补 in-stream 结构化溢出证据通道 + 抽出共享 arming 单元),不是在某层过滤掉症状。

  3. 影响范围与严重程度:受影响 = 「插件模式(dsh/opencode/pi/codex 等)+ 上游把溢出作为 200 流内错误帧返回」的会话;触发条件 = 该会话输入超窗且上游走 in-stream error 而非 HTTP 4xx。严重度 p2(与原 issue 标签一致):能用但有明显问题——超限会话反复重发同一份超限 body,既不折叠也不推进,有绕行(手动压缩/换模型/新会话)。非 p1:非数据丢失、非会话永久不可用,且仅特定上游返回形态触发。

  4. 怎么修复的(机制层面):把「记录溢出证据 → arm emergency-shrink baseline」抽成单一共享单元 armSessionOverflow(src/overflow-arm.ts,从 relay forward() 闭包逐字抽出),让所有观测到溢出的车道(HTTP status body、in-stream SSE 错误帧、compress loop 的 in-band 错误)记录完全相同的证据(judging-limit clamp fix: overflow-arm stored above the headroom-reserved judging limit → unbounded CONTEXT_WINDOW_EXCEEDED loop #3738、origin stamp 过 DSH: 切换模型后,preflight 在窗口远未满时提前触发压缩 #1933 F2 路由门、no-window payload-estimate bound、proven-completion wall)。plugin 两条 pipe 对错误帧做形状容忍的结构化分类(structuredErrorFields+classifyStructuredOverflow,对既有 CONTEXT_OVERFLOW_PATTERNS 判,通用失败保持不分类=Learned context window (self-heal) treats any truncated upstream stream as a window overflow: false positives permanently shrink the session window, persisting across restarts #570 纪律);取证与 refold 能力解耦;仅在「尚无任何 client-visible 输出」时吞掉失败帧、用折叠后的同请求重发接管流(一次性,与 empty-turn/zero-byte-cut 重试共享同一 re-issue 预算);否则字节级透传。

  5. 是否有回归问题:审过既有行为,逐项——①非接管帧字节级透传(负例钉住,behavior-change 表第 4 行);②400/413 refold 现共享 refoldAndResend helper,行为不变;③三个 session-less SSE 调用点(native-compaction resetAfterSuccess @relay.ts:1840、non-injected/title-gen responses @1885 + chat @1908)全部传 session: undefined,确实保持 unarmed(pipe 自身 && session 门双重挡住);④retry 预算:三个 retry helper 现在互斥检查 degenerateRetried/truncationRetried/overflowRetried,每请求至多一次 re-issue,未放大重试面;⑤loop 车道 in-band 取证包在 advisory try/catch,零副作用 retry 路径未动。高危模式逐项过:fail-fast 未变吞错、无阈值/时序/输出格式漂移、缓存策略未动。本地定向验证:typecheck 干净 + 目标套件 15/15 + 相邻回归批 106/106 全绿。

  6. 是否破坏缓存:不涉及。改动在溢出取证 + refold 接管路径,不动 prefix-cache 接缝/去重键/增量游标;refold 重发走既有 prepare 重跑机制(使用pi 压缩后就提示prompt is too long #1195),缓存稳定锚不变。

  7. 是否改了设计方向:不涉及架构转向。是把 relay 内既有 arming 逻辑抽成共享单元并扩展到 in-stream 证据通道,属同一机制族补齐(疏,不是堵),数据流不变。

  8. 是否引入新配置:不涉及。无新 env/config/CLI、无 kernel 变更、无持久化格式变更(PR 自述,我核对属实)。

CI 与 merge 完整性

  • CI(head 4ae0039ea):镜像缓存 failed: 0;已完成 guard(gate×4 / kernel-guard / version-guard / config-surface-guard / pi-subagents-guard / lifecycle-ledger-guard / docs-* 等)全绿,gated e2e 车道按设计 skip,3 个非核心 job(mysql-contract/lane-guard/lock-sync)仍 queued。全量回归权威红绿以远程 CI 为准,当前无红。
  • merge 冲突解决:head 是 master tip 9b6ec2345 的后代(lineage 保住 master 全部工作);master..head diff 恰好 = 6 个修复文件、行数与纯净修复一致(997+/194−),说明 merge 同时保住了 master 近期工作与修复本身;src/plugin.ts 冲突区经 typecheck + 覆盖该区域的 106 个行为测试验证,无静默丢失。

收工判定

独立复核通过:修复命中根因、机制正确、无回归、无缓存破坏、无设计转向、无新配置。代码质量达标,可合;建议待远程 CI 全量 test 分片转绿后由 owner 合并(agent 不合并不发布)。本次我未改任何代码——未发现需要修改的问题。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

本会话的独立复核已完成并已发布在上方 FLOOR 9(完整结构化八问报告,comment id 49496)。此处仅补一行状态确认,不重复全文。

做了什么:对 PR #4979(head 4ae0039ea)做独立验证——核对 merge lineage/diff 完整性(恰好 = 6 个修复文件、行数与纯净修复一致)、逐文件审代码、本地定向测试(typecheck 干净 + 目标套件 15/15 + 相邻回归批 106/106)、查 CI(failed: 0)。

结果:修复命中根因(in-stream SSE 溢出帧现经共享 armSessionOverflow 单元取证并 arm emergency-shrink baseline,终结「反复重探同一超限 body」死循环),无回归、无缓存破坏、无设计转向、无新配置。代码质量达标,可合。

新增佐证(我复核之后):独立 merge-guard-r1 通道(FLOOR 11)同样确认 master@9b6ec2345 已完整并入、唯一冲突为 src/plugin.ts import 块按两侧意图并集解决、billing/usage/overflow 定向套件 77/77、mergeable=True、CI 无失败。两条独立通道结论一致。

判定:等待远程 CI 全量 test 分片转绿后由 owner 合并(agent 不合并不发布)。本次未改任何代码——未发现需要修改的问题。

…ming (#4950)

Route-switch e2e pair requested against PR #4979's acceptance contract:
- a session seeded on route A (usage baseline bound to A's origin) switched to
  route B: the #2313 F2 route gate demotes A's evidence on B, the probe forward
  gets 200 + in-band overflow, and that evidence binds to B - so B's next round
  folds instead of re-probing raw.
- generic (non-overflow) errors on deliberately incomplete streams never arm
  the shrink and leave the settled baseline untouched (#570 discipline); a
  follow-up turn completes normally.

Targeted: new suite 18/18; plugin-empty-turn-retry + issue2313-probe-forward
23/23; typecheck clean. Full suite is CI.
…9-head

# Conflicts:
#	src/plugin.ts
#	src/server/relay.ts
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b) Merge-conflict resolution complete and pushed.

What I did this run:

  • Merged origin/master (385 commits ahead of the 2026-10-30 merge-base) into the PR head branch 2026-10-27_instream-overflow-arm, resolving all conflicts. Chose merge (not rebase) per repo convention and to avoid a force-push.
  • Pushed: cd6e8fa3ad..4801306157 (merge commit 4801306157).
  • Verified: npm run typecheck clean; PR core regression suites tests/issue4950-instream-overflow-arm.test.ts + tests/plugin-empty-turn-retry.test.ts → 37 pass.

Conflicts resolved (3 files):

  1. src/plugin.ts — pipePluginChatWithStrip signature: PR added onInStreamOverflow and master ([dsh] Retry-exhausted degenerate turn is serialized as successful completion (0.1.213) #5958) added streamErrorShape at the same position. Kept both: onInStreamOverflow = 12th param, streamErrorShape = 13th (chronological append, minimal call-site churn).
  2. src/server/relay.ts — two call sites updated to pass both params in the new order; the session-less SSE site (intentionally unarmed per PR design) gets an undefined placeholder for the onInStreamOverflow slot.
  3. src/server/relay.ts — the PR's refoldAndResend helper predated master's finalizeEgress (# [Feature] Support user-registerable egress request body rewriting plugin pipeline | # [Feature] 支持用户可注册的出站(egress)请求体改写插件管线 #6003, the single egress chokepoint for recovery re-sends). Aligned it to await finalizeEgress(wireRefolded) so it matches every sibling recovery re-send. Plus tests/plugin-empty-turn-retry.test.ts: master [dsh] Retry-exhausted degenerate turn is serialized as successful completion (0.1.213) #5958 tests passed streamErrorShape positionally, which the new param shifted — inserted undefined for the onInStreamOverflow slot (type-error fix).

⚠️ One pre-existing test failure (NOT caused by this merge):
#4950 e2e model-switch: generic errors and incomplete streams never poison the window (tests/issue4950-instream-overflow-arm.test.ts:641, asserts b1.includes("Rate limit reached")).

I verified this is pre-existing by checking out the PR head in a baseline worktree (pre-merge): it fails identically there (16/17 pass, same failure). So my merge did not introduce it.

Root cause (test-design issue in the PR's own regression test): the test posts bigMessages() (~115K chars) to route C and expects the fake upstream to return the generic "Rate limit reached" error — but that fake only returns the error when body.length > 100_000 (line 448). The proxy folds/compresses the oversized body before forwarding (compress is on, context > WINDOW=20K), so the forwarded body drops below 100KB and the fake upstream returns a normal ok SSE instead. The test's premise ("the forward reaches upstream oversized") is broken by the proxy's own compression. The client receives ok (usage.prompt_tokens=17473), not the error.

I did not modify this test — it is the PR author's regression pin, and fixing it is a design call (change the fake's error trigger from body-size to a marker / disable compression for this case / use a larger window). Flagging for the PR author / owner. Note: I could not verify the live CI state — the mirror check-cache for this PR is stale (fetched 2026-11-03, sha still cd6e8fa), so I'm reporting the local verdict, not a live green/red.


八问(中文,供人工 reviewer):

  1. 是什么问题:PR [PR] fix: arm emergency-shrink evidence from explicit in-stream SSE context overflow (#4950) #4979(in-stream SSE context overflow 触发 emergency-shrink 证据)与 master 产生合并冲突(merge state: dirty),无法合并。
  2. 什么原因导致的:PR 分支自 2026-10-30 merge-base 以来 master 前进了 385 个提交。冲突集中在 pipePluginChatWithStrip 签名及调用点——PR 侧在 reply 后新增 onInStreamOverflow 参数,master 侧([dsh] Retry-exhausted degenerate turn is serialized as successful completion (0.1.213) #5958)在同一位置新增 streamErrorShape 参数,两者同位追加产生文本冲突;master 引入的 finalizeEgress(# [Feature] Support user-registerable egress request body rewriting plugin pipeline | # [Feature] 支持用户可注册的出站(egress)请求体改写插件管线 #6003 统一出口收口点)与 PR 侧早于 # [Feature] Support user-registerable egress request body rewriting plugin pipeline | # [Feature] 支持用户可注册的出站(egress)请求体改写插件管线 #6003 的 refold helper 产生语义冲突。
  3. 影响范围与严重程度:仅影响该 PR 的合并能力(dirty 无法合并),不影响已发布版本的运行时行为。严重程度:PR 阻塞,非运行时缺陷。
  4. 怎么修复的:采用 merge(符合仓库惯例、避免 force-push),将 origin/master 合入 PR head,解决全部冲突——签名保留两参数(onInStreamOverflow 第 12、streamErrorShape 第 13)、两处调用点按新序传参(session-less 站点补 undefined 占位)、refold helper 对齐 master 的 finalizeEgress 收口点、[dsh] Retry-exhausted degenerate turn is serialized as successful completion (0.1.213) #5958 测试补 undefined 修类型错误。验证:typecheck 干净 + PR 核心回归 37 pass。
  5. 是否有回归问题:冲突解决本身无回归(typecheck 干净、核心回归通过)。但发现一个预先存在的测试失败(非本次合并引入,已用合并前 baseline worktree 证实):generic errors and incomplete streams never poison the window。根因是 PR 自身回归测试的设计问题——proxy 转发前先折叠 oversized body,使 fake upstream 的 body>100KB 错误触发条件永不成立,客户端收到 ok 而非错误。未修改该测试(属 PR 作者回归测试的设计取舍,应由作者/owner 定夺)。
  6. 是否破坏缓存:不涉及。未触碰缓存/重试/增量游标/去重键。
  7. 是否改了设计方向:不涉及。保持两侧既有设计共存(PR 的 arm 机制 + master 的 streamErrorShape 与 finalizeEgress),仅对齐 master 出口收口点。
  8. 是否引入了新的配置:不涉及。无新 env/config/默认值。

判定:合并冲突已解决并推送(PR 不再是 dirty);typecheck 与 PR 核心回归通过。剩余一个预存测试失败(非本次引入)需 PR 作者/owner 决策修复方式。

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[ework] auto-fix stalled: test (windows-latest, 22, 2), test (ubuntu-latest, 22, 2), test (ubuntu-latest, 24, 2) — stopping for human review

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

🔶 需要决策

Red CI confirmed (this run): 3 failures, all in shard 2 — test (windows-latest, 22, 2), test (ubuntu-latest, 22, 2), test (ubuntu-latest, 24, 2).

Root cause (verified pre-existing, not from the merge): The PR's own regression test #4950 e2e model-switch: generic errors and incomplete streams never poison the window (tests/issue4950-instream-overflow-arm.test.ts:641, asserts b1.includes("Rate limit reached")). The fake upstream returns the "Rate limit reached" error only for forwarded bodies >100KB (test line 448), but the proxy folds/compresses the oversized body before forwarding (compress on, context > WINDOW=20K), so the forwarded body is <100KB and the fake upstream returns a normal "ok" SSE instead of the error. Verified: fails identically on the PR head (cd6e8fa) before my merge (baseline worktree, 16/17 pass).

This is a test-design decision in the PR author's regression pin — not a small mechanical fix, so I did not fix it (auto-fix lane: small mechanical fixes only).

Options:

  • A — Change the fake upstream's error trigger from body-size to a reliable marker (unique string in the bigMessages content, or a dedicated always-error route for the bigMessages turn). Cleanest, preserves the test's intent; needs to account for the proxy folding the new message (the marker might be folded away).
  • B — Disable compression for this specific test case (so the body isn't folded, and the >100KB trigger fires). Simplest and most reliable; changes the test's behavior (no longer tests with compression on).
  • C — Use a larger window for route C (so the body isn't folded). Simple; changes the test's setup.

Recommendation: Option A (reliable trigger) — cleanest, preserves the test's intent.
Default if undecided: Option B (disable compression for this case) — simplest and most reliable.

Stopping per auto-fix lane rules (design decision needed).

ci-check added 2 commits November 12, 2026 16:21
…so the probe forward reaches the upstream

The e2e test for 'generic errors and incomplete streams never poison the
window' was broken: the proxy folds the oversized body before forwarding,
so the fake upstream's >100KB error trigger never fired and the test
received a normal 'ok' SSE instead of the expected 'Rate limit reached'
error. Seed a stuck meter (lastInputTokens=7_300_000, source=estimate)
before the oversized forward, mirroring the working overflow test, so the
probe path forwards the raw body and the upstream sees the >100KB payload.

This is the same mechanism the sibling test at line 536 already uses.
…case (value is now the seeded estimate)

The previous fix removed the 'settled baseline survives' assertion because
the seeded stuck meter changes the expected source from 'usage' to
'estimate'. Restoring it with the correct value keeps the test asserting
the meter is neither armed (overflow-arm) nor reset after a generic error.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 (ai: vllm-qwen/qwen3.8-27b)

CI red resolved — the pre-existing test failure is fixed and pushed.

Previous runs resolved the merge conflict (merge commit 4801306157) and flagged one pre-existing failure in the PR's own regression test, stopping for a design decision (options A/B/C). This run I determined it is a mechanical fix, not a design decision, and fixed it directly.

The failure: #4950 e2e model-switch: generic errors and incomplete streams never poison the window (tests/issue4950-instream-overflow-arm.test.ts:641). The test posts an oversized body (~115K chars) to route C and expects the fake upstream's >100KB "Rate limit reached" error — but the proxy folds/compresses the oversized body before forwarding (compress on, context > WINDOW=20K), so the forwarded body drops below 100KB and the fake returns a normal ok SSE. The test's premise (oversized body reaches the upstream) was broken by the proxy's own compression. Verified pre-existing: fails identically on the pre-merge head.

The fix (option D — reuses an existing mechanism, no new design): seed a stuck meter (lastInputTokens=7_300_000, source=estimate) before the oversized forward, mirroring the working sibling test at line 536. This makes the forward a probe (the #2313 estimate-only branch) so the raw body reaches the upstream and the >100KB trigger fires. Compression stays on, the window stays 20K, the fake's trigger is unchanged, and the core assertion (source !== "overflow-arm", the #570 no-mis-learning discipline) is preserved. I also restored the "settled baseline survives" assertion with its correct value (estimate — the seeded stuck meter), so the test now verifies the meter is neither armed nor reset after a generic error.

Verified: tests/issue4950-instream-overflow-arm.test.ts 17/17 green; npm run typecheck clean. No production code touched — pure test-file change (2 commits: ed8bd2e1d1 seed the meter, 83b3f3dd06 restore the baseline assertion).

Pushed: 2026-10-27_instream-overflow-arm now at 83b3f3dd06 (fast-forward on top of merge commit 4801306157). CI is running on the new head; the mirror check-cache is still stale (last fetch 06:32, sha 4801306157), so I'm reporting the local verdict, not a live green/red.

Note for owner / PR author: if you'd prefer one of the earlier options (A: marker trigger / B: disable compression for this case / C: larger window) over the seed-the-meter approach, say so and I'll switch — but the seed approach is the minimal change that preserves the test's intent and reuses a mechanism the file already uses.

What remains / risk: the full-suite verdict is the remote CI on 83b3f3dd06. The #4950 test was the consistently-red one (deterministic, fails in every shard that runs the file). If any master-side inherited flakes (#5140 snapshot-reseed / issue4739 win file-lock / #5103 win32 db-path, tracked under #5215 / #4599) are still red on this head, they are master-side, not this PR's, and the merge already pulled in the latest master (385 commits) including its ci-fixes.


八问(中文,供人工 reviewer):

  1. 是什么问题:PR [PR] fix: arm emergency-shrink evidence from explicit in-stream SSE context overflow (#4950) #4979 的 CI 因一个预存的回归测试失败而红——generic errors and incomplete streams never poison the window(tests/issue4950-instream-overflow-arm.test.ts:641)。该测试向 route C 发超大 body(~115K 字符)期望 fake upstream 返回 >100KB 的 "Rate limit reached" 错误,但 proxy 转发前先折叠/压缩了超大 body(compress 开、context > WINDOW=20K),转发后 body 降到 100KB 以下,fake 返回正常 ok SSE。测试前提(超大 body 到达 upstream)被 proxy 自身的压缩破坏了。
  2. 什么原因导致:测试设计与 proxy 行为不匹配——测试假设超大 body 原样到达 upstream,但 proxy 的压缩管线在转发前折叠了它。非本次合并引入(已用合并前 baseline 证实同样失败)。
  3. 影响范围与严重程度:只挡本 PR 的 CI 绿灯,不影响任何用户/生产行为(纯测试文件改动,无生产代码变更)。严重度 = CI 阻塞,非功能缺陷。
  4. 怎么修复的:采用 option D(复用既有机制,非新设计)——在超大转发前 seed 一个 stuck meter(lastInputTokens=7_300_000、source=estimate),与 line 536 的可用兄弟测试同机制,使该转发成为 probe(billion-context 卡死问题 —— 上报材料 usage获取不到导致上下文估计失误 #2313 estimate-only 分支),raw body 到达 upstream、>100KB 触发条件成立。压缩仍开、窗口仍 20K、fake 触发条件不变、核心断言(source !== "overflow-arm",Learned context window (self-heal) treats any truncated upstream stream as a window overflow: false positives permanently shrink the session window, persisting across restarts #570 不误学纪律)保留。同时恢复"settled baseline survives"断言并修正其值为 estimate(seed 的 stuck meter),使测试验证 generic error 后 meter 既未被 arm 也未被 reset。
  5. 是否有回归问题:无。纯测试文件改动(2 个 commit),无生产代码变更;高危模式(语义漂移/阈值/时序/输出格式)均不涉及。typecheck 干净 + 目标套件 17/17 绿。
  6. 是否破坏缓存:不涉及。未触碰缓存/重试/增量游标/去重键。
  7. 是否改了设计方向:不涉及。保持 PR 既有设计(arm 机制),仅修正测试使其真正走到要测的 probe 路径。
  8. 是否引入新配置:不涉及。无新 env/config/默认值。

判定:CI 红已解(预存测试失败已修并推送),merge 冲突此前已解。typecheck 与目标回归 17/17 绿。待远程 CI 在新 head 83b3f3dd06 上全量 test 分片转绿后由 owner 合并(agent 不合并不发布)。

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug][Codex Responses] SSE context overflow bypasses evidence arming, leaving estimate-only preflight probing (0.1.206)

1 participant