Skip to content

[PR] fix: adopt the refold pipeline's Prepared on accepted overflow refolds (#2777) - #2785

Closed
ranxianglei wants to merge 1 commit into
masterfrom
2026-10-11_overflow-refold-prepared
Closed

ranxianglei wants to merge 1 commit into
masterfrom
2026-10-11_overflow-refold-prepared

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

Closes #2777

What

An accepted overflow refold updated the wire body but left forward()'s local Prepared binding stale (the callback mutated pendingForward.*, which does not alias into forward()'s parameter). The internal compression loop seeds its coreMessages from that binding, and a FAILED compress (e.g. the model citing refs from its stale pre-refold view) skips the post-compress fold refresh (core.ts: refresh only on non-FAILED proxy results) — so the continuation re-request rebuilt the ORIGINAL oversized message view instead of the accepted folded one, re-triggering upstream context overflow.

Fix

  • overflowRefold now returns { body, prepared }; handle.ts hands back the refold pipeline's Prepared alongside the body.
  • relay.ts adopts both after a SUCCESSFUL retry (if (refolded.prepared) prepared = refolded.prepared). Failed retries keep today's behavior exactly.
  • The bili 改写带 body 签名的模型请求,CodeArts(华为 APIG SDK-HMAC-SHA256)全部 401 #1884 lone-surrogate scrub still applies to the returned body; signed thinking and byte-exact tool arguments are untouched (this fix changes which prepared VIEW seeds the loop, not how any payload is transformed).

Behavior change disclosure (old → new)

After an ACCEPTED overflow refold, the body of subsequent internal tool-loop continuations is now composed from the accepted folded view (fold summary + recent tail) instead of the pre-refold unfolded message view. This is the intended fix. Outside that path nothing changes: the hook only exists when a prepared forward is present, fires only on a stated-window overflow 400/413, and adoption happens only when the retry is accepted. Client-visible behavior for normal turns, failed retries, and unfoldable payloads is byte-identical (regression cases A/B/C unchanged and green).

