Skip to content

[PR] fix(reconcile): preserve edited user instructions after message ID churn - #4875

Open
j0nsh1n wants to merge 7 commits into
ranxianglei:masterfrom
j0nsh1n:2026-10-26_preserve-edited-user-text
Open

j0nsh1n wants to merge 7 commits into
ranxianglei:masterfrom
j0nsh1n:2026-10-26_preserve-edited-user-text

Conversation

@j0nsh1n

@j0nsh1n j0nsh1n commented Oct 26, 2026 •

Copy link
Copy Markdown

Why

When a client rewrites message IDs, approximate reconciliation can hide an edited user instruction behind a stale summary. Preserve corrected user text while keeping unchanged history folded.

Fixes #4874. Related #4620 offers opt-in user-message compression protection and addresses a different mechanism.

Scope

Keep role-user anchors out of approximate gap matching. In the mass-prose tier, text/user messages may match only when replacing candidate line breaks with spaces reproduces the stored normalizedIdentity. This restores the reported #3640 wrapping case without relying on word-bag or simhash similarity for user text.

Four outgoing-view regressions cover changed approval, reordered permissions, several simultaneous edits and punctuation-only edits. Another regression checks that line-wrapped user/assistant content stays folded and the next resend is quiet. The non-user order-bracket fixture now requires its exact expected claim.

Tradeoffs

This proposes a user-role exception to AGENTS.md decision 11's positional replacement tradeoff. User text that cannot be matched exactly may use more context. The user-role guard also covers tool results projected as user; the added line-wrap reconstruction is limited to text messages.

The reconstruction is conservative: it must reproduce the existing stored identity and does not promise arbitrary multiline-format equivalence. Existing exact passes, image-specific matching and non-user fallback remain in place. No new setting, metadata field, persistence version or kernel change. Compression recovery remains separate.

Verification

  • All 25 test files referencing fold-reconcile: 297 passed, 0 failed, 2 skipped because the optional solver was unavailable. Includes fold-anchor-doctrine.test.ts.
  • node node_modules/typescript/bin/tsc --noEmit --project tsconfig.json: passed.
  • npm run build: passed.
  • git diff --check: passed.
  • The new wrapping regression failed before this correction. Original changed-instruction regressions remain green.

The initial patch received independent GLM-5.3-Flash review. Grok 4.6 drafted the correction from Codex's design; Codex independently reviewed it and reran the checks. AI-assisted work by OpenAI gpt-6.1-sol and xAI Grok 4.6. Full-suite GitHub CI results are separate from these local checks.

@ranxianglei ranxianglei changed the title fix(reconcile): preserve edited user instructions after message ID churn [PR] fix(reconcile): preserve edited user instructions after message ID churn Oct 26, 2026
@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

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

查重:不重复。这是 #4874 的修复 PR,无并列的重复修复 PR;与 #4620(通过 opt-in kernel 设置阻止用户消息被压缩)相关但机制不同——#4620 是「别压缩用户消息」的配置面,#4875 是「reconcile 阶段已折叠的用户指令被改写后仍被旧摘要盖住」的账本判定问题,本 PR 不加配置、只改 reconcile 判定。

标签:bug / scope/kernel / p1(已打)。内核折叠判定面缺陷;改错的用户指令被静默吞掉 = 正确性/数据完整性问题,判 p1;行为与客户端车道无关,不打客户端标签。

