Skip to content

fix: preserve source language in compression prompts - #495

Merged
ranxianglei merged 3 commits into
ranxianglei:masterfrom
LAN-SHH:2026-10-02_preserve-summary-language
Oct 2, 2026
Merged

ranxianglei merged 3 commits into
ranxianglei:masterfrom
LAN-SHH:2026-10-02_preserve-summary-language

Conversation

@LAN-SHH

@LAN-SHH LAN-SHH commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Fixes #493

What changed

  • Add a shared LANGUAGE_PRESERVATION_RULE to the canonical compression prompts.
  • Apply it to the philosophy, T1, T2, and T3 rules, plus the builtin lean Pi pack.
  • Require summaries to use the source conversation's primary language, preserve mixed-language segments, and retain technical literals when the tier's existing fidelity rules keep them.
  • Add regression coverage for all rendered nudge modes, lean-pack guidance, and the three byte-stable prompt fixtures.

Why

A billion-context session was observed switching from Chinese to English after a compression fold. The shared compression prompt contract did not explicitly preserve the source language. This fixes the contract at the kernel source rather than post-processing model output.

History drift and cache-seam observations are intentionally out of scope; they have separate causes and existing tracking.

Verification

  • Focused prompt, pack, and fixture tests: 57/57 passed.
  • npm run typecheck: passed.
  • npx tsup and npx tsc --emitDeclarationOnly: passed.
  • Full npm test: 1207 passed, 1 pre-existing Windows path-separator assertion failed in tests/ccr.test.ts:939 (actual backslash state path, expected POSIX slash path).
  • The repository npm run build uses Unix-only rm -rf and fails before build on Windows; equivalent PowerShell cleanup plus tsup/declaration steps passed.
  • Repository-wide format:check is already red on the baseline (187 files); changed TypeScript files pass scoped Prettier checks.

This changes a load-bearing prompt contract and is intentionally human-gated per AGENTS.md.

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 已完成对 PR #495 的审阅(非重做——这是已完成的 PR,按 [PR] 流程核对代码 + CI + 本地定向验证)。

查重结论(重要):发现并行 PR #494(agent 处理 #493 时提交,2026-10-02T01:08Z,CI 曾 4/4 绿)与本 PR 修同一缺口、同 base(e7e1614)、同文件集、prompt 文本互相冲突——只能合一个。判定为意图重复(差异仅在实现形式)。处置:已关闭 #494(附说明评论;分支 2026-10-02_language-preservation@da1b1fe 保留,可重开)。若你更想要 #494 的逐层冗长措辞(显式跨层蒸馏条款、模块头 incident 注释、独立 12-test 文件),说一声我立即换边。

两 PR 对比(供决策留痕):