Tests

  • New regression case in tests/issue1195-overflow-refold.test.ts: overflow 400 → preflight summary → accepted folded retry emitting compress(startId=m00042,endId=m00099) (invalid refs) → asserts the internal continuation carries the fold summary + recent tail and omits the folded early markers. Verified FAILING on master without the fix, PASSING with it.
  • Adjacent hermetic suites green locally: context-overflow, e2e-overflow-selfheal, refold-wiring, issue2484-overflow-and-summary (37 tests) + the full 4-case refold suite.
  • npm run typecheck clean; npm run build clean (dist built at the PR head).
  • Real-client codex e2e (ACP_TEST_E2E=1) could not run in this environment (no local LLM upstream available here); CI covers it for src/server/** changes.

@github-actions

github-actions Bot commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-10-11_overflow-refold-prepared (093d41a)

Option A — Install this exact build (recommended)

npm install -g billion-context@0.0.3066-pr.2785.0b9163a

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-pr2785.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

[bot] 🏷 正在 review(不重做——这是已完成的 ework-agent-pr 工作,走拉分支核对 + CI 确认流程)。初步结论:方向正确、机制已在代码层面核实(runCompressLoop 的 seed 确实取自 forward() 本地 prepared 绑定,core.ts 的 fold refresh 门只放行非 FAILED 结果)。CI 唯一红项 test (windows-latest, 24) 是存储测试清理的 EPERM 文件锁 flake(#2771 家族),与本 PR 改动无关且 master 已由 #2788 修复——正在把分支 rebase 到当前 master(e7b94a2)后重跑。另注意:#2777 上还有一个外部贡献者的 draft PR #2786,两个 PR 都 close 同一 issue,合并其一后另一个应关闭。完整八问结论稍后补。

#2777)

An accepted overflow refold updated the wire body but left forward()'s local
Prepared binding stale. The internal compression loop seeds its coreMessages
from that binding, and a FAILED compress (e.g. invalid refs from the model's
stale view) skips the post-compress fold refresh — so the continuation
re-request rebuilt the original oversized message view instead of the
accepted folded one, re-triggering upstream context overflow.

- overflowRefold now returns { body, prepared }; handle.ts hands back the
  refold pipeline's Prepared alongside the body
- relay.ts adopts both after a successful retry (failed retries unchanged);
  the #1884 lone-surrogate scrub still applies to the returned body
- regression test in tests/issue1195-overflow-refold.test.ts: overflow ->
  summary -> accepted folded retry emitting compress(invalid refs) ->
  internal continuation must carry the folded summary + tail, not the
  pre-refold markers
@ranxianglei
ranxianglei force-pushed the 2026-10-11_overflow-refold-prepared branch from 19061fd to 093d41a Compare October 11, 2026 12:38
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 Review 完成 — 可合并(wire 相邻变更,按 §7.4 由人工合并)。分支已 rebase 到当前 master(e7b94a2),新 head 093d41a18,全部 12 个 CI workflow 绿(含 Windows 矩阵与真实 codex e2e——作者本地跑不了的那条,CI 已覆盖通过)。

结构化八问:

  1. 是什么问题:一次被接受的 overflow refold 之后,内部工具循环的后续请求仍从 refold 之前的旧 Prepared 视图重建消息体——折叠没生效在循环里,上游再次 context overflow。
  2. 什么原因导致的:绑定层契约缺口。overflowRefold 回调只返回 body,而回调内对 pendingForward.* 的变更并不别名进 forward() 的局部 prepared 参数;内部压缩循环(relay.ts:1400-1408)正是从这个局部绑定取 coreMessages。叠加 core.ts:1233-1236 只在非 FAILED 压缩结果后刷新 fold 视图——模型引用了旧视图里的失效 ref 导致 compress FAILED 时,种子视图就永久停在 refold 前的超大视图。我在代码层面逐点核实过这条因果链(issue 诊断准确,是根因不是症状)。
  3. 影响范围与严重程度:特定条件触发——同一请求内发生「stated-window overflow 400 → 接受折中重试 → 同轮内出现一次 FAILED compress」三者叠加时,续传请求重发原始超大视图,用户表现为该轮再次失败。自 0.1.192 起发布的版本均受影响(Accepted overflow refold leaves stale Prepared messages in internal tool-loop continuations #2777)。非普遍路径,但命中即硬失败,非体验瑕疵。
  4. 怎么修复的:refold 流水线现在返回 { body, prepared },handle.ts 把两者一起交回;relay.ts 仅在重试被接受时同时采纳(if (refolded.prepared) prepared = refolded.prepared)——改的是「哪个视图给循环当种子」这个决策点,不是对任何 payload 做过滤/改写,属根因修复而非遮症状。失败重试路径逐字节保持现状(含 fake-completion corrective retry derives from the raw client body, bypassing wire transforms the main attempt carried #1900 的重试裁决透传)。
  5. 是否有回归问题:无。逐项清点既有行为:普通轮次(hook 仅在存在 prepared forward 时存在)、失败重试(else 分支未动,客户端看到重试裁决)、不可折叠 payload(原 400 逐字透传)、bili 改写带 body 签名的模型请求,CodeArts(华为 APIG SDK-HMAC-SHA256)全部 401 #1884 lone-surrogate scrub(仍作用于返回 body)、签名 thinking 与逐字节工具参数(未触碰任何变换路径)。A/B/C 三个既有回归用例未改动且全绿;我本地另做了定向验证:新用例在无修复的 master 代码上 FAIL(断言「续传保留摘要」不成立)、加修复后 PASS;相邻 hermetic 套件(context-overflow / e2e-overflow-selfheal / refold-wiring / issue2484-overflow-and-summary)37/37 绿。
  6. 是否破坏缓存:不涉及。缓存/重试/增量游标/去重键策略均未触碰;refold 流水线本就在 withSessionLock(session) 下运行,采纳的是同一 session 对象,前缀缓存头稳定性不受影响。
  7. 是否改了设计方向:不涉及。单一调用点(handle.ts 是唯一传 hook 的地方,其余 forward() 调用传 undefined)上的既有契约补全,无架构/边界/数据流转向。
  8. 是否引入了新的配置:无(PR 声明 config surface 不变,与 diff 一致)。

行为变更披露(旧→新):仅在被接受的 overflow refold 之后,内部工具循环续传请求的消息体改由被接受的折叠视图(fold 摘要 + 近期尾部)构成,而非 refold 前的未折叠视图。这是本修复的本意;该路径之外一切(正常轮次、失败重试、不可折叠 payload)逐字节不变。

过程备注:

@ranxianglei

Copy link
Copy Markdown
Owner Author

关闭:superseded by #2786。同一修复(accepted overflow refold 的 Prepared view 保留,#2777)已由 #2786 合并落地;本 PR 残留仅 17 行测试未随迁,由 #2786 的测试覆盖承接。(孤儿 PR 扫描)

@ranxianglei ranxianglei changed the title fix: adopt the refold pipeline's Prepared on accepted overflow refolds (#2777) [PR] fix: adopt the refold pipeline's Prepared on accepted overflow refolds (#2777) Oct 21, 2026
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.

Accepted overflow refold leaves stale Prepared messages in internal tool-loop continuations

1 participant