核心判断:技术实现正确、测试有牙、我本地独立复跑验证过;但它主动收窄了 AGENTS.md 决策 11 里 owner 亲自批准的「顺序括号替换」折中,属产品/策略决策,合并前需要你拍板。 下面按八问给结论。

  1. 是什么问题:客户端改写消息 ID 时,reconcile 的近似匹配层(simhash / order-bracket / mass-prose)会把一条「被用户改过的指令」按它夹在两个未变邻居之间的位置认领掉,prune 后出站视图只剩旧摘要、把修正后的指令丢在模型之外——模型继续按旧指令(如 APPROVED/FORBIDDEN)行事。

  2. 什么原因导致的:根因是近似认领通道对「角色」不设防。决策 11 的 order-bracket 是为 公告:release v0.1.193 修复dsh 切模型导致上下文暴涨问题,修复fork问题,修复claude codex dsh等自动压缩导致会话破坏问题 . 另外修复几十个bug. 我本地场景有限,未必都测全,麻烦大家小场景先测试下是否有问题.任何问题及时反馈. #2821 设计的兜底:同索引 + 两侧都有已验证位置认领时,即便该格内容变了也断言占位(coverage rides the slot)。这个兜底当初没区分 assistant/tool 格和 user 指令格:对前者吞一格陈旧字节换整个会话不被单格 re-render 打崩,划算;对 user 指令吞掉的可能是刚改的授权/禁令,代价不对称。三个触发面各落一层:单词改写(word-bag 变了)被 simhash 编辑诚实门挡住后落到 order-bracket 被吞;词序重排(word-bag 相同)被 simhash 层吞;多处同时改触发 mass-prose(shape census)被吞。

  3. 影响范围与严重程度:触发条件窄但后果重——需同时满足「ID churn + 某条已折叠 user 指令被改写 + 该格落在两个已验证邻居之间(或处于 mass 事件)」,此时模型基于陈旧指令行动,属正确性/数据完整性,p1。影响所有走压缩且宿主会重写 ID 的车道(dsh 等 re-projection 最典型);字节完全不变的重放不受影响(仍走 byNorm 精确通道)。

  4. 怎么修复的:给近似层加一个 user 角色例外——gap 循环里 anchor.r === "user" 一处 continue 同时挡 simhash 与 order-bracket 两层,并在 mass-prose 的 looseProse 里 return false。精确通道(byTool/byTwin/byNorm/byTurn/byImage)、图像 textless 配对、非 user 回退全部不动。效果:改过的 user 指令不再被近似认领 → 进 unmatched → 重新上线到达模型;未变历史照常折叠。这是「疏」不是「堵」——移除的是产生误认领的机制本身,不是中途抹字节。

  5. 是否有回归问题(逐项核过既有行为):

  6. 是否破坏缓存:不影响。改动只决定哪条 user 格进 unmatched(重新上线),不动稳定前缀、不动 cache ref、不动增量游标;被保留的 user 指令本就在客户端历史里,不是新增缓存负担。

  7. 是否改了设计方向:是——这是本 PR 唯一需要你拍板的点。 它给决策 11 的「顺序括号替换折中」开了一个 role-user 例外:user 格不再享受「同索引+双侧验证就断言占位」的兜底,宁可多占上下文也不吞可能改过的指令。我的建议:批准现状。理由:①不对称代价成立——隐藏一条改过的用户指令是正确性失败,多留一行短 user 文本是 negligible 成本;②与「绝不隐藏用户意图」([bug] 插件透传会剥掉工具调用参数里的 render tag(arguments 流挂了 tag-echo 过滤器) #1039 tool-call arguments are user intent)的纪律一致;③精确通道照旧,只有「只能近似匹配到」的 user 文本才受影响,面很窄。(若要最大保守可把例外限到 contentType:"text" 的 user、排除投影成 user 的 tool-result,但那会漏掉一部分真实场景,我不推荐。)

  8. 是否引入新配置:无。纯 reconcile 判定逻辑,不加 env/config/默认值。

测试有效性:强。三个出站回归用真 reconcileFoldCoverage + 内核 prune,既断言正面(修正后的指令到达模型)又断言反面(未变 covered 消息保持折叠 + acp_summary 仍在),双向有牙、确定性、无端口/网络依赖。我本地独立复跑:PR head 上 18/18 通过;摘掉两处 guard 后恰好那 5 条(3 出站 + 2 plan 级)失败,证明它们钉住的是真 bug 而非恒真断言。一个小观察(非阻塞):新 gate 的反向(非 user 仍被 order-bracket 认领)目前只靠既有软断言兜(tests/issue2915-order-centric-reconcile.test.ts:307 允许 byOrder===1 或 unmatched 两种结果),没有硬钉;由于 guard 对非 user provably inert,这不算本 diff 的风险,只是未来防回归的加固点,可选补一条非 user 的 byOrder===1 硬断言。

CI:静态门(kernel-guard / config-surface-guard / build-artifact / gate 等)全绿;全量 test 车道(ubuntu/windows × node22/24 × shard)审查时仍在跑,未见失败,以 CI 终态为准。

收工判定:代码正确、测试可信、回归面已逐项核清,唯一门槛是第 7 问的策略收窄需你点头。你批准后即可合并;若也想顺手把上面那条非 user 反向硬断言补上,说一声我来加,或让作者补都行。

@ranxianglei ranxianglei added bug Something isn't working p1 scope/kernel labels Oct 26, 2026
Restore formatting-only mass re-anchoring by requiring the unwrapped candidate to match the stored normalized identity. Keep user messages out of approximate matching and preserve changed punctuation and instruction order. Pin the non-user order-bracket path and quiet folded resends.

Implementation drafted by Grok 4.6; design, review and verification by Codex.
@j0nsh1n

j0nsh1n commented Oct 27, 2026

Copy link
Copy Markdown
Author

(ai: openai/gpt-6.1-sol)

@ranxianglei I reproduced the #3640 regression reported on #4874. The original four-suite check missed fold-anchor-doctrine.test.ts; the broader check now includes all 25 test files referencing fold-reconcile.

Corrected in c5279e63. The gap-tier user guard remains. The mass-prose tier now accepts text/user candidates only when newline-to-space reconstruction matches the stored normalizedIdentity. No new threshold, metadata field, setting or kernel change. Non-user matching is unchanged; tool-result/reasoning user cells stay excluded from this fallback.

I avoided a tighter simhash threshold because the existing long-prefix Allow Alice; deny Bob. to Deny Alice; allow Bob. example has distance 0. The exact comparison preserves punctuation as well as word order. This is deliberately conservative and does not claim to recognize arbitrary multiline rewrites.

Added outgoing-view coverage for line-wrapped history remaining folded and a quiet next resend, plus simultaneous punctuation-only edits remaining visible. The original approval/reordered/multiple-edit regressions remain. The assistant fallback now requires byOrder === 1 and its exact expected claim, as suggested.

Independent verification of the corrected tree: 297 passed, 0 failed, 2 skipped across the 25 files; the skips require an unavailable optional solver. Typecheck, build and diff whitespace checks passed. The new wrapping regression failed before the correction. Grok 4.6 wrote the bounded change; I supplied the design, reviewed it and reran verification.

Please re-review the correction. The user-role policy exception still needs your explicit approval. GitHub CI results remain separate from these local checks.

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

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

复查对象:修正提交 c5279e6(在我上轮审的 cd3510b 之上正好一个 commit,只动 src/fold-reconcile.ts 与 tests/issue2915-order-centric-reconcile.test.ts)。以下结论全部本地独立复跑验证,未照搬自述。

结论先行:修正是对的,而且比上一版更干净——它堵上了我上轮放行版本里引入的一个真实回归(line-wrap 后的 user 历史在 mass 事件里不再折叠 → 上下文膨胀 + 反复报 drift,#3640 场景),同时没有削弱对「被改过的用户指令」的保护。唯一仍卡合并的还是第 7 问:决策 11 的 user-role 例外需要你拍板。

逐项(聚焦本轮 diff 的变化):

  1. 是什么问题:两件事。①原 Edited user instructions can stay hidden behind stale summaries after message ID churn #4874 的 bug(被改的用户指令被近似认领盖住)——维持修复。②上轮那版把 mass-prose 层对 user「一刀切 return false」,副作用是仅仅换行重排、内容没变的 user 文本在 mass 事件里也折不了。本轮修的就是这个副作用。

  2. 什么原因导致的:v1 把「被编辑」和「只是重新折行」混为一谈、一律不折。修正用精确归一化身份区分:换行→空格重建后与原存储 normalizedIdentity 相等才折;真正的编辑(词/标点变化)身份必不相等、照样留在线上。

  3. 影响范围与严重程度:①这个回归本身是体验/成本类(p2 级)——内容没丢,只是没折叠 + 日志噪音,现已消除;②原 Edited user instructions can stay hidden behind stale summaries after message ID churn #4874 仍是 p1(正确性)。影响面同前:走压缩且宿主重写 ID 的车道。

  4. 怎么修复的:looseProse 的 user 分支改为「双方 contentType 都是 text 且 normalizedIdentity(text 换行转空格) === anchor.n」,长度门在此之前已生效。复用既有 normalizedIdentity(byNorm 用的同一个函数),不加新阈值/元数据/配置/内核改动,非 user 路径逐字节不动。净效果收敛成一条更清晰的原则:user 文本只在精确身份(字节或归一化)下折叠,任何一层都不走近似/模糊认领(simhash、order-bracket、mass-prose-wordbag 全挡)。

  5. 是否有回归问题(已核):

    • 本地独立复跑引用 fold-reconcile 的全部 25 个测试文件:299 通过 / 0 失败(你报的 297 通过 + 2 skip 是同一批 299,其中 2 个可选 solver 用例在我环境能跑、直接绿)。
    • 非 user 路径 provably inert(guard 对非 user 恒为 false)。
    • 「被改的 user 指令」保护仍在:新增仅标点改动(Allow Alice;→Allow Alice?)用例验证它照样可见;单词改写 / 词序重排 / 多处编辑三个原回归保留。
    • 长度门在 user 分支之前,碰撞风险与既有 byNorm 通道同级,无新增风险。
    • 高危模式排查:无语义漂移、无阈值/时序/输出格式变化、fail-fast 未变吞错。
  6. 是否破坏缓存:不影响。只决定哪条 user 格折叠/上线,不动稳定前缀、cache ref、增量游标。

  7. 是否改了设计方向:决策 11 的收窄点没变——gap 层(simhash + order-bracket)对 user 的排除维持原样,这仍是你需要显式批准的 product/policy 决策。我的建议维持:批准。理由同前(不对称代价 + 与「绝不隐藏用户意图」纪律一致);且这版把规则收敛成「user 文本只认精确身份」一句,比 v1 更好论证。mass-prose 的精化属于 Snapshot as session reconstruction: identity claim order takes priority, message hash demoted to reference signal (root- | 快照即会话重构:身份认领顺序优先,消息哈希降级为参考信号(根治 #3588/#3640 一类误判) #3641 shape-census 域,不触碰决策 11。

  8. 是否引入新配置:无。

测试有效性:强,且有牙。我做了反向验证——把 v1(cd3510b)源码换回来跑新测试,line-wrap 那条确实在 v1 上失败,证明它钉住的是真回归而非常数断言;c5279e63 上通过。你把我上轮建议的「非 user order-bracket 硬断言」落实了(软断言改成硬钉 byOrder===1 + 精确 claim),采纳到位。确定性、无端口/网络依赖。你提到 reorder 例子 simhash 距离为 0 故不改阈值——与词袋/分片行为一致,合理,我没逐位复测但不构成阻塞。

CI:镜像缓存对修正后 head 尚为空,GitHub API 配额审查时耗尽,拿不到远端 check 终态;本地全量定向面(25 文件)绿作为证据,最终以 CI 终态为准。

收工判定:修正正确、测试可信、比上一版更收敛,唯一门槛仍是第 7 问的决策 11 user-role 例外需你点头;你批准后即可合并。

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b) Merged origin/master (9b6ec23) into this PR — clean merge, zero conflicts; new head a28d32d fast-forwarded onto the PR branch (j0nsh1n:2026-10-26_preserve-edited-user-text), PR now tracks it against current master; CI in progress, no failures so far.

@ranxianglei

Copy link
Copy Markdown
Owner

🤖 Powered by ework · qwen3.8-27b

(ai: vllm-qwen/qwen3.8-27b) Re-synced: merged origin/master (44067a5) into this PR — clean merge, zero conflicts; new head d3b0e9c fast-forwarded onto the PR branch; PR now tracks it against current master, CI in progress.

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 p1 scope/kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Edited user instructions can stay hidden behind stale summaries after message ID churn

2 participants