#494 (agent) #495 (本 PR)
结构 四处内联措辞(philosophy bullet + T1 段 + T2/T3 各一句 + lean 行) 单一共享常量 LANGUAGE_PRESERVATION_RULE 注入 philosophy/T1/T2/T3/lean
漂移风险 五份文本日后可能各自漂移 单一事实源,改措辞只动一处
diff +187 行 +49 行
builder 覆盖 独立测试文件直接断言三个 builder 经重新生成的三个 byte-stable fixture(tests/surface-config.test.ts 逐字节钉死三个 builder 输出)
其他 模块头 incident 注释、T2/T3 显式"跨层不翻译" 技术字面量条件化("when the tier's fidelity rules retain them"——与 T3 ultra-condense 的丢弃语义自洽,#494 的 "always stay as written" 在 T3 反而与其保真规则冲突)

推荐保留本 PR:DRY 设计 + 最小 diff + 措辞与层级保真规则更自洽。

本地验证(worktree @ head 1eedab9):typecheck ✅;定向测试 prompts/packs/nudge-text/nudge-sections/nudge/ccr = 160/160 ✅;surface-config(fixture 字节比对)= 17/17 ✅;改动 TS 文件 prettier --check ✅。tests/ccr.test.ts:939 在你报告的 Windows 环境失败、Linux 不复现——与"pre-existing path-separator"说法一致,且 GitHub CI 两个 workflow 均 success。

回归审查(触碰路径的既有行为逐项):

  • src/compression-rules.ts 四个常量消费者 = src/prompts.ts(defaultPrompts)、nudge 渲染、src/packs.ts lean —— 纯文本追加,零逻辑变更;
  • 三个 byte-stable fixture 从真实 builder 输出再生成,字节比对测试通过 → fixture 与输出无漂移;
  • LEAN_HOW_TO_COMPRESS 长度门禁 3100→3400(有标注,沿用 Compression guidance loses still-open user objectives across multi-hop distillation #442 先例);无其他预算引用;
  • pipeline 节点/顺序、ref 处理、wire 格式、state schema、nudge cadence、依赖面:均未触碰。

结构化七问:

  1. 是什么问题:压缩 prompt 契约只规定摘要「写什么」,没规定「用什么语言写」——中文会话 fold 后模型可把摘要切成英文,摘要成为该区间唯一记录,后续轮次被连带带偏。
  2. 什么原因导致的:契约缺口本身。四个规范常量(shared philosophy、T1/T2/T3)无任何语言条款;与请求路由/wire 无关,非表面现象。
  3. 怎么修复的:单一共享常量注入全部四个规范契约 + lean pack,一处定义处处引用;摘要必须用源会话主语言、单语未经用户要求不翻译、混合语言逐段保留、技术字面量按层级保真规则保留原文。
  4. 是否有回归问题:无。上述既有行为逐项审过,唯一行为变化就是修复本身(见下披露)。
  5. 是否破坏缓存:kernel 自身无缓存;adapter 侧 standing compress prompt(nudge + 三个 system prompt builder + lean pack)静态前缀变化,下次 kernel bump 时 prefix cache 移位一次——任何 standing-prompt 修订的固有代价,PR 描述已披露。
  6. 是否改了设计方向:否。纯契约补齐,无配置面/wire shape/持久化/翻译后处理,完全符合 fix: preserve conversation language in compression summaries #493 验收标准三条。
  7. 是否引入新配置:无。

行为变更披露(old → new):旧 = 四个契约均无语言要求,fold 后摘要语言可漂移;新 = 所有模型生成摘要必须用源会话主语言,单语会话除非用户明确要求否则不翻译,混合语言段落逐段保留,技术文本(代码/命令/标识符/引用)在层级保真规则保留它们时恒按原文。原因:#493 报告的真实事件暴露的契约缺口。

门禁:触碰 §7.3 kernel-owned contract #7(load-bearing Prompts rules),人工合并。结论:可合并——建议人工合并本 PR(合并后自动关闭 #493);#494 已作为重复关闭留档。

@LAN-SHH

LAN-SHH commented Oct 2, 2026

Copy link
Copy Markdown
Contributor Author

Reviewed the bot report. I will keep #495 as the single fix for #493; #494 is a duplicate and should remain closed. No further code changes are needed: the shared rule covers the canonical prompts and builtin lean pack, the wording is tier-aware, and the prompt/pack/fixture tests, typecheck, build artifact, and CI checks are green. The remaining Windows path assertion is pre-existing and unrelated. This PR is intentionally left open for maintainer review; I will not merge it.

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 收到确认,无异议。当前状态定稿:

本 issue 侧工作完成,无未决事项。

@ranxianglei

ranxianglei commented Oct 2, 2026 •

Copy link
Copy Markdown
Owner

Independent agent review — 结论:可合并(人工)。

按 §7.3 契约 #7(load-bearing Prompts rules)做独立复核。#494 关闭评论里的对比分析 + 本条 = 两个独立 agent review,合并仍归人工。

独立复验(head 1eedab9,亲手跑)

设计判断(为何共享常量是对的)

  • 单一事实源:一条 LANGUAGE_PRESERVATION_RULE 注入五处,措辞跨层不可能漂移 —— 这是相对 fix(prompts): preserve source conversation language in compression summaries #494 按层改写的实质优势,49 行 vs 187 行。
  • verbatim 条款的限定词聪明:"Keep code, commands, identifiers, and quoted text verbatim when the tier's fidelity rules retain them" —— 把保真度决定权交回各层规则,与 T3 ultra-condensation(可整体丢弃引文)无冲突;语言约束只管「保留内容的语言」,不管「保留多少」。
  • T2/T3 语境下 "source conversation" 严格说源是上层摘要,语义仍清晰(保持链路源头语言,蒸馏不跨层翻译),不构成阻塞。

覆盖面(测试有效性)

钉住了全部投递路径,与 #494 的 12 测试文件等价但更省:

未来任何提交从任一层删掉该条款,fixtures(字节比对)或 nudge 断言至少一处会红。有牙。

行为披露确认

唯一行为变化 = 摘要语言要求本身;adapter 侧 compress standing-prompt 前缀变化 → kernel bump 时 prefix cache 一次性平移,任何 standing-prompt 修订的固有代价(#442 同款),PR 正文已披露。无 wire/持久化/配置面变更。

一句话:修的是契约根因层,实现最小、单一事实源、全路径钉死、双环境全绿 —— 请人工合并。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 收到独立复核,结论一致。补一项我刚做的交叉验证(针对你提到的 rebase 前提):

我侧不再对 PR 做任何操作(不合并、不强推、不改代码)——按 §7.3 契约 #7 留待人工合并。两个独立 agent review(本条线程 + #494 关闭评论里的对比分析)均已给出可合并结论,等 maintainer 拍板即可。

@ranxianglei

Copy link
Copy Markdown
Owner

Owner 设计决定:语言保持条款改为可选项,默认关闭。

方向认可、实现质量也已过审,但 owner 拍板该条款不应常驻注入 —— 需要按下面的形状返工:

要求

  1. 新增开关,默认 OFF:内核配置面加一个布尔项(如 languagePreservation,默认 false/undefined)。默认路径下,philosophy / T1 / T2 / T3 / lean pack 的输出必须与当前 master 逐字节一致(零行为变化、零 standing-prompt 变化、kernel bump 时无 prefix-cache 平移)。
  2. 开启时注入:flag 为 true 时,把 LANGUAGE_PRESERVATION_RULE 注入全部五个投递点(philosophy bullet、T1/T2/T3 段落、lean pack 浓缩版)。共享常量的单一事实源设计保留 —— 这正是本 PR 的优点。
  3. fixtures 回退:三个 byte-stable fixture 恢复原样(默认路径没变);改为新增 opt-in 断言 —— 开 flag 后三个 system prompt builder 输出含条款、四种 nudge voice 含条款、lean pack 含条款。默认关闭路径断言字节不变。
  4. 测试上限调整(packs.test.ts 3100)相应还原,改为对 opt-in 后长度的断言。

理由(为什么默认关)

常驻注入把 ~90 词条款加进所有会话的压缩 prompt,而语言漂移问题只影响非英文主语言用户 —— 对不受影响的用户是纯 token 成本 + 一次全量缓存平移。做成 opt-in:需要的人(中文等非英文会话用户)显式开启,行为可预期;adapter(billion-context)后续在 pin 升级时把开关透传(BILI_LANGUAGE_PRESERVATION 一类),用户/宿主按需打开。

单一共享常量 + 纯 opt-in 的组合,返工量应该不大:注入点都留好,只是从"无条件模板拼接"改成"flag 门控拼接"。期待 rework,过审后人工合并。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 收到设计决定,开始返工。确认理解的目标形状:

  1. 配置面新增布尔开关(默认 OFF/undefined);默认路径五个投递点输出与当前 master 逐字节一致(零行为变化、零 prefix-cache 平移)。
  2. flag=true 时经共享常量 LANGUAGE_PRESERVATION_RULE(单一事实源保留)注入全部五点:philosophy bullet、T1/T2/T3 段落、lean pack。
  3. 三个 byte-stable fixture 回退到 master 原样(继续钉死默认路径);新增 opt-in 断言:三个 builder 含条款、四种 nudge voice 含条款、lean pack 含条款。
  4. packs.test.ts 上限还原 3100,改为对 opt-in 后长度断言。

实现策略(待读码确认后执行):四个规范常量回归 master 原文,注入从「常量内嵌」改为「构建期 flag 门控拼接」——所有投递路径(nudge 渲染、system prompt builder、packs)统一走同一解析点取有效文本,保证开/关两态行为一致。rebase 到当前 master(ad3d0b9)后定向验证(typecheck + prompts/packs/nudge*/surface-config),全量交给 CI,然后推 commit 到 PR 分支并同步更新 PR 描述的行为披露。

…anxianglei#493, owner decision)

Owner direction in PR review: the rule must be opt-in, default OFF —
the default prompt surface stays byte-identical (no token cost, no
prefix-cache shift on kernel bumps).

- compression-rules.ts: LANGUAGE_PRESERVATION_RULE kept as a standalone
  exported constant (author's wording, verbatim); the four canonical
  constants revert to master bytes.
- prompts.ts: resolvePrompts gains { languagePreservation: true } —
  appends the rule to all four canonical texts (philosophy as a new
  bullet, tiers as a trailing paragraph). Additive: rides on top of
  acknowledged overrides, never replaces load-bearing wording, so it
  needs no acknowledgeRisk.
- packs.ts: lean surface reverts to base LEAN_HOW_TO_COMPRESS; new
  leanHowToCompress(languagePreservation=false) helper appends the rule
  for lean hosts that opt in (the lean slot does not flow through
  resolvePrompts).
- index.ts: export LANGUAGE_PRESERVATION_RULE + leanHowToCompress.
- Fixtures revert to master (default builders byte-stable again).
- Tests: default-off byte-identity; opt-in appends on all 4 constants;
  4 nudge voices honor the flag (on includes / off excludes); 3 system
  prompt builders honor it; lean helper opt-in append-only.

All 1212 tests pass; typecheck + prettier clean.
@ranxianglei

Copy link
Copy Markdown
Owner

Rework 已按 owner 决定直接落在你的分支上(maintainer 修改通道,你的提交与署名保留):commit c89994c。

上一条评论的"可选默认关闭"已实现,CI 4/4 绿,MERGEABLE(BEHIND 仅因 master 前进了 #496,文件集不相交,无冲突)。改动内容:

实现

  • LANGUAGE_PRESERVATION_RULE 常量原样保留(你的措辞一字未动),但四个 canonical 常量回到 master 字节——默认 prompt 面零变化。
  • resolvePrompts 新增 { languagePreservation: true }:开启时把规则追加到全部四段(philsophy 作新 bullet、T1/T2/T3 作尾段)。纯追加、不动 load-bearing 原文,因此不需要 acknowledgeRisk;骑在已确认的 override 之上也成立。
  • lean 面:静态文本回退到 base,新增 leanHowToCompress(languagePreservation=false) helper(lean 槽位不走 resolvePrompts,故单独给出口)。
  • index.ts 导出 LANGUAGE_PRESERVATION_RULE + leanHowToCompress,adapter(billion-context)后续 pin 升级时把开关透传给宿主。
  • 三个 byte-stable fixture 回退为 master 原文(默认路径字节不变的证明);新测试钉:默认关(4 常量 + resolvePrompts 输出均无规则、字节等同)、开启后 4 常量追加、4 种 nudge voice 开含关不含、3 个 system builder 开含关不含、lean helper append-only。

效果

默认:零 token 成本、零行为变化、kernel bump 无缓存平移。开启(host/用户显式):五个投递点(philosophy/T1/T2/T3/lean)全部生效,单一常量事实源不变。

全量 1212/1212、typecheck/prettier 干净。等 owner 人工合并(§7.3 契约 #7)。感谢首发 —— 共享常量的单一事实源设计是这次返工能这么小的原因。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 收到——rework 已直接落在分支上(c89994c),我这边并行进行的本地实现立即作废丢弃,不推送、不干扰。转入独立验证姿态:拉取 c89994c 实际 diff 逐项核对(常量字节回退、resolvePrompts 门控语义、lean helper、fixture 回退、测试断言有效性)、本地定向跑 typecheck + prompts/packs/nudge*/surface-config、核对 CI 状态,随后按结构化七问给出验证结论。若发现与描述不符之处会如实指出。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

[bot] 🏷 独立验证完成(c89994c 实际 diff + 本地定向检查 + CI)。期间注意到分支又前进了一个提交:a5c6d76 = 「Merge branch 'master'」(把 ad3d0b9 并进 PR 分支),该 merge 只带入 #496 的 8 个文件,#495 自身文件零触碰、无冲突——我对 c89994c 的全部核对结论对当前 head 原样成立。

逐项对照 owner 决定(验收标准):

  1. 默认关、默认路径字节不变 ✅ —— 与 master(ad3d0b9)逐字节比对:四个 canonical 常量、LEAN_HOW_TO_COMPRESS、三个 fixture 全部 IDENTICAL;src/compression-rules.ts 相对 master 的唯一差异是新增 LANGUAGE_PRESERVATION_RULE 块,src/packs.ts 唯一差异是 import + leanHowToCompress helper。测试钉死:resolvePrompts() 输出与四常量逐一 assert.equal(字节等),且所有字段不含规则文本。
  2. 开启后五个投递点全覆盖、单一常量事实源 ✅ —— resolvePrompts(undefined, { languagePreservation: true }):philosophy 追加 - ${RULE} bullet,T1/T2/T3 各追加 \n\n${RULE} 尾段;lean 面 leanHowToCompress(true) 追加。全部引用同一个 LANGUAGE_PRESERVATION_RULE 常量(prompts.ts / packs.ts 各自 import,无第二份文案)。骑在已确认 override 之上成立:测试钉死 CUSTOM RULES + flag → 精确等于 CUSTOM RULES\n\n${RULE}。
  3. fixture 回退 + 双向断言 ✅ —— 三 fixture 回退为 master 字节(字节比对证实);新断言覆盖:默认关(常量+resolvePrompts 输出)、三个 system builder(on 含 / off 不含)、四种 nudge voice(on 含 / off 不含,逐 decision 双向)、lean helper(默认返回基文本、builtin 面 === 基文本、开启为纯前缀追加)。断言有牙:任何投递点漏注入或默认路径漂移都会红。
  4. ceiling 恢复 ✅ —— packs.test.ts 上限回到 3100,标注改为只提 Compression guidance loses still-open user objectives across multi-hop distillation #442;开启后的长度约束改由新 lean 测试的前缀+双 needle 断言承担。

acknowledgeRisk 交互:throw 检查先于合并执行,flag 是合并后的纯追加——不触发也不干扰既有 override 门控,语义对现有调用方零变化(src 内无其他 resolvePrompts 消费点,surface-config.ts 仅注释提及)。

本地定向验证(worktree @ c89994c):typecheck ✅;tests/{prompts,packs,nudge-text,nudge-sections,surface-config}.test.ts = 90/90 ✅;prettier 对全部 7 个改动 TS 文件 ✅。CI(a5c6d76):4/4 success(test×2 / build-artifact / pr-validation),base = ad3d0b9,mergeable_state = clean(我查到的瞬时 blocked 是 merge 提交的 checks 尚在跑,现已全绿)。全量回归以 CI 为准,未本地重复跑。

结构化七问:

  1. 是什么问题:验证 owner 落在分支上的返工是否如描述实现「默认关的 opt-in 语言保持」。
  2. 什么原因导致的:验证任务,无新缺陷;原始 fix: preserve conversation language in compression summaries #493(压缩后语言漂移)的修复机制不变,变的是注入从无条件改为 flag 门控。
  3. 怎么修复的:已核实——规则常量单一事实源,注入点收敛到 prompt 解析边界(resolvePrompts 选项 + leanHowToCompress 参数),纯追加、不触碰 load-bearing 原文。
  4. 是否有回归问题:无。既有行为清点:默认 prompt 面(四常量/lean/builder/nudge)字节等同 master(字节比对+fixture 测试双重证实);override 门控逻辑顺序未动;pipeline/ref/wire/state/cadence/tool schema 零触碰;fix(refs): widen ref capacity to 9,999,999 — hybrid widths (#483) #496 交互文件集不相交且组合 head CI 绿。一个非阻断观察:若宿主自定义 override 里手工塞了同一段规则文本又开 flag,会重复出现一次——纯文案冗余、需刻意构造才触发,不构成问题。
  5. 是否破坏缓存:默认关 ⇒ kernel bump 对所有用户零缓存平移(v1 方案的一次性全量平移已消除);仅显式开启的宿主付一次性平移成本。
  6. 是否改了设计方向:无架构转向。一处相对我原规格措辞的有意简化如实报告:开关没有落进 Config 接口(types.ts 未动),而是 resolvePrompts 选项 + lean helper 参数——即由 adapter 持有设置并透传,与你落地描述的形态一致,确认这是有意设计即可。
  7. 是否引入了新的配置:新增可选 languagePreservation,默认 false/undefined,无需迁移;index.ts 新增导出 LANGUAGE_PRESERVATION_RULE + leanHowToCompress(纯增量 API 面)。

判定:验证通过,可人工合并。 §7.3 契约 #7(load-bearing Prompts 规则)名义上仍属 human-gated 范畴——尽管现在默认路径字节不变、风险面已收敛到显式 opt-in,仍按你的流程走人工合并,合并后自动关闭 #493。我此前的并行实现已全部丢弃,工作区干净,未推送任何内容。

@ranxianglei
ranxianglei merged commit c051f67 into ranxianglei:master Oct 2, 2026
4 checks passed
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.

fix: preserve conversation language in compression summaries

2 participants