Skip to content

[PR] kernel: bridge span-safe gaps at the merge gate so mega-turn islands … - #6345

Open
guowenjie1992 wants to merge 3 commits into
ranxianglei:masterfrom
guowenjie1992:2026-11-12_megaturn-span-safe-merge-gaps
Open

guowenjie1992 wants to merge 3 commits into
ranxianglei:masterfrom
guowenjie1992:2026-11-12_megaturn-span-safe-merge-gaps

Conversation

@guowenjie1992

@guowenjie1992 guowenjie1992 commented Nov 12, 2026 •

Copy link
Copy Markdown

…survive minCompressRange (production 2026-11-09 no-ranges incident)

Production shape (acp host, 2026-11-09 night): a mega-turn with a protected-tool exchange every ~4 rounds + a mid-turn block cut mid-group fragmented the compressible surface into 3-5K-char islands. Every island sat below compress.minCompressRange (5000 chars), mergeRangesToThreshold dropped them all, recommendedRanges=[] reached the host, and the emergency lane fell back to irreversible physical pruning three times in one night — while the host's message-level diagnostic still counted 84-149 'collectible' messages. 28 spine-cut no-range diagnostics same day, other sessions.

Two independent killers, both fixed:

  1. mergeRangesToThreshold closed its batch at every index gap, so sub-gate islands could never accumulate. It now bridges across gaps buildCompressibleRanges marks span-safe (bridgeableGapBefore): protected-tool exchanges (apply carves them via filterProtectedToolMessages, 'Bug 39') and integrity-withdrawn members (apply withdraws them again, they stay visible — Compression breaks Responses assistant history ordering, causing repeated invalid_assistant_history 400s #564 reverse-split semantics). The per-CALL 出现持续压缩失败,无法自动恢复 #847 gate sums chars over all ranges in the request, so a bridged span clears the gate each island missed. Hard gaps (blocks, carriers, media, dead refs, unrefed, soft zone — whose interior hits truncate the fold at the first protected message, [Bug] compress range straddling the protected latest user message: summary of the reply is anchored BEFORE that user message (causal order inversion) #3953) still close the batch, and sub-gate remnants still emit nothing. buildCompressibleRanges tracks gap composition (hardGapSinceCompressible) and chains it across withdrawals.

  2. Ranges ending adjacent to a mid-group block cut died at screening regardless: the pair-boundary adjustment widened the span across the coverage boundary, dragging the block in as nested/consumed, and the merge-integrity path resolved the unit to fold-nothing (fatal=null, filteredIds=0). projectUnit now clamps the ADJUSTMENT's widened head/tail at the coverage boundary (clampAdjustmentAtCoverage) — safe because covered halves are invisible to the integrity judge (Context compression leak — rose to 350k | 上下文压缩泄露 涨到 35w #5531); the requested span itself is never clamped, so refold candidates keep resolving. The clamp reuses the shared index map so the decision request: O(n²) per-turn recommend screening in acp-kernel starves the event loop on long sessions (#5304) #5337 O(units x n) discipline holds.

Observability (the incident was undiagnosable from the host side): screenRecommendedUnits warns (budgeted) for every silent drop class — fatal, empty projection, refold-guard — and the recommend node warns with stage-by-stage numbers when the funnel zeroes with material present.

Tests: tests/megaturn-protected-gap-bridging.test.ts pins the incident shape end-to-end (bridge + clamp + full-chain advertise, plus a negative for hard gaps). issue5531 closed-loop updated: the recovery block is found by coverage now that the clamp keeps the seed block active instead of dragging it into a merge. Full suite 1626/1626.

kernel-change: bridge span-safe gaps at the merge gate so mega-turn islands survive minCompressRange + clamp merge-integrity adjustment at the coverage boundary; adds regression tests; no config surface change.

…survive minCompressRange (production 2026-11-09 no-ranges incident)

Production shape (acp host, 2026-11-09 night): a mega-turn with a
protected-tool exchange every ~4 rounds + a mid-turn block cut mid-group
fragmented the compressible surface into 3-5K-char islands. Every island
sat below compress.minCompressRange (5000 chars), mergeRangesToThreshold
dropped them all, recommendedRanges=[] reached the host, and the
emergency lane fell back to irreversible physical pruning three times in
one night — while the host's message-level diagnostic still counted
84-149 'collectible' messages. 28 spine-cut no-range diagnostics same
day, other sessions.

Two independent killers, both fixed:

1. mergeRangesToThreshold closed its batch at every index gap, so
   sub-gate islands could never accumulate. It now bridges across gaps
   buildCompressibleRanges marks span-safe (bridgeableGapBefore):
   protected-tool exchanges (apply carves them via
   filterProtectedToolMessages, 'Bug 39') and integrity-withdrawn members
   (apply withdraws them again, they stay visible — ranxianglei#564 reverse-split
   semantics). The per-CALL ranxianglei#847 gate sums chars over all ranges in the
   request, so a bridged span clears the gate each island missed. Hard
   gaps (blocks, carriers, media, dead refs, unrefed, soft zone — whose
   interior hits truncate the fold at the first protected message,
   ranxianglei#3953) still close the batch, and sub-gate remnants still emit
   nothing. buildCompressibleRanges tracks gap composition
   (hardGapSinceCompressible) and chains it across withdrawals.

2. Ranges ending adjacent to a mid-group block cut died at screening
   regardless: the pair-boundary adjustment widened the span across the
   coverage boundary, dragging the block in as nested/consumed, and the
   merge-integrity path resolved the unit to fold-nothing (fatal=null,
   filteredIds=0). projectUnit now clamps the ADJUSTMENT's widened
   head/tail at the coverage boundary (clampAdjustmentAtCoverage) —
   safe because covered halves are invisible to the integrity judge
   (ranxianglei#5531); the requested span itself is never clamped, so refold
   candidates keep resolving. The clamp reuses the shared index map so
   the ranxianglei#5337 O(units x n) discipline holds.

Observability (the incident was undiagnosable from the host side):
screenRecommendedUnits warns (budgeted) for every silent drop class —
fatal, empty projection, refold-guard — and the recommend node warns
with stage-by-stage numbers when the funnel zeroes with material
present.

Tests: tests/megaturn-protected-gap-bridging.test.ts pins the incident
shape end-to-end (bridge + clamp + full-chain advertise, plus a
negative for hard gaps). issue5531 closed-loop updated: the recovery
block is found by coverage now that the clamp keeps the seed block
active instead of dragging it into a merge. Full suite 1626/1626.
@ranxianglei ranxianglei changed the title kernel: bridge span-safe gaps at the merge gate so mega-turn islands … [PR] kernel: bridge span-safe gaps at the merge gate so mega-turn islands … Nov 12, 2026
@guowenjie1992
guowenjie1992 deleted the 2026-11-12_megaturn-span-safe-merge-gaps branch November 12, 2026 04:56
@guowenjie1992
guowenjie1992 restored the 2026-11-12_megaturn-span-safe-merge-gaps branch November 12, 2026 04:56
@guowenjie1992 guowenjie1992 reopened this Nov 12, 2026
@guowenjie1992

Copy link
Copy Markdown
Author

All 3 remaining failing test jobs are pre-existing on current master, not introduced by this PR — verified locally on a clean origin/master checkout, both tests fail there with the same signature:

  • #1592 chat fold round-2 renders the next turn's shape (tests/fold-round2-shape.test.ts) — the single failure on both ubuntu shard-1 legs
  • out-of-order stamps are NOT evidence of missing history (tests/log-retention.test.ts) — the single failure on the windows shard-2 leg

Everything this PR touches is green: all guard jobs, static gates, the kernel suite (1636/1636), and the other 3,705 tests in the affected shards.

(3 个失败的 test 作业都是 master 上既有的红,不是本 PR 引入——已在干净的 origin/master 上本地复现同样失败。本 PR 触及的一切全绿。)

Happy to adjust anything per the kernel review — thanks!

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

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

查重 (dedup): the PR's mechanism (sub-gate islands dying at the merge gate) is the same family as open issue #4356 ("Small fragments below the single-fold minimum never get reclaimed"); the PR does not reference it. No dedicated issue exists for the 2026-11-09 production incident.

Thanks for the PR. I have to push back on the "pre-existing on master" claim — the evidence points the other way.

All 3 failing shards fail on one test, and that test passes on master.

  1. I pulled the logs for all three failing jobs (ubuntu 22/1, ubuntu 24/1, windows 22/2). Each has exactly one not ok: #1592 chat fold round-2 renders the next turn's shape (tests/fold-round2-shape.test.ts). There is no log-retention failure in any of the three logs — so the "windows shard-2 leg failed on out-of-order stamps (tests/log-retention.test.ts)" attribution is not supported by the CI logs for that job; its only failure is dsh 缓存失效 #1592.

  2. Local A/B/C at the exact SHAs CI used (worktrees, npm install + npm --prefix kernel run build first):

    • master tip c26c31ace4 (= the PR's merge base): node --import tsx --test tests/fold-round2-shape.test.ts → pass
    • PR head ed2926e17d: same command → fail, identical error to CI: pair 9->10 diverges at body-10 element #4/15 — mid-history rewrite
    • PR head with only kernel/src/unit-projection.ts reverted to master (keeps the bridging, drops the clamp): → pass

    So the regression is caused by clampAdjustmentAtCoverage (fix fix: address all code review findings (condense, routing, session-id, dead code) #2), not by the merge-gate bridging (fix fix: keep system prompt byte-stable for prefix cache #1). The master test lane at c26c31ace4 is also green per the CI Control Center: Centralized CI Failure Handling & Status Sync (Comment all CI issues here; do not open new issues) | CI 总控: CI 失败集中处理与状态同步(所有 CI 问题在此评论, 勿开新 issue) #4599 sentinel. (If your local origin/master was stale — a common cause — the relevant comparison is the merge base c26c31ace4, where dsh 缓存失效 #1592 passes.)

Why the clamp breaks the #1592 geometry (from a diagnostic dump of the actual wire bodies):

In the test, fold 2 requests range m00003..m00033, which overlaps fold 1's existing block coverage (m00003..m00015) — a refold candidate.

  • master: the pair-boundary adjustment widens the span across the coverage boundary, dragging the covered members in; the nested/consumed machinery consumes fold 1's block; fold 2's single summary replaces fold 1's at the original anchor (body element 3). The 9→10 divergence is inside the summary element → test passes.
  • PR head: the clamp trims the widening at the coverage boundary → no drag → fold 1's block is not consumed → fold 2's summary lands at element 4 while fold 1's summary survives at element 3: two stacked summaries, the second fully subsuming the first. The divergence is at element feat: OpenAI Responses API support (/v1/responses) #4 — mid-history, neither the summary element nor a trailing volatile slot → test fails.

Consequence beyond the test: the consuming machinery is exactly what the clamp disabled, so a subsumed block (fold 1) stays alive indefinitely. In long sessions with repeated refolds, redundant subsumed summaries accumulate — context bloat, and the model sees overlapping summaries. The #1592 invariant (a fold's re-render must match the steady path's shape) is a pinned regression for exactly this class of shape drift; the steady path never emits two stacked subsumed summaries.

So the clamp needs to handle both geometries: trim the widening so the incident geometry (range ending adjacent to a mid-group block cut) resolves, while still letting a range that overlaps an existing block consume/merge the subsumed block (preserving master's behavior for that geometry).

Other review notes (the rest is in good shape):

Verdict: blocked. Fix #1 (bridging) is sound and isolates clean; fix #2 (clamp) regresses the refold-overlap geometry and must be refined to preserve the consume-on-overlap behavior.


结构化八问

  1. 是什么问题:2026-11-09 生产事故——mega-turn 里每 ~4 轮一次受保护工具交换 + 组中块切口,把可压缩面切成 3-5K 字符孤岛,全部低于 compress.minCompressRange(5000),mergeRangesToThreshold 在索引间隙处关闭批次,孤岛永远无法累积,recommendedRanges=[] 导致应急车道一夜三次不可逆物理裁剪。
  2. 什么原因导致的:两个独立杀手——①mergeRangesToThreshold 在每个索引间隙关闭批次,跨 span-safe 间隙(受保护工具交换、integrity 撤回成员)的孤岛无法累积;②范围末端紧邻组中块切口的几何下,pair-boundary 调整把覆盖边界外的成员拖进来,merge-integrity 把单元解析成 fold-nothing(fatal=null)。
  3. 影响范围与严重程度:触发条件:mega-turn + 周期性受保护工具交换 + 组中块切口。严重度:应急车道退化为不可逆物理裁剪(数据丢失级,用户可见),p1。
  4. 怎么修复的:①buildCompressibleRanges 跟踪间隙硬度(hardGapSinceCompressible),mergeRangesToThreshold 跨 span-safe 间隙桥接(批次不关闭),硬间隙仍关闭;②projectUnit 新增 clampAdjustmentAtCoverage,在覆盖边界处钳制调整的扩张头尾(请求范围本身不钳制);③screenRecommendedUnits/recommend 节点对静默丢弃分类加预算告警。
  5. 是否有回归问题:有,确定性回归,本 PR 自引入——clampAdjustmentAtCoverage 破坏了 dsh 缓存失效 #1592 钉死的折叠重渲染形状不变量:refold 重叠几何下(新范围与既有块覆盖重叠),master 上 pair-boundary 调整拖入覆盖成员→nested/consumed 机制消费旧块→单一合并摘要;PR 上钳制阻止拖入→旧块不被消费→两条堆叠摘要(后者完全包含前者),分歧落在 body-10 元素 feat: OpenAI Responses API support (/v1/responses) #4(历史中段,既非摘要元素也非尾部易变槽)→tests/fold-round2-shape.test.ts 在 3 个 CI shard 全部失败。本地 A/B/C 隔离证实:只回退 clamp(保留桥接)该测试即通过。后果:被包含的块永久存活(消费机制正是被钳制禁用的那套),长会话重复 refold 会累积冗余堆叠摘要(上下文膨胀,模型看到重叠摘要)。
  6. 是否破坏缓存:前缀缓存本身未破坏(PR 头元素 3 不变,命中实际比 master 多延伸一个元素);但堆叠冗余摘要使后续每轮请求多携带一条被包含的摘要,长期是上下文/缓存成本的正向漂移。
  7. 是否改了设计方向:桥接部分符合 KDD refactor: reapOrphanBlocks should live in acp-kernel, not the proxy #12(资格判定与执行共用单一投影)与 Compression breaks Responses assistant history ordering, causing repeated invalid_assistant_history 400s #564 反向分裂语义,方向正确;clamp 部分改变了"覆盖重叠时旧块被消费"的既有行为,与 dsh 缓存失效 #1592 钉死的稳态形状契约冲突。
  8. 是否引入了新的配置:无新配置。新增导出 warnScreenDrop(预算 40、步长 100 的 console.warn,沿用文件内既有模式),新增 CompressibleRange.bridgeableGapBefore 字段(内部结构,非配置面)。

判定:拦下(block)。 桥接(fix #1)成立且隔离干净;clamp(fix #2)在 refold 重叠几何上造成确定性自引入回归,须细化到同时保住"覆盖重叠时消费旧块"的行为后重推。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

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

Progress report (restarted after a 35-min stall). I was handling this PR's CI red items; here's the current state and where I'm blocked. All checks below are single-shot remote reads (no local full-suite runs, no polling loops — that's what stalled me).

What I verified:

The technical problem (the clamp regression) — 八问:

  1. 是什么问题: clampAdjustmentAtCoverage(fix fix: address all code review findings (condense, routing, session-id, dead code) #2)在 refold 重叠几何下破坏了 dsh 缓存失效 #1592 钉死的折叠重渲染形状不变量——新折叠范围与既有块覆盖重叠时,钳制阻止 pair-boundary 调整拖入覆盖成员,旧块不被消费,出现两条堆叠摘要(后者完全包含前者)。
  2. 什么原因导致的: 钳制只为「范围末端紧邻组中块切口」的事故几何设计(把扩张钳在覆盖边界),却没区分「范围与既有块覆盖重叠」的 refold 候选几何——后者需要保留 master 的「拖入→消费旧块→单一合并摘要」。两种几何走了同一条钳制路径。
  3. 影响范围与严重程度: 触发条件 = 长会话中重复 refold(新范围与既有折叠块覆盖重叠)。严重度 = 被包含的旧块永久存活、冗余堆叠摘要累积(上下文膨胀 + 模型看到重叠摘要),并直接打红 3 个 CI test shard。p1。
  4. 怎么修复的: (待修)钳制需区分两种几何:事故几何 → 在覆盖边界钳制扩张头尾;refold 重叠几何 → 不钳制,保留拖入→消费旧块→单一合并摘要(master 行为)。桥接(fix fix: keep system prompt byte-stable for prefix cache #1)不受影响,保持。
  5. 是否有回归问题: 本 PR 自引入(本地 A/B/C 已证实)。修复须同时保住两种几何,避免修 A 坏 B。
  6. 是否破坏缓存: 堆叠冗余摘要使后续每轮多携带一条被包含摘要,长期是上下文/缓存成本正向漂移;前缀缓存本身未直接破坏。
  7. 是否改了设计方向: 桥接(fix fix: keep system prompt byte-stable for prefix cache #1)符合 KDD refactor: reapOrphanBlocks should live in acp-kernel, not the proxy #12/Compression breaks Responses assistant history ordering, causing repeated invalid_assistant_history 400s #564;clamp(fix fix: address all code review findings (condense, routing, session-id, dead code) #2)改变了「覆盖重叠时旧块被消费」的既有行为,与 dsh 缓存失效 #1592 稳态契约冲突,需回调到兼容两种几何。
  8. 是否引入了新的配置: 无。

Delivery blocker (🔶 needs your call): the fix is an additive commit to the PR branch, but the head branch is in the contributor's fork and the ranxianglei identity has no push access (collaborator check → HTTP 403) — the same wall as #4902 / #5777 (since 10-27). The technical fix (and its impact/regression profile above) is identical across all options — only the delivery path differs:

  • A. Author pushes the fix — the review above specifies the geometry to preserve; natural path, but depends on the external contributor (no SLA, may stall).
  • B. Grant ranxianglei collaborator access to guowenjie1992/billion-context → I push the fix as an additive commit (preserves the contributor's authorship/diff per §4). One-time, revocable.
  • C. Re-open from a ranxianglei branch — fastest to unblock but §4-discouraged (replaces a still-mergeable contribution's authorship).
  • Recommendation: B (fastest reliable path, preserves authorship); A as fallback.

Verdict: red items are triaged and root-caused (3 test shards = self-introduced clamp regression, not inherited; kernel-guard/lock-sync = cancelled, not failed). The fix is well-defined but delivery is blocked on fork push permission. I have not pushed anything; the branch is untouched. Awaiting your A/B/C call.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants