From 3105f2a7d6f90fe262dbace91297e22eaf6f5fd6 Mon Sep 17 00:00:00 2001 From: ework-agent Date: Sun, 27 Sep 2026 21:38:28 +0800 Subject: [PATCH 1/2] =?UTF-8?q?docs:=20MESSAGE-IDENTITY=20=E2=80=94=20cont?= =?UTF-8?q?ent=20hashes=20as=20the=20cross-turn=20join=20key=20(#1496)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MESSAGE-IDENTITY.md | 187 ++++++++++++++++++++++++++++++++++++++ MESSAGE-IDENTITY.zh-CN.md | 156 +++++++++++++++++++++++++++++++ README.md | 2 + README.zh-CN.md | 1 + 4 files changed, 346 insertions(+) create mode 100644 MESSAGE-IDENTITY.md create mode 100644 MESSAGE-IDENTITY.zh-CN.md diff --git a/MESSAGE-IDENTITY.md b/MESSAGE-IDENTITY.md new file mode 100644 index 000000000..1e372bf23 --- /dev/null +++ b/MESSAGE-IDENTITY.md @@ -0,0 +1,187 @@ +# Message identity: why content hashes are the cross-turn join key + +Design record settling the question posed in #1496: **can message identity be an +explicit ingress-assigned auto-increment id instead of a content-derived hash?** +Conclusion: no — message identity stays content-derived, and the question was +really about the *join key*, not the id. This is the message-granularity sibling +of SESSION-IDENTITY.md, which settles session-granularity identity. Implementation +anchors: kernel `deriveMessageId` (raw id minted from message bytes at ingress), +`session.state.messageRefs` (`byRaw`: hash → ref, `byRef`: ref → hash), ingress +alignment in `src/server.ts`, drift detection in `src/session.ts` +(`foldCoverage`, `detectUnannouncedHistoryRewrite`). + +## Principle: the question is the join key, not the id + +The ref ledger (`mNNNNN`) already IS a session-scoped auto-increment, never-reused +id — kernel contract, see AGENTS.md §2 "Kernel Contract: Message Ids Are Never +Reused". So #1496's real question is not "where do we get a stable id" but: at turn +N+1, what re-pins the persisted ledger onto the freshly re-serialized message array? + +At turn N+1 the host re-serializes its entire history from its own private storage; +bili sees a new byte sequence, never the birth of the array. The join between the +persisted ledger and the incoming array must run on a key both sides hold. Content +bytes are the only such key stable across all supported hosts × wire lanes (the five +hosts surveyed in #1496 — codex, claude-code, pi, omp, hermes — over the four lanes: +anthropic chat, openai chat, responses, google). The raw id is therefore a content +hash (`h_`, minted by the kernel from message bytes), and `byRaw` maps +hash → ref: **the hash layer is not an alternative identity, it is the per-turn join +that re-pins the incremental ledger onto the incoming array.** + +Two consequences carry over from SESSION-IDENTITY.md: + +- **Byte-exactness is load-bearing.** The id is derived from the exact bytes of the + message; any byte change yields a different id. That is the contract, not a bug. +- **The hash doubles as a change detector.** Because the id is a function of the + bytes, the moment a client edits or rewrites history (fork/regenerate/edit — + #1148/#1102/#1247) the ids change, the join breaks, and the system detects the + drift *from the break itself*: `foldCoverage` presence checks (#1195), + `detectUnannouncedHistoryRewrite` (#1001), fork adoption (#629 family). An explicit + assigned id would silently lose this signal — same id, different bytes, no alarm. + +## Handled ≠ authored ≠ stored + +Position A's core error (#1496) was conflating two arrays: the egress array (what +bili sends upstream after compression — which bili authors) and the ingress array +(what the host sends bili — which the host authors). **The join runs on the ingress +array**, and on that array the host holds authorship: + +1. The client keeps its own session storage and re-serializes the full history every + turn. +2. bili converts wire → core (kernel derives content-hash ids from the bytes in + transit) and aligns against the persisted `byRaw` ledger. +3. Anything bili marks onto an ingress message lives only in that request's memory — + it is never written back into the client's storage. Next turn the client resends + its own copy, unmarked. + +Per-host survey (all five supported hosts are "own storage + re-serialize per turn"): + +| Host | Mode | Own storage | Do our marks round-trip? | +|---|---|---|---| +| codex | proxy · responses | rollout files | only what codex itself stored — #242 proves it stores and replays its `input[].id`, and upstream 400'd on ours | +| claude-code | proxy · anthropic | JSONL transcript | no | +| pi | plugin | own sessions | only bili-minted tool results / markers | +| omp | plugin | own sessions | same | +| hermes | plugin | own sessions | same | + +Plugin mode is the one corner where position A partially holds: the agent executes +`compress` itself, so the tool call + result live inside the agent's own history and +bili-minted bytes there genuinely round-trip. But that does not remove the join need +for foreign messages (user text, non-bili tool results) — the majority of traffic. B +holds uniformly across all supported hosts; plugin mode is a bounded exception, not +a counterexample. + +## No writable id field exists on any lane + +An explicit id needs a lane with a message-level id field that (a) upstream accepts +with arbitrary values AND (b) the host stores back and replays. No lane has both: + +- **anthropic chat / openai chat**: no message-level id field at all (only + provider-minted `tool_use` / `tool_call` ids). Nothing to write. +- **Responses `input[].id`**: the field exists but is provider-namespaced — shape + validated and replay-paired by upstream: + - #242: bili minted `msg-proxy-2-<54-char upstream id>` = 66 chars > the 64-char + cap; Codex Desktop stored it in its rollout and replayed it; upstream 400'd on + every subsequent turn ("string too long … maximum length 64"). Conversation + permanently stuck until #243 remapped via `hashId()` (28 chars total) plus + ingress healing. + - #1475: renaming provider-opaque ids (`rs_*` reasoning, `fc_*` function_call) at + ingress broke Copilot (`Expected an ID that begins with 'rs'`); reasoning id ↔ + `encrypted_content` replay pairing means rename = identity break. Healing had to + be confined to bili's own `msg-proxy-*` prefix — + `sanitizeResponsesInputIds` (src/loop/adapter-responses.ts) deletes those ids + (replay the full message instead) and shortens over-long foreign ids to + `msg-fix-`; anything else passes through untouched. + - The lesson: even where a host demonstrably stores-and-replays ids (#242 proved + the round trip happens), upstream shape validation makes the field unusable as a + free-form identity stamp. **Field present ≠ writable.** +- **google**: same provider-namespace pattern. +- Embedding an id into content bytes would violate wire fidelity (the #1039 + invariant — forwarded bytes stay byte-exact). + +## Single-message bytes stable, array prefix unstable + +Position A's second premise — "prefixes never change, order is a stable criterion" — +is false in production: + +- **folds shorten the array**: bili's own folds replace covered ranges with their + summary carrier; +- **host self-compaction rewrites history**: #1001 + `detectUnannouncedHistoryRewrite` (opencode silently rewriting history on model + switch); the `REWRITE_MIN_INCOMING_TOTAL = 5` guard distinguishes true rewrites + from stub side requests (#1075); +- **fork / regenerate / edit mutate early bytes**: #1148/#1102 branch replays, + #1247 same-position rewrite; +- **side requests send short arrays**: #1307. + +What does hold is the weaker axiom: **single-message bytes are immutable while the +message lives**. That is exactly the axiom a content hash needs — nothing more. + +### Failure-mode asymmetry + +This is the decisive argument. The two join candidates fail differently: + +- **position join fails → misattribution.** Refs and compressed blocks attach to the + wrong message — silent corruption. The #1307 incident (163/163) is the production + instance; its original count guard (≤2) was a pure positional heuristic, and it + failed. +- **hash join fails → non-recognition.** The message simply isn't recognized as + known; the cost is one raw resend + ladder restart — a self-healing performance + loss, never corruption. + +A mechanism whose worst case is "slower" beats one whose worst case is "silently +wrong", every time. + +## The hash axiom's own bug was fixed by keeping the hash + +Content-derived ids have one inherent property: same bytes ⇒ same id. #1476 hit +exactly that — a resent user message collided with its earlier instance. The fix did +not retreat to positional ids; it layered instance discrimination **on top of** the +hash base: kernel #459 renumbers colliding instances (persistent `_1/_2` suffix +dimension — a kernel instance-durability contract) and #463 added `lastPassIds` echo +discrimination. Instance durability is orthogonal to "which base do ids derive +from". + +Counterpoint worth recording: the colliding message was a USER message — precisely +the class that cannot carry a persistent ingress-assigned id (user-authored, +client-stored; bili never sees it being born). Under explicit ids, user/foreign +messages would still fall back to content hashes anyway. + +## Tags are derived views, not identity + +Render tags (`mNNNNN`) are a projection of the ledger into +visible text: rendered at egress, stripped at ingress, idempotent under re-render. +The tag-echo incidents (#206, #14, #673) prove the marker-into-storage channel is +real but dirty: models imitate tags in visible output (including typo'd names, +#673), clients replay the echoed tags, and the imitation amplifies. The repair lives +on the egress side — src/loop/tag-echo-filter.ts strips tag-shaped spans from model +prose only, forwarding tool-call arguments byte-exact (#1039 invariant). If tags were +identity, stripping them would destroy identity; the fact that they can be stripped +safely is exactly why they are views, not carriers. + +## strict-echo reasoning: the one upstream-mandated content round-trip + +Some upstreams (DeepSeek thinking mode, #684; history #762/#1479/#1482) reject +requests unless reasoning content round-trips paired with tool calls — a mandate to +preserve specific content bytes verbatim across turns. This is the only lane where an +upstream requires content round-tripping, and it is handled as a **repairable shape +constraint, never as identity**: `isStrictReasoningEcho` gates per session/upstream/ +model (src/strict-echo.ts), `normalizeStrictEchoReasoning` repairs split-turn +signatures, and the fallback drops reasoning wholesale rather than half-preserving it +(`reasoning-pair-violated` warning, src/server.ts). The identity machinery neither +reads nor depends on these bytes. + +## Future rule + +If a genuinely stable client-side message id ever appears — a protocol field that +upstream accepts AND hosts store back (see the lane survey above) — it may join as an +**additional hint** at best (disambiguation, faster adoption, debuggability). It +never replaces the hash base. This mirrors SESSION-IDENTITY.md's future direction: +client-side signals narrow the search; the byte-exact hash stays ground truth. Any +proposal to swap the base must first answer the four questions this document settles: +who authors the ingress array, which lane carries the id, what is the failure mode, +and what happens to user-authored messages. + +Related: SESSION-IDENTITY.md (session granularity) · #1496 (design review settled +here) · #1476 / kernel #459 / kernel #463 (collision + instance discrimination) · +#242 / #1475 (Responses id namespace) · #1307 (positional heuristic failure) · +#206 / #14 / #673 (tag echo) · #684 (strict echo) · #1039 (wire fidelity). diff --git a/MESSAGE-IDENTITY.zh-CN.md b/MESSAGE-IDENTITY.zh-CN.md new file mode 100644 index 000000000..f28523eab --- /dev/null +++ b/MESSAGE-IDENTITY.zh-CN.md @@ -0,0 +1,156 @@ +# 消息身份:为什么 content-hash 是跨轮 join key + +设计记录,定案 #1496 提出的问题:**消息身份能否用入口显式自增 id 取代 +content-derived hash?** 结论:不能——消息身份保持 content-derived;而且这个问题的 +本质是 **join key**,不是 id。本文是 SESSION-IDENTITY.md(会话粒度身份)的消息粒度 +姊妹篇。实现锚点:内核 `deriveMessageId`(入站时从消息字节铸造 raw id)、 +`session.state.messageRefs`(`byRaw`:hash → ref,`byRef`:ref → hash)、 +`src/server.ts` 的入站对齐、`src/session.ts` 的漂移检测(`foldCoverage`、 +`detectUnannouncedHistoryRewrite`)。 + +## 原则:问题在 join key,不在 id + +ref 账本(`mNNNNN`)**本身**就是会话内自增、永不复用的显式 id——内核契约,见 +AGENTS.md §2「Kernel Contract: Message Ids Are Never Reused」。所以 #1496 真正的 +问题不是「去哪拿一个稳定 id」,而是:**第 N+1 轮,拿什么把持久化账本重新钉回宿主 +刚重新序列化的消息数组?** + +第 N+1 轮,宿主从自己的私有存储重新序列化完整历史;bili 看到的是一段新字节序列, +永远看不到数组的「出生」。持久账本与入站数组之间的 join,必须跑在双方都持有的 key +上。内容字节是唯一在所有支持宿主 × wire lane(#1496 逐一核查过五个宿主——codex、 +claude-code、pi、omp、hermes——跨四条 lane:anthropic chat、openai chat、responses、 +google)都稳定的 key。因此 raw id 是内容哈希(内核从消息字节铸造的 `h_`), +`byRaw` 映射 hash → ref:**hash 层不是另一种身份,而是每轮把自增账本重新钉回入站 +数组的 join。** + +两条推论从 SESSION-IDENTITY.md 继承: + +- **逐字节精确是承重契约。** id 由消息的精确字节导出;任何一个字节变化都会得到不同 + 的 id。这是契约,不是缺陷。 +- **hash 同时是变更探测器。** id 是字节的函数:客户端一旦 edit/rewrite/fork 历史 + (#1148/#1102/#1247),id 就变、join 就断,系统**从断口本身**检测到漂移: + `foldCoverage` presence 检查(#1195)、`detectUnannouncedHistoryRewrite`(#1001)、 + fork adoption(#629 一族)。换成显式分配的 id 会悄悄丢掉这个信号——同样的 id、 + 不同的字节、没有警报。 + +## 经手 ≠ 执笔 ≠ 存储 + +立场 A 的核心错误(#1496)是混淆了两个数组:出站数组(bili 压缩后发给上游的—— +bili 执笔)和入站数组(宿主发给 bili 的——宿主执笔)。**join 跑在入站数组上**,而 +在这个数组上执笔权在宿主手里: + +1. 客户端维护自有会话存储,**每轮从自己的存储重新序列化**完整历史; +2. bili 做 wire → core 转换(内核现场从字节推导 content-hash id),与持久化 + `byRaw` 账本对齐; +3. bili 打在入站消息上的任何标记只活在本次请求的内存里,**从不写回客户端存储**。 + 下一轮客户端照发它自己的原始副本,无标记。 + +逐宿主核查(五个支持宿主全部满足「自有存储 + 每轮重新序列化」): + +| 宿主 | 模式 | 自有存储 | 我们打的标记能往返吗 | +|---|---|---|---| +| codex | proxy · responses | rollout 文件 | 只回传它自己存的——#242 证明它把 `input[].id` 存进 rollout 并回传,而上游对 ours 直接 400 | +| claude-code | proxy · anthropic | JSONL transcript | 否 | +| pi | plugin | 自有会话 | 仅 bili 自铸的工具结果 / marker | +| omp | plugin | 自有会话 | 同上 | +| hermes | plugin | 自有会话 | 同上 | + +plugin 模式是立场 A 唯一部分成立的角落:agent 自己执行 `compress`,工具调用与结果 +活在 agent 自己的历史里,bili 在那里铸造的字节确实往返。但这并不消除对外来消息 +(user 文本、非 bili 工具结果——流量的大头)的 join 需求。B 在所有支持宿主上一致 +成立;plugin 模式是有界例外,不是反例。 + +## 没有任何 lane 存在可写的 id 字段 + +显式 id 需要某条 lane 提供消息级 id 字段,且同时满足:(a) 上游接受任意值; +(b) 宿主存回并回放。**没有 lane 两者兼备:** + +- **anthropic chat / openai chat**:根本没有消息级 id 字段(只有服务商铸造的 + `tool_use` / `tool_call` id)。无可写之处。 +- **Responses `input[].id`**:字段存在,但属**服务商命名空间**——上游做形状校验 + + 回放配对: + - #242:bili 铸 `msg-proxy-2-<54 字符上游 id>` = 66 字符 > 64 字符上限;Codex + Desktop 把它存进 rollout 并回传;此后上游每轮 400("string too long … maximum + length 64")。会话永久卡死,直到 #243 改用 `hashId()` 重映射(共 28 字符)+ + 入口修复。 + - #1475:入口改写服务商 opaque id(`rs_*` reasoning、`fc_*` function_call)导致 + Copilot 400(`Expected an ID that begins with 'rs'`);reasoning id ↔ + `encrypted_content` 有回放配对,改名即破坏身份。修复只能收窄到 bili 自己的 + `msg-proxy-*` 前缀——`sanitizeResponsesInputIds`(src/loop/adapter-responses.ts) + 删除这些 id(改为整条消息回放)、把超长外部 id 缩短为 `msg-fix-`,其余 + 原样通过。 + - 教训:即便某宿主确实存回并回传了 id(#242 证明往返会发生),上游形状校验仍让 + 该字段无法当自由身份戳用。**「字段存在」≠「可写」。** +- **google**:同一服务商命名空间模式。 +- 把 id 嵌进内容字节则直接违反 wire fidelity(#1039 不变量——转发的字节保持 + byte-exact)。 + +## 单条字节稳定,数组前缀不稳定 + +立场 A 的第二条前提——「前缀永不变,顺序本身就是稳定判据」——在生产中不成立: + +- **fold 缩短数组**:bili 自己的折叠把覆盖段替换为 summary carrier; +- **宿主自压缩改写历史**:#1001 `detectUnannouncedHistoryRewrite`(opencode 切模型 + 时静默改写历史);`REWRITE_MIN_INCOMING_TOTAL = 5` 守卫区分真改写与 stub 侧请求 + (#1075); +- **fork / regenerate / edit 改早期字节**:#1148/#1102 分支重放、#1247 同位置改写; +- **侧请求发短数组**:#1307。 + +真正成立的公理更弱:**单条消息在其存活期内字节不可变**。这恰好就是 content-hash +需要的全部公理——不多不少。 + +### 失败模式不对称 + +这是决定性论据。两个 join 候选的失败方式截然不同: + +- **位置 join 失败 → 认错(misattribution)**。ref 和压缩块挂到错误的消息上——静默 + 数据损坏。#1307 事故(163/163)即生产实例;其原始的计数守卫(≤2)正是纯顺序 + 启发式,失败了。 +- **hash join 失败 → 认不出(non-recognition)**。消息只是没被识别为已知;代价是一 + 次 raw 重发 + ladder 重启——自愈的性能损失,永不损坏数据。 + +最坏情况只是「变慢」的机制,永远胜过最坏情况是「悄悄出错」的机制。 + +## hash 公理自身的 bug,是靠保留 hash 修掉的 + +content-derived id 有一个固有属性:同字节 ⇒ 同 id。#1476 恰好撞上它——重发的 user +消息与其早期实例撞号。修复没有退回位置 id,而是在 hash 基座之上**叠加实例判别**: +kernel #459 给撞号实例重铸后缀(持久的 `_1/_2` 维度——内核实例耐久性契约),#463 +加入 `lastPassIds` 回声判别。实例耐久性与「id 从哪种基座派生」正交。 + +值得记录的反直觉点:撞号的是一条 USER 消息——恰恰是**无法携带持久入口自增 id** +的那一类(user 执笔、客户端存储;bili 从未见过它的出生)。换显式 id,user/外来消息 +仍只能退回 content-hash。 + +## Tag 是派生视图,不是身份 + +渲染 tag——包裹每个消息 ref(`mNNNNN`)并携带 `tokens=` / `type=` 属性的 `acp` +XML 标记——是账本在可见文本上的投影:出站渲染、入站剥离、重复渲染幂等。tag-echo +事故(#206、#14、#673)证明「标记进入存储」这条通道真实存在但很脏:模型在可见输出 +里模仿 tag(包括拼错名字,#673),客户端回放被回声的 tag,模仿不断放大。修复放在 +出站侧——src/loop/tag-echo-filter.ts 只从模型散文里剥离 tag 形状的片段,工具调用 +参数保持 byte-exact 转发(#1039 不变量)。如果 tag 是身份,剥离它就会摧毁身份; +恰恰因为可以安全剥离,才说明它是视图而非载体。 + +## strict-echo reasoning:唯一的上游强制内容往返 + +某些上游(DeepSeek thinking mode,#684;历史 #762/#1479/#1482)要求 reasoning +内容与 tool call 配对往返,否则拒绝请求——这是强制特定内容字节跨轮原样保留的 +mandate。这是唯一一条上游要求内容往返的 lane,处理方式始终是**可修复的形状约束, +绝不当身份**:`isStrictReasoningEcho` 按 session/upstream/model 门控 +(src/strict-echo.ts),`normalizeStrictEchoReasoning` 修复拆散轮次的签名,兜底策略 +是整体丢弃 reasoning 而不半留(`reasoning-pair-violated` 警告,src/server.ts)。 +身份机制既不读取也不依赖这些字节。 + +## 未来规则 + +若将来出现真正稳定的客户端消息 id——某个上游接受**且**宿主存回的协议字段(见上文 +lane 核查)——它至多作为**附加提示**参与(join 消歧、加速采纳、便于调试),**永不取代 +hash 基座**。这与 SESSION-IDENTITY.md 的未来方向一致:客户端信号缩小搜索范围, +逐字节哈希仍是 ground truth。任何提议更换基座的方案,必须先回答本文定案的四个 +问题:入站数组谁执笔、哪条 lane 承载 id、失败模式是什么、user 执笔的消息怎么办。 + +相关:SESSION-IDENTITY.md(会话粒度)· #1496(本文定案的设计复核)· #1476 / +kernel #459 / kernel #463(撞号 + 实例判别)· #242 / #1475(Responses id +命名空间)· #1307(顺序启发式失败)· #206 / #14 / #673(tag echo)· #684(strict +echo)· #1039(wire fidelity)。 diff --git a/README.md b/README.md index 6326ff6cb..84c3fc058 100644 --- a/README.md +++ b/README.md @@ -1202,6 +1202,8 @@ section used to warn about (#1262): instead of silently colliding with something else's state. Design record and threat model: [SESSION-IDENTITY.md](SESSION-IDENTITY.md). +Message-granularity identity — why message ids are content hashes, not +ingress-assigned ids (#1496): [MESSAGE-IDENTITY.md](MESSAGE-IDENTITY.md). For upstream sticky-routing, the proxy forwards only identity values the client already supplied (e.g. a body `session_id` is forwarded upstream as diff --git a/README.zh-CN.md b/README.zh-CN.md index c0ae60272..ccabb6794 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -547,6 +547,7 @@ Windows 下会自动发现常见 Clash/Mihomo 静态系统代理;Web UI 会显 - 完全没有任何可用信号时,请求会被显式 400 拒绝,而不是静默与他人状态碰撞。 设计记录与威胁模型:[SESSION-IDENTITY.md](SESSION-IDENTITY.md)。 +消息粒度身份——为什么消息 id 是内容哈希而非入口自增 id(#1496):[MESSAGE-IDENTITY.zh-CN.md](MESSAGE-IDENTITY.zh-CN.md)。 上游粘性路由方面,代理只转发客户端本来就提供的身份值(例如 body 里的 `session_id` 会以 `x-session-id` 上送),绝不自行合成一个。 From 3ba213788b278fe30fd1bccb4fc332d59093b864 Mon Sep 17 00:00:00 2001 From: ework-agent Date: Sun, 27 Sep 2026 22:27:03 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20MESSAGE-IDENTITY=20review=20?= =?UTF-8?q?=E2=80=94=20REWRITE=5FMIN=5FINCOMING=5FTOTAL=20is=2010,=20not?= =?UTF-8?q?=205=20(#1509)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- MESSAGE-IDENTITY.md | 2 +- MESSAGE-IDENTITY.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MESSAGE-IDENTITY.md b/MESSAGE-IDENTITY.md index 1e372bf23..cadf5e4ea 100644 --- a/MESSAGE-IDENTITY.md +++ b/MESSAGE-IDENTITY.md @@ -107,7 +107,7 @@ is false in production: summary carrier; - **host self-compaction rewrites history**: #1001 `detectUnannouncedHistoryRewrite` (opencode silently rewriting history on model - switch); the `REWRITE_MIN_INCOMING_TOTAL = 5` guard distinguishes true rewrites + switch); the `REWRITE_MIN_INCOMING_TOTAL = 10` guard distinguishes true rewrites from stub side requests (#1075); - **fork / regenerate / edit mutate early bytes**: #1148/#1102 branch replays, #1247 same-position rewrite; diff --git a/MESSAGE-IDENTITY.zh-CN.md b/MESSAGE-IDENTITY.zh-CN.md index f28523eab..5b9782f8f 100644 --- a/MESSAGE-IDENTITY.zh-CN.md +++ b/MESSAGE-IDENTITY.zh-CN.md @@ -91,7 +91,7 @@ plugin 模式是立场 A 唯一部分成立的角落:agent 自己执行 `compres - **fold 缩短数组**:bili 自己的折叠把覆盖段替换为 summary carrier; - **宿主自压缩改写历史**:#1001 `detectUnannouncedHistoryRewrite`(opencode 切模型 - 时静默改写历史);`REWRITE_MIN_INCOMING_TOTAL = 5` 守卫区分真改写与 stub 侧请求 + 时静默改写历史);`REWRITE_MIN_INCOMING_TOTAL = 10` 守卫区分真改写与 stub 侧请求 (#1075); - **fork / regenerate / edit 改早期字节**:#1148/#1102 分支重放、#1247 同位置改写; - **侧请求发短数组**:#1307。