docs: pin the truncation rule to arithmetic after Codex review
"Truncate at cap and append the ellipsis" admits both 501 and 500 total length; the two would desync test assertions from the telemetry length promise. Cap is now the total including the marker.
This commit is contained in:
@@ -62,7 +62,7 @@ class PolyGatewayError(Exception):
|
|||||||
|
|
||||||
| 函数 | 职责 | 关键防御 |
|
| 函数 | 职责 | 关键防御 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `summarize_body(text) -> str` | 折叠空白 → 截断至 `_ERROR_BODY_CAP` → 被截时补 `…` | 空/空白入参返回 `""` |
|
| `summarize_body(text) -> str` | 折叠空白 → 按 §3.4 的机械规则截断 | 空/空白入参返回 `""` |
|
||||||
| `response_body(response) -> str` | 从 `httpx.Response` 取已缓冲文本 | `ResponseNotRead` → 返回 `""`,**绝不触发网络读** |
|
| `response_body(response) -> str` | 从 `httpx.Response` 取已缓冲文本 | `ResponseNotRead` → 返回 `""`,**绝不触发网络读** |
|
||||||
|
|
||||||
- **折叠空白不是洁癖**:错误体常是缩进 JSON,直接拼进 message 会让一行日志炸成多行、遥测列不可读。
|
- **折叠空白不是洁癖**:错误体常是缩进 JSON,直接拼进 message 会让一行日志炸成多行、遥测列不可读。
|
||||||
@@ -90,7 +90,11 @@ message 形态:`"{源名} {标签}: {状态码} | {摘要}"`;**摘要为空时
|
|||||||
|
|
||||||
### 3.4 常量取值
|
### 3.4 常量取值
|
||||||
|
|
||||||
`_ERROR_BODY_CAP = 500`。Issue 给出的真实样本约 160 字符;既有遥测文本截断常量是 200(`embedding.py:72`、`ocr.py:72`),对错误体偏紧(会切掉稍长的 `error.message`)。500 能容下绝大多数网关错误体,最坏情形(5xx 重试 3 次)每次调用向遥测多写约 1.5KB,`TEXT` 列可承受。
|
**机械规则(实现与测试逐字照此)**:`_ERROR_BODY_CAP = 500` 是**最终摘要的总长度上限**,含截断标记。折叠空白后长度 ≤ 500 则原样返回;超出则取前 **499** 字符并追加 `…`,总长恰为 500。
|
||||||
|
|
||||||
|
> 这条必须写成算术而非叙述:`text[:500] + "…"`(501)与 `text[:499] + "…"`(500)都能被"截断至 cap 并补 `…`"这句话涵盖,而两者会让测试断言与遥测长度承诺对不上(Codex 审查 2026-08-16 提出)。
|
||||||
|
|
||||||
|
取值理由:Issue 给出的真实样本约 160 字符;既有遥测文本截断常量是 200(`embedding.py:72`、`ocr.py:72`),对错误体偏紧(会切掉稍长的 `error.message`)。500 能容下绝大多数网关错误体,最坏情形(5xx 重试 3 次)每次调用向遥测多写约 1.5KB,`TEXT` 列可承受。
|
||||||
|
|
||||||
message 与 `body_text` **共用同一变量**,不设两个长度:两份不同长度会让"遥测里看到的"与"下游 catch 到的"对不上,排查时反而多一层困惑。
|
message 与 `body_text` **共用同一变量**,不设两个长度:两份不同长度会让"遥测里看到的"与"下游 catch 到的"对不上,排查时反而多一层困惑。
|
||||||
|
|
||||||
@@ -118,7 +122,7 @@ message 与 `body_text` **共用同一变量**,不设两个长度:两份不同
|
|||||||
|
|
||||||
### 4.3 幂等与重复
|
### 4.3 幂等与重复
|
||||||
|
|
||||||
纯函数,同输入同输出;`summarize_body` 对已摘要文本再摘要是幂等的(长度已 ≤ cap)。
|
纯函数,同输入同输出。`summarize_body` 对自身输出再调用一次是幂等的:输出总长恒 ≤ 500(§3.4)且不含需折叠的空白,第二次调用走"原样返回"分支,不会出现 `…` 被反复追加。
|
||||||
|
|
||||||
### 4.4 持久化与原子性
|
### 4.4 持久化与原子性
|
||||||
|
|
||||||
@@ -184,7 +188,8 @@ Issue 的中转 400 场景确实指向这个方向,但当前只有一个使用
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 1 | **端到端遥测**:mock transport 返回 400 + 真实样本体 → 断言 recorder 收到的 `error` 含摘要 | G1 |
|
| 1 | **端到端遥测**:mock transport 返回 400 + 真实样本体 → 断言 recorder 收到的 `error` 含摘要 | G1 |
|
||||||
| 2 | 参数化状态码(400 / 401 / 404 兜底 / 429 普通 / 429 `insufficient_quota` / 500)→ 断言 message 含摘要且 `exc.body_text` 非空,**分类与既有断言逐一不变** | G2, G4 |
|
| 2 | 参数化状态码(400 / 401 / 404 兜底 / 429 普通 / 429 `insufficient_quota` / 500)→ 断言 message 含摘要且 `exc.body_text` 非空,**分类与既有断言逐一不变** | G2, G4 |
|
||||||
| 3 | 超长体 → 截断至 cap 且以 `…` 结尾;`body_text` 与 message 中的摘要**逐字相同** | G3 |
|
| 3 | 超长体 → `len(summary) == 500` 且以 `…` 结尾,前 499 字符与原文前 499 字符逐字相同;`body_text` 与 message 中的摘要逐字相同 | G3 |
|
||||||
|
| 3b | 长度恰为 500 / 501 的体 → 前者原样不带 `…`,后者截为 500 带 `…`(边界) | §3.4 |
|
||||||
| 4 | 多行缩进 JSON → 折叠为单行 | G3 |
|
| 4 | 多行缩进 JSON → 折叠为单行 | G3 |
|
||||||
| 5 | 空体 / 纯空白体 → 不拼悬空分隔符,`body_text == ""` | §3.3 |
|
| 5 | 空体 / 纯空白体 → 不拼悬空分隔符,`body_text == ""` | §3.3 |
|
||||||
| 6 | 非 JSON 体、非 UTF-8 字节 → 不抛异常,分类不变 | §4.2 |
|
| 6 | 非 JSON 体、非 UTF-8 字节 → 不抛异常,分类不变 | §4.2 |
|
||||||
|
|||||||
Reference in New Issue
Block a user