From 1489aab95dcc199954d0317d3e412f9286091ab0 Mon Sep 17 00:00:00 2001 From: iomgaa Date: Sun, 16 Aug 2026 05:57:07 -0400 Subject: [PATCH] docs: add the missing imports to the plan's key interfaces Codex review: the code blocks reference httpx and PolyGatewayError, but neither module imports them today. A zero-context implementer copying them verbatim would stall on F821. --- research-wiki/graph/edges.json | 12 ++++++ research-wiki/index.md | 6 ++- research-wiki/log.md | 3 ++ ...2026-08-16-issue10-error-body-retention.md | 19 +++++++++- .../issue10-error-body-retention-plan.md | 37 +++++++++++++++++++ 5 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 research-wiki/plans/issue10-error-body-retention-plan.md diff --git a/research-wiki/graph/edges.json b/research-wiki/graph/edges.json index c4080ac..871ad31 100644 --- a/research-wiki/graph/edges.json +++ b/research-wiki/graph/edges.json @@ -155,6 +155,11 @@ "id": "design:issue10-error-body-retention", "label": "HTTP 错误响应体留存(Issue #10)", "type": "design" + }, + { + "id": "plan:issue10-error-body-retention-plan", + "label": "实现计划: HTTP 错误响应体留存(Issue #10)", + "type": "plan" } ], "links": [ @@ -276,6 +281,13 @@ "relation": "implements", "evidence": "T1-T6 实施该设计,含 §3.6 订正", "added": "2026-08-06T14:58:01.673693+00:00" + }, + { + "source": "plan:issue10-error-body-retention-plan", + "target": "design:issue10-error-body-retention", + "relation": "implements", + "evidence": "7 任务覆盖设计 G1-G4 与 §7 全部验收用例", + "added": "2026-08-16T09:50:57.830855+00:00" } ] } \ No newline at end of file diff --git a/research-wiki/index.md b/research-wiki/index.md index 3d0c734..c72c94b 100644 --- a/research-wiki/index.md +++ b/research-wiki/index.md @@ -1,6 +1,6 @@ # Research Wiki 索引 -> 自动生成,更新时间:2026-08-16 09:12 UTC +> 自动生成,更新时间:2026-08-16 09:50 UTC ## design (28) - [2026-07-20-m1-core-design](designs/2026-07-20-m1-core-design.md) `design:2026-07-20-m1-core-design` @@ -46,7 +46,7 @@ - [P7 OCR soak 验收: 99.73% 与 13 不变量全 PASS](findings/p7-ocr-soak.md) `finding:p7-ocr-soak` - [推理开关与 reasoning_tokens: 供应商实测与业界做法](findings/2026-08-02-thinking-switch-and-reasoning-tokens.md) `finding:2026-08-02-thinking-switch-and-reasoning-tokens` -## plan (21) +## plan (23) - [2026-07-20-m1-core-plan](plans/2026-07-20-m1-core-plan.md) `plan:2026-07-20-m1-core-plan` - [2026-07-20-m2-distributed-plan](plans/2026-07-20-m2-distributed-plan.md) `plan:2026-07-20-m2-distributed-plan` - [2026-07-21-m25-resilience-plan](plans/2026-07-21-m25-resilience-plan.md) `plan:2026-07-21-m25-resilience-plan` @@ -57,6 +57,7 @@ - [2026-07-31-sampling-params](plans/2026-07-31-sampling-params.md) `plan:2026-07-31-sampling-params` - [2026-08-06-governance-backend-error-plan](plans/2026-08-06-governance-backend-error-plan.md) `plan:2026-08-06-governance-backend-error-plan` - [2026-08-06-issue8-stall-budget](plans/2026-08-06-issue8-stall-budget.md) `plan:2026-08-06-issue8-stall-budget` +- [2026-08-16-issue10-error-body-retention](plans/2026-08-16-issue10-error-body-retention.md) `plan:2026-08-16-issue10-error-body-retention` - [est_tokens 解耦实施计划](plans/est-tokens-decoupling.md) `plan:est-tokens-decoupling` - [issue #8 实施计划: stall 非生产性等待口径](plans/issue8-stall-budget-plan.md) `plan:issue8-stall-budget-plan` - [M1 核心里程碑实现计划](plans/m1-core-plan.md) `plan:m1-core-plan` @@ -65,6 +66,7 @@ - [M3 OCR 实现计划](plans/m3-ocr.md) `plan:m3-ocr` - [M4 迁移实现计划(T0-T14)](plans/m4-migration.md) `plan:m4-migration` - [响应可观测字段扩展实现计划](plans/response-observability-fields.md) `plan:response-observability-fields` +- [实现计划: HTTP 错误响应体留存(Issue #10)](plans/issue10-error-body-retention-plan.md) `plan:issue10-error-body-retention-plan` - [实现计划: 治理后端故障归位为 scope 级不可用(Issue #7)](plans/governance-backend-error.md) `plan:governance-backend-error` - [推理开关能力建模与 reasoning_tokens 采集实施计划(issue #5 + #6)](plans/2026-08-02-thinking-capability.md) `plan:2026-08-02-thinking-capability` - [采样参数透传实现计划(issue #4)](plans/sampling-params-plan.md) `plan:sampling-params-plan` diff --git a/research-wiki/log.md b/research-wiki/log.md index 832c672..a83a4a9 100644 --- a/research-wiki/log.md +++ b/research-wiki/log.md @@ -99,3 +99,6 @@ - [2026-08-07 15:11 UTC] 重建索引: 62 篇页面 - [2026-08-16 09:09 UTC] 新增 design: HTTP 错误响应体留存(Issue #10) (design:issue10-error-body-retention) - [2026-08-16 09:12 UTC] 重建索引: 64 篇页面 +- [2026-08-16 09:50 UTC] 新增 plan: 实现计划: HTTP 错误响应体留存(Issue #10) (plan:issue10-error-body-retention-plan) +- [2026-08-16 09:50 UTC] 新增边: plan:issue10-error-body-retention-plan --implements--> design:issue10-error-body-retention +- [2026-08-16 09:50 UTC] 重建索引: 66 篇页面 diff --git a/research-wiki/plans/2026-08-16-issue10-error-body-retention.md b/research-wiki/plans/2026-08-16-issue10-error-body-retention.md index 20827b7..efeda27 100644 --- a/research-wiki/plans/2026-08-16-issue10-error-body-retention.md +++ b/research-wiki/plans/2026-08-16-issue10-error-body-retention.md @@ -26,6 +26,10 @@ ```python # src/polygateway/transports/_http_errors.py +from __future__ import annotations + +import httpx # response_body 的类型与 ResponseNotRead 都来自它 + _ERROR_BODY_CAP = 2048 # 字符(非字节),含省略标记在内的最终总长上限 _HEAD_CHARS = 1400 _TAIL_CHARS = 600 @@ -69,6 +73,18 @@ class PolyGatewayError(Exception): ```python # src/polygateway/transports/openai_compat.py +# 既有 errors 导入(:18-23)须补入 PolyGatewayError —— 当前只导了四个子类, +# 直接写 _classify 的返回注解会让 ruff 报 F821 未定义名。 +from polygateway.errors import ( + PolyGatewayError, # ← 新增 + RequestRejectedError, + ResultInvalidError, + SourceDeadError, + TransientError, +) +from polygateway.transports._http_errors import compose_message, summarize_body + + def _classify(status: int) -> tuple[type[PolyGatewayError], str]: """状态码 → (错误类, message 标签);映射与 1.1.2 逐条相同。""" if status in (401, 403): @@ -117,7 +133,7 @@ def _status_to_error( ### - [ ] Task 2: 共享摘要单元 -**新建**: `src/polygateway/transports/_http_errors.py`(按上文"关键接口"逐字实现,含中文模块/函数 docstring 解释**为什么**折叠空白、为什么头尾保留、为什么 `response_body` 必须降级) +**新建**: `src/polygateway/transports/_http_errors.py`(按上文"关键接口"逐字实现,**含其中的 `import httpx`**,加中文模块/函数 docstring 解释**为什么**折叠空白、为什么头尾保留、为什么 `response_body` 必须降级) **新建测试**: `tests/unit/test_http_error_body.py` @@ -155,6 +171,7 @@ resp = httpx.Response(400, stream=_Unread()) # 未 read → .text 抛 Response - `_translate_429` 签名改为 `(source, body_text, headers, ctx)`,两支 message 各自追加 `compose_message` 后缀,构造改用 `**ctx`;**`json.loads` 仍读原文 `body_text`**。 - message 主体逐字保持 1.1.2 原样(`凭据失效/欠费: {status}` / `请求被拒: 400` / `瞬时错误: {status}` / `客户端错误: {status}` / `配额耗尽(insufficient_quota)` / `限速: 429`),只在末尾追加 ` | {摘要}`。 - 三个调用点(`:402` embed、`:417` stream、`:509` 非流式)签名不变,**不改动**。 +- **补 import**:`PolyGatewayError`(errors)与 `compose_message` / `summarize_body`(`._http_errors`),见上文关键接口——漏补则 `make lint` 报 F821(Codex 审查 2026-08-16 提出)。 - **不改** `operation` 硬编码 `"chat"`(设计 §5.4 有意留给独立 issue)。 **测试**(`tests/unit/test_openai_compat.py`,沿用既有 `_transport_for(handler)` + `httpx.MockTransport`): diff --git a/research-wiki/plans/issue10-error-body-retention-plan.md b/research-wiki/plans/issue10-error-body-retention-plan.md new file mode 100644 index 0000000..a070734 --- /dev/null +++ b/research-wiki/plans/issue10-error-body-retention-plan.md @@ -0,0 +1,37 @@ +--- +type: plan +node_id: plan:issue10-error-body-retention-plan +title: "实现计划: HTTP 错误响应体留存(Issue #10)" +date: 2026-08-16 +--- + +# 实现计划: HTTP 错误响应体留存(Issue #10) + +**全文**: `plans/2026-08-16-issue10-error-body-retention.md`|**实现**: [[design:issue10-error-body-retention]]|**分支**: `feat/issue-10-error-body-retention` + +## 任务分解 + +| # | 任务 | 产出 | +|---|---|---| +| 1 | 内核字段 | `PolyGatewayError.body_text`(默认空串)+ 与 `raw_text` 的界限 docstring | +| 2 | 共享摘要单元 | 新建 `transports/_http_errors.py`:`summarize_body` / `compose_message` / `response_body` | +| 3 | openai_compat 收口 | `_status_to_error` 表驱动;429 判类型仍读原文 | +| 4 | monkey_ocr 收口 | `_classify_status` 同款,含 `ResponseNotRead` 降级 | +| 5 | **端到端验收** | 400 调用后 SQLite `error` 列含摘要——本计划的硬判据 | +| 6 | 文档与版本 | 1.2.0、README pin `>=1.2,<2`、CHANGELOG、ARCHITECTURE §6.2 | +| 7 | 合并前门 | lint + 全套件 + 全新上下文 verifier | + +依赖:1‖2 → 3‖4 → 5 → 6 → 7。 + +## 计划期钉死的两条实现红线 + +1. **429 判 `insufficient_quota` 必须解析未截断原文**,不得改用摘要——摘要会破坏 JSON,超长体一旦改用摘要解析,配额耗尽的源将不再 `force_open`,把诊断改进变成治理 bug。Task 3.4 有专门回归用例。 +2. **message 主体逐字保持 1.1.2 原样**,只在末尾追加摘要后缀;状态码→分类映射逐条不变,验收要求既有分类断言零改写。 + +## 保真校验 + +不涉及 `reference/` 迁移。错误分类映射不变,保真体现为"既有分类断言全部保留"。 + +## 执行期观察 + +Task 计划提交时 pre-commit 钩子的全套件跑出现一次 `tests/e2e/test_compat_projects.py::TestGovDocOnboarding::test_call_site_shape_runs_governed` 失败,单独跑与 e2e 全目录跑(7 passed / 23.30s,每例 2-3.5s)均通过,重跑全套件亦通过 → 判为真实网关抖动,非回归。该用例正是 [[design:issue8-stall-budget]] 当年记录的三个漂移用例之一,e2e 打真实网关的固有 flaky 面仍在。