Skip to content

[PR] fix(kernel): stub plain-text line-form compress calls in consumed-call cleanup (#3975) - #4032

Open
ranxianglei wants to merge 3 commits into
masterfrom
wt-3975-ework-daemon
Open

ranxianglei wants to merge 3 commits into
masterfrom
wt-3975-ework-daemon

Conversation

@ranxianglei

@ranxianglei ranxianglei commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Closes #3975

kernel-change: the consumed-call cleanup (kernel/src/hide-consumed.ts) cannot parse the plain-text line-form content that the compress tool itself accepts (parseLineEntry); the host side cannot fix this without duplicating the line-form parser in a second location (format-drift risk — the #3780 precedent already locates the shared home for this decode in the kernel). Issue #3975 is the dedicated issue naming the kernel root cause.

Rebased onto current master (incl. #3769, which replaced the old keep-last-two orphan rotation with the fold-gated sweep); tests adapted to the current semantics, end-state guarantees unchanged.

What breaks today

parseCallText understood object-array content and stringified JSON arrays only. A plain-text line-form content string (first line m00100–m00120 topic, remaining lines the summary) resolved to no quoted ranges, so such calls mis-resolved as orphans: on quiet turns they stayed visible unstubbbed — retaining their full summary text forever alongside the kernel acp_summary — and on fold turns they were swept as failure residue although they ARE the folded block's summary carrier (#1567). Measured in the reporter's snapshot: 2 of 15 mcp__bili__compress calls unsimplified (~2.68K tokens args, ~2.54K redundant full-text overlap across 10 active blocks).

The same mechanism also kept bare-name proxy-lane line-form calls at full length forever (id-matched fate always keeps; the rewrite returned null pre-fix).

Fix

Reuse the tool's own acceptance ladder instead of a second reader:

  • parse-compress-input.ts: new exported parseLineContent(content) — stripJsonWrapperResidue → splitLineEntries → parseLineEntry, i.e. exactly what the compress tool accepts when content is not a JSON array. Unparsable entries keep source/header only and never claim a range.
  • hide-consumed.ts: string content whose inner JSON value is not an array (or fails to parse) flows through parseLineContent; quoted-range keys use the normalized refs (aligning with how line-form specs store block refs); rewrite/compact rebuild the line form with headers verbatim and long summaries stubbed to 200 chars, re-emitting the full args object with the string shape preserved (fix: persistent overlay homes for pi/omp/hermes launchers (session history loss) #230 convention). Garbage/refless strings stay byte-identical.

Line-form calls now resolve active/inactive by range exactly like object-array calls and get stubbed identically; on fold turns they are fate=active and therefore exempt from the #3769 sweep, while true orphans are still swept at/after the fold start.

Behavior change (old → new)

Surface Old New
Rendered args of a line-form compress call with long summaries full text retained forever (both MCP lane and bare-name proxy lane) long summaries stubbed to 200 chars, header lines verbatim — identical end state to object-array calls
Fate of line-form calls always orphan (full text visible on quiet turns; swept as failure residue on folds despite being the block's carrier) active/inactive by quoted range; quiet-turn orphans still visible but stubbed
Kernel acp_summary retention for these blocks unchanged (anchor stays the sole complete carrier) unchanged — deliberately NOT extended: post-stub args are not a complete carrier, so stripping the anchor would lose the full text (issue expectation #3)

Object-array, stringified-array, and garbage paths are regression-pinned unchanged.

Config surface

None — no config/env/CLI changes.

Tests

@ranxianglei ranxianglei changed the title fix(kernel): stub plain-text line-form compress calls in consumed-call cleanup (#3975) [PR] fix(kernel): stub plain-text line-form compress calls in consumed-call cleanup (#3975) Oct 20, 2026
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: wt-3975-ework-daemon (cedd2a4)

Option A — Install this exact build (recommended)

npm install -g billion-context@0.0.4817-pr.4032.1512ad8

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-pr4032.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)

查重:不重复。 本 PR 是 #3975 的专属修复 PR(Closes #3975)。相邻条目核对:#3785(line-form 双重转义换行打捞,已合)改的是解析入口的容错,不是 consumed-call 清理;#2970/#2977(MCP compress 路由进清理层)、#3769/#3784(orphan 清扫门控)是本 PR 依赖的既有机制而非平行修复;#4311(摘要双份保留,已关)与本 PR 同症状家族但指向的是载体去重边界,PR 已按该边界刻意不扩大 carrier 索引。无并列的同机制在途 PR。

标签:pr + bug + scope/kernel + p2(缺陷类;根因与改动都在 kernel 的 consumed-call 清理面;能用但有冗余驻留、有绕行——p2;MCP shim 为多宿主共用面,不打具体客户端标签)。

开始独立审核(不照抄 #3975 线程结论):拉分支通读 diff、清点触碰路径的既有行为、本地定向跑新增测试与相关套件、核对 CI。另注意到 PR head 相对当前 master 显示 merge conflict(master 已推进约 3 天),审核中一并处理 rebase。结论随后按八问回复。

@ranxianglei ranxianglei added bug Something isn't working p2 scope/kernel labels Oct 23, 2026
awork added 3 commits October 23, 2026 13:46
…anup (#3975)

parseCallText only understood object-array content (and stringified JSON
arrays), so a plain-text line-form content string — which the compress tool
itself accepts via parseLineEntry — resolved to no quoted ranges. Such calls
mis-resolved as orphans and rode the keep-last-two orphan window UNSTUBBED,
retaining their full summary text forever alongside the kernel acp_summary.

Reuse the tool's own acceptance ladder: export parseLineContent from
parse-compress-input.ts (stripJsonWrapperResidue -> splitLineEntries ->
parseLineEntry) so hide-consumed resolves ranges from exactly what the tool
accepts instead of a second hand-rolled reader. Line-form calls now resolve
active/inactive by range like object-array calls, get their long summaries
stubbed to 200 chars with headers re-emitted verbatim, and free their orphan
window slots for genuinely failed calls. Unparsable/garbage strings stay
byte-identical (no refs claimed, no rewrite).

kernel/package.json 0.0.147 -> 0.0.148 (CI kernel-guard).
Host-level regression for the issue's expectations 2-3: after
hideConsumedCompressCalls + stripKernelSummaries, a plain-text mcp__bili__compress
call ends stubbed while its acp_summary anchor stays byte-complete as the sole
full carrier — guarding against future buildCarrierIndex over-widening that
would strip the anchor off stubbed args. Parity pin: object-array end state
unchanged.
@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 Powered by ework · qwen3.8-27b

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

PR #4032 独立复审结论(对最新 master 重读 diff 与行为,不复述 #3975 线程结论)。

已执行的动作

八问

  1. 是什么问题:compress 工具接受纯文本 line-form content(首行 m00100–m00120 主题),但 consumed-call 清理只认对象数组/字符串化数组——line-form 调用被误判孤儿:完整摘要永不被截成 200 字符,与 kernel acp_summary 长期重复占上下文;且 fold 时被当「失败残留」扫掉,尽管它正是该块摘要的 carrier。
  2. 什么原因导致的:清理层(hide-consumed 的 parseCallText)是工具的第二个读取器,没有复用工具自己的接受阶梯(stripJsonWrapperResidue→splitLineEntries→parseLineEntry),两个读取器漂移,line-form 形状缺失。修在根上=单一解码源归 kernel(compress: literal backslash-n in string content still fails as kind=content-not-array, hiding the real missing-summary reason #3780 先例:共享解码的家在内核)。
  3. 影响范围与严重程度:所有用 line-form compress 的会话(MCP 名车道 + bare-name 代理车道均命中,后者 id-matched 也永不 stub)。报告者实测 15 次调用中 2 次未简化(~2.68K tokens args、~2.54K 重复重叠)。严重程度 p2:可用但持续冗余上下文成本,无数据丢失。注意 compress calls rejected when the summary text rides in content next to top-level startId/endId — plus U+2212 dash silently folds the wrong range #4252 之后 line-form 是 schema 唯一advertised 形状,新流量主力即此形,修复重要性相应提高。
  4. 怎么修复的:kernel 导出 parseLineContent,逐字走工具自己的接受阶梯;hide-consumed 把「内层 JSON 非数组或解析失败」的字符串内容路由给它;range key 用规范化 refs;rewrite/compact 按 line-form 重建(header 逐字、>200 字符摘要截 200、字符串形状保留,fix: persistent overlay homes for pi/omp/hermes launchers (session history loss) #230 约定);垃圾/无 ref 字符串保持字节不变。fate/sweep 逻辑本体未动,只扩展消费点。
  5. 是否有回归问题:逐项清点既有行为——对象数组/字符串化数组/垃圾路径回归钉住不变(fix: persistent overlay homes for pi/omp/hermes launchers (session history loss) #230 字符串形状约定、无 ref 垃圾字节稳定均有测试);[Bug] MCP failed compression record rotation prematurely rewrites the history prefix, triggering expensive cache recompu | [Bug] MCP 失败压缩记录轮换提前改写历史前缀,触发大额缓存重算 #3769 fold-gated sweep 语义保持(测试同时钉 carrier 豁免 + 真孤儿清扫两方向);quotesActiveBlock 不解析 line-form,判定与对象形 clamped-range 行为对称(都落到 fold 时处理),非回归;acp_summary 锚点保留刻意不扩展——stub 不是完整载体,删锚会丢全文(issue 期望 Use kernel renderTags:"text-only" + forbid tag echoing in prompt #3);无 fail-fast 变吞错,SUMMARY_STUB_CHARS=200 常量未动,无阈值/时序/输出格式漂移。两种压缩模式都过了一遍:清理层作用于重发历史,MCP/bare-name 双车道各有测试钉。
  6. 是否破坏缓存:否。重建确定性(同输入同字节,JSON.stringify 键序稳定),stub 输出是定点(新增幂等测试实证第二遍字节不变),前缀缓存稳定。
  7. 是否改了设计方向:否。方向=单一共享解码源放 kernel,与 compress: literal backslash-n in string content still fails as kind=content-not-array, hiding the real missing-summary reason #3780/[Bug] recommend/apply 对同一区间的 turn-integrity 判定永久不一致:acp_status 反复推荐的区间被 apply 侧整段拒绝(0.1.196,Range would split N turn(s) at the protected-zone boundary) #3236「判定与执行共用单一投影」同源。
  8. 是否引入新配置:无。

已知残留(不阻塞,已在 #3975 记为 checklist 项):parser 仍接受的两种 legacy flat 形状({startId,endId,summary} 无 content;{content: 摘要文本, startId, endId},#4252 后不再 advertised)cleanup 同样不解析——前者在其块 active 期间全程全文可见(从不 stub),后者下次 fold 正常被清(只是中间不 stub)。两者均先于本 PR 存在、属未 advertised 的衰减形状、无数据丢失;是否扩展 cleanup 覆盖留给 owner 决策。

判定:代码闭环、测试有牙(10+2 kernel / 2 host,含负向门)、冲突已解、本地定向证据齐。等 CI 全局门转绿后建议合并——kernel 变更属 human-only review 档,请人工合并:#4032 。CI 结果出来我再补一条确认。

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

bug Something isn't working p2 scope/kernel

Projects

None yet

1 participant