diff --git a/Docs/api-client.md b/Docs/api-client.md
index 4dfb0f5..4b844eb 100644
--- a/Docs/api-client.md
+++ b/Docs/api-client.md
@@ -1,6 +1,6 @@
# Cyrene v2 客户端 API 契约
-> **契约版本:`v0.83`**(上一版 `v0.82`,其条目见 §6;`v0.81` / `v0.80` / `v0.79` / `v0.78` / `v0.77` / `v0.76` / `v0.75` / `v0.74` / `v0.73` / `v0.72` / `v0.71` 及更早见本文件 §6,`v0.67` 及更早的基线已归档、只读:`Docs/archive/api-client.v0.65.md`)。
+> **契约版本:`v0.84`**(上一版 `v0.83`,其条目见 §6;`v0.82` / `v0.81` / `v0.80` / `v0.79` / `v0.78` / `v0.77` / `v0.76` / `v0.75` / `v0.74` / `v0.73` / `v0.72` / `v0.71` 及更早见本文件 §6,`v0.67` 及更早的基线已归档、只读:`Docs/archive/api-client.v0.65.md`)。
> **读者**:Web 前端 / 移动端原生客户端(含 Android)/ IM 桥接等**跨平台客户端开发者**。
> **唯一真源 = 当前代码**(`internal/services/gateway/*` 等)。本文档由代码逐条核对得出;与代码不符时**以代码为准**,并回改本文档。
> **旧的超详细版已归档、只读**:`Docs/archive/api-client.v0.65.md`(412 KB,含 v0.28→v0.65 全部历史条目)与 `Docs/archive/api-reference.v0.65.md`(170 KB,后端全量字段级文档)。归档的原因是**结构性臃肿 + 历史条目并列 + 长期漂移**;本文档**不复制**那段历史,需要考古时去归档。
@@ -22,6 +22,8 @@
> **v0.77 是链路图按路分桶 + 记忆整理护栏/异步落地版(已实现;纯增量)**:① **`graph_update` 按路分桶**(切片 FV2)—— 帧 `data` 新增可选 `turnId`(该图的**路**的权威回合标识)与 `round`(会话轮次号);真并行(`parallel:true`)时同一会话**每一路各发自己的帧**(`data.id` / `data.turnId` 各不相同),两路不再互相顶掉;`GET /api/v1/admin/flow/graph` 响应新增 `lanes[]`(**最近一轮每一路**的图,恒为非 null 数组),`graph` 语义不变(最新一路 / 指定轮 / `null` 诚实空态)⇒ **老的读取方零改动**。**无破坏性变更**(两个新键可选;单路时 `turnId` 缺席 ⇒ 客户端行为与 v0.75 逐字相同)。详见 **§2.2 B13 / §3.4.5 / §4.11 / §7.4-19**。② **记忆整理护栏抬高 + 诚实截断 + 试算异步落地**(切片 MT-A)—— 每分区候选上限 `MEMORY_TIDY_CANDIDATE_LIMIT` 默认值 `20 → 200`、两两比对上限改为 env 键新键 `MEMORY_TIDY_COMPARE_LIMIT`(默认 `2000`,原先**写死** `400`);配置事实面 **12 → 13 条**;`truncated` 新增第 4 种标签 **`(budget)`**(墙钟时间预算截断);**v0.76 ③ 的加性异步已落地**(`?async=1` + B15 轮询可用;新错误码 **`tidy_run_not_found`**)。详见 **§2.2 B14/B15 / §4.10(a) / §4.12 / §4.12.1 / §5**。③ **「入库前审查」的 4 个 env 键登记**(切片 MT-B,纯增量)—— `MEMORY_REVIEW_ENABLED`(`true`)/ `MEMORY_REVIEW_QUEUE_SIZE`(`256`)/ `MEMORY_REVIEW_SCAN_LIMIT`(`200`)/ `MEMORY_REVIEW_TIMEOUT_SEC`(`20`);⚠️ 该切片的**面板读侧 / 回滚端点目前没有 HTTP 入口**(见 §7.2)。详见 **§5**。
+> **v0.84 是「显示名 + 段落标签硬约束」版(已实现并推库:`c46053e` 显示名 / `8051906` 段落修复 / `bc1dee3` provider 配置面去 env 化;**一处形状变更(插件动作响应)、一处新增硬约束;无破坏性变更**)**:① **`plugin.providers` 候选响应形状:裸字符串数组 → 对象数组 `{"options":[{"value": ` 或 ` = 一段`,**段落不嵌套**。修的是安卓端登记的 ` 正文 ` 显示给用户);**实测两半都是产出侧造成**:规整器**原样放过**该形状,且会在「末段漏 `
` 或 `
`。语义上:**一个 `` = 一段,段落不嵌套**。 + +**为什么写进契约**(这曾是真实纠纷):安卓端从 `GET /api/v1/sessions/web/messages` 读到过一条 `content` 形如 + +``` +
真乖♪ 这可是今天最让人家放心的一句。
+那现在——想让人家陪你看会儿晚霞,还是安静坐着发会儿呆?
+``` + +他们的解析契约 `P_BLOCK_RE =]*)?>([\s\S]*?)
` 是**非贪婪**的 ⇒ 第三段必然匹配成「外层 `` 开、内容 = `
正文`、`
` 收」⇒ **用户直接看到字面的 ``**。这不是他们解析器的口味问题:**任何按该契约定实现的消费方(Web 面板 / IM 桥 / 第三方)都会踩**。 + +**实测根因(两半都在产出侧,已修 `8051906`)**: + +1. 规整器**原样放过**该形状(分块正则非贪婪 ⇒ `
X
` 被当成「一个已完整包裹的 `` 块」逐字保留;更糟的是旧的覆盖检查用**同一非贪婪正则**,护栏本身是盲的); +2. 规整器还会**亲手制造**它:段首 `
` 未闭合(模型末段漏 `
`)时**无条件再套一层** —— 实证:模型吐 `那现在…?`(无闭标签)经旧代码规整后与上报串**逐字节相同**; +3. 顺带修掉一个**幂等漏洞**:落单 `
` 旧行为 ⇒ `正文。
`,再跑一次又变 ⇒ 越跑越多。 + +**修后的处置口径(产出侧,逐条有测试)**:`X
` ⇒ `X
`;`X`(漏闭)⇒ 补 `
`(**补闭不补开**);`正文
` ⇒ `
正文
`(合并不吞字);`A
` ⇒ `
A
`(丢空开标签、不造空气泡);`` ⇒ 整对丢;落单 `` ⇒ 丢标签、**正文不动**。 + +**🔴 客户端要做 / 不用做的**: + +- **不用做**:不必为这个畸形写特例解析器(产出侧已保证不再产出)。 +- **仍要做**:**保留**你现有的「剥落单标签」容错 —— ① **历史行不回填**(库里已经有畸形的行);② 产出链**不止一条**(渠道镜像 / 主动推送 / 后台思考各有包装点),不能假设全都干净。 +- **护栏(不许退化)**:`1 < 2`、`a`、``)、代码围栏内的 `
`、` `、自闭合 ` A\n\n B A\n\nB 正文 ` / ` 正文