Repository navigation
[PR] fix: preflight switches to digest folds mid-flight when the LLM path cannot close the gap within budget - #5678
ranxianglei wants to merge 2 commits into
Conversation
…nnot close the gap within budget Field evidence (#5671, dsh persona sub-session, v0.1.212): a session ballooned to ~7.3x its window (5793 msgs / 24.9MiB / ~7.2M tok vs a 983k window) with a highly fragmented fold pool (1312 viable ranges, largest ~18k tok). The entry emergency trigger (#2383) only fires above 19.2x overshoot, so this payload stayed on the slow LLM path: 32 rounds x one fold each removed ~1% of the ideal per-fold mass, the 6.2M-token deficit was mathematically unclosable, and the invocation died fail-fast 413 retryable=false - after which every retry instant-413s and the session is lost forever. Add a second, budget-aware trigger point inside the round loop: when the largest summaryBudget viable ranges cannot close the remaining deficit by more than ADAPTIVE_EMERGENCY_SLACK (1.5x, covering re-fold amplification + estimator noise), flip the remainder of the invocation to the CPU-only deterministic- digest regime (#2383 mechanism, EMERGENCY_ROUND_CAP rounds). The flip is monotonic per invocation. Gated on baselineKnown exactly like the #1841 futility gate: in the unknown-baseline regime the deficit counts raw chars while range.tokens carry calibrated estimates, and mixing those scales false-positives on payloads the LLM path can actually converge. Behavior changes (disclosed in the PR): - baseline-known sessions between the coverage bound and 19.2x overshoot now get CPU-digest-quality summaries when the LLM walk is provably doomed; originals stay restorable via decompress. Previously such sessions burned up to 32 LLM calls (~minutes) and failed anyway. - pools hopeless in BOTH regimes now exit through the #1841 futility gate as deterministic exhaustion and answer 413 retryable=false instead of 502 "budget exhausted" - status-driven headless hosts stop spinning (#3461). No new config surface. Tests: new tests/preflight-adaptive-emergency.test.ts (both-directions pair per #3617); tests/preflight-round-budget.test.ts second scenario re-scoped from "LLM budget exhaustion -> 502" to "deterministic doom -> 413 non-retryable".
📦 Built Package ArtifactBranch: Latest build — install this exact versionnpm install -g billion-context@0.0.8149-pr.5678.fd02bb6This exact version is immutable and reproducible. The rolling Recent builds (commit → version)
Download artifact
tar xzf billion-context-pr5678.tgz
npm install -g packageInstall instructions are refreshed on each push. |
(ai: vllm-qwen/qwen3.8-27b) 查重: 不重复(独立核验)。open PR 里没有任何并行工作做「preflight 循环内切 digest」这件事——最接近的 #5679(storage drift 诊断)、#5676(嵌套折叠账本)机制与失败域都不同;本 PR 是 #5671「中幅超窗 + 碎片化折叠池」这个失败域的唯一实现。与 PR 正文的自查重结论一致。 标签: bug / dsh / scope/kernel / p1 —— 修的是 dsh 车道 preflight 压缩决策面的会话丢失缺陷(会话不可恢复类,按 owner 修订 2026-10-19 归 p1)。 评审进行中(PR #5678,分支
代码初判(细节随终稿):切换点位置正确(每轮 #1841 全池门之后、执行折叠之前),翻转单调(只 LLM→digest,构造上不可能反向),baselineKnown 门控与 #1841 同一纪律(未知基线制度下 deficit 用原始字符数而 range.tokens 是校准估算,混算会误杀能收敛的会话)。 |
(ai: vllm-qwen/qwen3.8-27b) PR #5678 评审结论(终稿) —— 代码、行为、测试、CI 全部独立核验完毕。 结构化八问1. 是什么问题:payload 中幅超窗(低于 19.2x 紧急阈值)且可折叠池高度碎片化时,preflight 把整个 LLM 摘要预算烧在注定无效的折叠上再 fail-fast;headless 宿主对着失败判决无限重试,会话永久死亡(现场证据 #5671:~7.3x 窗口、1312 个碎片 range、32 轮只削掉理想质量的 <1%,之后 413/重试全灭)。 2. 什么原因导致的:入口紧急触发(#2383)和 #1841 futility gate 都按「理想折叠」定价——前者比全池质量对窗口,后者比全池对 deficit;但 walker 一次调用最多只能碰 summaryBudget(≤32)个 range。池子碎片化时出现夹缝:全池质量够(#1841 不触发)、top-N 质量不够(实际走不完),两个门都不开,循环空烧数分钟 LLM 调用后才失败。病因是「资格判定用的定价口径」与「walker 实际可达性」不一致,不是预算太小。 3. 影响范围与严重程度:基线已知、payload 落在「top-N 可达质量不足」到 19.2x 之间的会话——长 dsh persona 子会话是典型形状(历史长、工具碎片多)。修复前这类会话永久不可恢复(p1 类,已按此打标);修复后同一形状 CPU-only 收敛为 digest 折叠并正常转发,原文可 decompress 找回。 4. 怎么修复的:在 round loop 内加第二个预算感知触发点——每轮执行折叠前给「真实池子」定价:最大的 summaryBudget 个 viable range 的校准质量 × 1.5(#2682 re-fold 放大 + 估算噪声 slack)仍低于 deficit ⇒ LLM 路径结构性无解,本次调用剩余部分切到确定性 digest 制度(#2383 既有机制,round cap 提到 512)。翻转单调(构造上只 LLM→digest),baselineKnown 门控与 #1841 同纪律(未知基线制度下 deficit 用原始字符数、range.tokens 是校准估算,混算会误杀能收敛的会话)。我验证了边界数学:MAX_PREFLIGHT_ROUNDS == MAX_SUMMARY_CALLS_PER_PREFLIGHT == 16,两预算恒等,「walker ≤ summaryBudget folds」的上界成立;#1841 relax 后重置的是同一上限,不受影响;relax 探针在下一轮用含保护区的超集重算,不会提前判死。 5. 是否有回归问题:无。触碰路径的既有行为逐项清点:
6. 是否破坏缓存:不涉及缓存键/去重/增量游标;压缩使 fold 点之后的前缀缓存失效是所有压缩的固有代价,digest 块走 #2383 既有格式。 7. 是否改了设计方向:没有架构转向——把 #2383 既有的双制度模型加了一个触发点,同一决策面、同一数据流。 8. 是否引入了新的配置:无。ADAPTIVE_EMERGENCY_SLACK=1.5 是内部常量,刻意不暴露 env/config(与 FUTILITY_SLACK 同待遇)。 行为变更披露(old → new,均为 PR 正文已声明、我确认成立)① 循环内 digest 切换(新增):基线已知、位于覆盖界到 19.2x 之间的会话,原先烧满至多 32 次 LLM 摘要调用(分钟级)后失败的,现在在 LLM 路径被证明无解时切 CPU-only digest 收敛并转发;原文可 decompress 恢复。 测试有效性新 e2e 是真服务器 + 真 kernel 管道 + mock upstream,双向断言有牙(#3617):C 场景若门被删/反转会因 LLM 调用出现或状态非 200 而红;D 场景若门过激会因摘要消失/digest 出现而红。round-budget 重定标(400→600 turns)合理:旧夹具恰好被本 PR 的新行为救活(钉住的就是新的预期行为),放大后双制度皆无解,继续钉 fail-fast 契约(413 + retryable=false + 零 LLM 调用)。一个非阻塞观察:1.5x 边界本身没有精确钉(两侧远端有钉),该阈值本质依赖估算器精度,不值得为此加脆弱夹具。 CI 备注12:46Z 有一次批量重触发产生重复 run(重复的被自动取消)——同一模式在其他 SHA(12:58Z)也出现,属舰队级现象、与本 PR 无关;每个 workflow 在该 head 上均有成功运行。若分支保护因某个必需 context 解析到被取消的重复 run 而显示 blocked,重跑一次 checks 即可,无需代码动作。 判定可合并——diff 最小(3 文件,每行都服务于本 PR 目的)、命名/注释符合仓库惯例、双向测试到位、本地+CI 双绿、行为变更均已披露。合并按规矩由你操作:#5678 |
…ive-emergency test
ranxianglei
left a comment
There was a problem hiding this comment.
(ai: vllm-qwen/qwen3.8-27b)
评审结论:可合并(approve)。 独立核验通过——未照抄 issue 侧既有分析,自己重读了 diff、round loop、src/server.ts 状态映射与两套测试后才下结论。(本 PR 由同一账号提交,GitHub 不允许对自己账号的 PR 提交正式 approval,故以 review comment 形式留档;合并按规矩由 owner 操作。)
结构化八问
- 是什么问题:payload 中幅超窗(低于 #2383 的 19.2x 入口阈值)且可折叠池高度碎片化时,preflight 把整个 LLM 摘要预算烧在注定补不上 deficit 的折叠上再 fail-fast;headless 宿主对着失败判决无限重试,会话永久死亡(#5671 现场:~7.3x 窗口、1312 个碎片 range、32 轮只削掉 <1%,之后 413/重试全灭)。
- 什么原因导致的:入口触发(#2383)与 #1841 futility gate 都按「理想折叠 / 全池质量」定价,但 walker 一次调用最多只能碰 summaryBudget(≤32)个 range——碎片池在此出现夹缝:全池质量够(#1841 不开)、top-N 质量不够(实际走不完),两个门都不开,空烧数分钟 LLM 调用后才失败。根因是「资格判定的定价口径」≠「walker 的实际可达性」,不是预算太小。
- 影响范围与严重程度:基线已知、落在覆盖界到 19.2x 之间且池碎片化的会话(长 dsh persona 子会话是典型形状)。修复前这类会话永久不可恢复(p1);修复后同一形状 CPU-only digest 收敛并正常转发,原文可 decompress 找回。
- 怎么修复的:round loop 内加第二个预算感知触发点——每轮执行折叠前给「真实池子」定价:最大的 summaryBudget 个 viable range 的校准质量 × ADAPTIVE_EMERGENCY_SLACK(1.5,吸收 #2682 re-fold 放大 + 估算噪声)仍 < deficit ⇒ LLM 路径结构性无解,本次调用剩余部分切到确定性 digest 制度(#2383 既有机制,round cap 提到 512)。翻转单调(构造上只 LLM→digest),baselineKnown 门控与 #1841 同一纪律。
- 是否有回归:无。逐项清点触碰路径的既有行为:
- #2383 入口触发(>19.2x 从第 0 轮 digest):代码路径未动 ✓
- #1841 futility gate + zone-relaxation 探针:未动,新门严格在其下游 ✓
- 能收敛的 payload 保 LLM 质量:新门只在「预算内完美折叠也补不上 deficit」时触发,数学上就是不可收敛集;scenario D 钉住负向(2.24x 整合池仍走 LLM、出真摘要、零 digest 产物)✓
- 未知基线制度:baselineKnown 门控,字节级不变(preflight-covered-ranges 套件绿)✓
- #2952 tier recovery 在 digest 模式排除:与入口触发的既有行为一致 ✓
- 翻转在同一轮生效已核实:digest 决策
src/preflight.ts:2954(if (emergencyFold) { ... deterministicDigest(...) })读的是 live 变量,新门src/preflight.ts:2354在其上游先翻;for (... < effectiveRoundCap)每轮重读 let,提到 512 生效。
- 是否破坏缓存:不涉及缓存键 / 去重 / 增量游标;fold 点之后的前缀失效是所有压缩的固有代价,digest 块走 #2383 既有格式。
- 是否改了设计方向:没有架构转向——给 #2383 既有的双制度模型加了一个触发点,同一决策面、同一数据流。
- 是否引入新配置:无。ADAPTIVE_EMERGENCY_SLACK=1.5 是内部常量(与 FUTILITY_SLACK 同待遇),刻意不暴露 env/config。
行为变更披露(old → new,均为 PR 正文已声明、我确认成立)
① 循环内 digest 切换(新增):基线已知、位于覆盖界到 19.2x 之间、LLM 被证无解的会话,原先烧满至多 32 次 LLM 摘要调用(分钟级)后失败 → 现切 CPU-only digest 收敛并转发;原文可 decompress 恢复。
② 确定性无解的判决:502「budget exhausted after N rounds」→ 413 retryable=false(+ #3846 local-refusal 注记)。映射已核对 src/server.ts:4478(f.kind==="exhausted" && f.deterministic && !payloadFitsWindow ? 413 : 502);headless 宿主停止空转,与 #2847/#2921/#3146 同判决类。这是有意的语义变更,非意外漂移。
测试有效性
新增 e2e 是真 server + 真 kernel 管道 + mock upstream,双向断言有牙(#3617):C 场景(碎片 ~8x)若门被删/反转会因出现 LLM 调用或状态非 200 而红;D 场景(整合 ~2.24x)若门过激会因摘要消失 / digest 出现而红。round-budget 重定标(400→600 turns)合理:旧夹具恰好被本 PR 的新行为救活(钉住的就是新的预期行为),放大后双制度皆无解,继续钉 fail-fast 契约(413 + retryable=false + 零 LLM 调用)。
顺手小修
已顺手修:tests/preflight-adaptive-emergency.test.ts:168 断言消息里的 issue 引用笔误 #5617→#5671(纯 message 字符串,零语义影响)+ commit 3c9974e6a。head 已从 57db2a4e3 移到 3c9974e6a,CI 会在新 head 上重跑。
判定
可合并——diff 最小(3 文件,每行都服务于本 PR)、命名/注释符合仓库惯例、双向测试到位、行为变更均已披露、无 kernel/ 改动(HARD RULE 不适用)。合并按规矩由你操作:#5678
(ai: vllm-qwen/qwen3.8-27b) 评审完成:PR #5678 独立核验可合并(approve)——未照抄 floor 6,自己重读了 diff、round loop、 已顺手修: |
|
(ai: vllm-qwen/qwen3.8-27b) 复审确认(新 head CI 在 结论维持:可合并(approve)。 合并按规矩由 owner 操作:#5678 |
(ai: vllm-qwen/qwen3.8-27b) 复审完成(新 head |
Closes #5671
What & why
#5671 field log (dsh persona sub-session, v0.1.212): one sub-session ballooned to ~7.3x its window (5793 msgs / 24.9 MiB / ~7.2M tok vs a 983k window) with a highly fragmented fold pool (1312 viable ranges, largest ~18k tok). Preflight's entry-time emergency trigger (#2383) only fires above 19.2x overshoot, so this payload stayed on the slow LLM path: 32 rounds x one fold each removed only ~1% of the ideal per-fold mass, the 6.2M-token deficit was mathematically unclosable, and the invocation died with fail-fast 413 retryable=false. Every subsequent retry instant-413s against the same still-growing payload - three 413s at 04:29/05:45/06:13 in the log - and the session is lost forever.
This PR adds the missing middle of the convergence model: a second, budget-aware trigger point inside the round loop. When the largest
summaryBudgetviable ranges cannot close the remaining deficit by more thanADAPTIVE_EMERGENCY_SLACK(1.5x, covering #2682 re-fold amplification + estimator noise), the remainder of the invocation flips to the existing CPU-only deterministic-digest regime (#2383 mechanism,EMERGENCY_ROUND_CAProunds). In the incident shape the flip lands in round 1 before any LLM call; fragment pools then converge in seconds instead of minutes-plus-failure.The flip is monotonic per invocation (digests never re-expand content, so the bound stays true). It is gated on
baselineKnownexactly like the #1841 futility gate: in the unknown-baseline regime the deficit counts raw chars whilerange.tokenscarry calibrated estimates, and mixing those scales false-positives on payloads the LLM path can actually converge (regression caught bypreflight-covered-ranges.test.ts).Behavior changes (old -> new)
No change to: wire format, config surface, persistence format, kernel/, updater, cache behavior.
Config surface
None.
ADAPTIVE_EMERGENCY_SLACK = 1.5is an internal constant next to the other preflight bounds; no new env var or config key.Duplicate screening
Not a duplicate (partially merged): the treadmill half of #5671 ("compressed but it won't come down" - active blocks accumulate monotonically while distillation never fires below the pressure threshold) is the same symptom+mechanism family as the compression-leak thread already tracked on the internal tracker - evidence cross-linked there (that thread holds the root-fix options, parked awaiting owner). This PR covers the NEW failure domain: mid-overshoot payloads whose fold pool is too fragmented for the LLM walk to converge within budget (searched open+closed issues/PRs for preflight 413 / fail-fast / unbounded sub-session growth - no existing thread).
Tests
tests/preflight-adaptive-emergency.test.ts- both-directions pair (Test Blind Spot Retrospective: Reinforcing Negative Assertion Discipline, Tightening Fake Upstream Strictness, Thin Inst | 测试盲区复盘:补反向断言纪律、假上游严格化、薄安装冒烟、形态矩阵与生命周期覆盖 #3617 discipline): fragmented ~8x payload (< 19.2x entry trigger) switches mid-flight -> zero summarization calls, digest blocks, forward succeeds; consolidated ~2.24x payload keeps the LLM path -> real summaries, no digests.tests/preflight-round-budget.test.ts- second scenario re-scoped: the old fixture (400 turns) is now RESCUED by the switch (digests converge under the window), which is the intended new behavior; the fixture grows to 600 turns so the pool is hopeless in both regimes, pinning the new 413/retryable=false contract (was 502 / "exhausted after 32 rounds").preflightCompress-dependent suite (276 tests) + typecheck + build. Full-suite verdict = CI on the pushed head.