--- type: plan node_id: plan:2026-10-01-issue29-openai-fidelity title: OpenAI消息保真实现计划 date: 2026-10-01 --- # #29 OpenAI 消息保真实现计划 > 状态:计划及首轮代码独审已完成,P1/P2 均采纳;缓存空产物和测试双向依赖已修复,发布目标按人类最终指定改为 1.3.9(取代未发布的 1.4.0),最终独审与 T8 外部发布仍由父会话执行。 > 设计:[批准方向的设计落实稿](../designs/2026-10-01-issue29-openai-fidelity-design.md)。 > 目标:同一 chat 治理链返回可供下游继续工具对话的完整单 choice 协议结果,拒绝截断和 error 帧伪成功。 > 方案:增加 response_mode 与嵌套 completion;协议解析与聚合内聚在 transport 内部模块,治理层仅传模式/搬结果;旧文本默认保持兼容。 > 技术:Python 3.12+、frozen dataclass、httpx SSE、现有 asyncio 看门狗/对冲、pytest、真实 Redis;不加运行时依赖。 ## 0. 工作区、审批与执行纪律 | 项目 | 已核验值 | | --- | --- | | 工作目录 | `/home/iomgaa/.config/superpowers/worktrees/PolyGateway/issue29-openai-fidelity` | | 分支 | `feat/issue29-openai-fidelity` | | 基线 | `0e29deac1a72bfee348ed2f8061ea2c33be217e8` / 1.3.8 | | 原工作区 | `/home/iomgaa/Projects/PolyGateway`,main 上已有未提交文档与 .pi,不得覆盖或夹带提交 | | 基线命令 | `conda run -n PolyGateway pytest tests/unit -q` | | 基线结果 | 1627 passed in 12.25s;仅单元基线,不代表集成/slow/新增功能通过 | 所有 Python 命令用 PolyGateway conda 环境;始终从上述隔离目录执行,确认 pytest 配置 pythonpath=src,避免误测主工作区 editable 安装。不要复制主树 `.env` 到受跟踪路径;需要真实验证时显式读取已有配置,不输出秘密。reference/ 不存在于新 worktree 的跟踪树,不为规划复制/修改参考仓。 技术方向、内部原创权属和 Apache-2.0 已获用户明确批准;细化设计与计划由独立 subagent 审查,Codex 不再调用。只在新产品/权利边界未获授权时暂停。父会话掌握审查、后续编码、合并/发布权限;当前任务不执行这些步骤。 本计划不涉及参考实现迁移,保真校验不适用;涉及既有移植流式看门狗的消费面,必须对照本库 `streaming.py`、1.3.8 stall 设计逐段保持其超时/取消/换算语义,不能借工具支持改算法。 ## 1. 文件结构与职责锁定 | 路径(相对工作目录) | 动作与职责 | | --- | --- | | `src/polygateway/types.py` | 新 ResponseMode/OpenAIChatCompletion;末尾追加 ChatRequest.response_mode、两个响应 completion | | `src/polygateway/__init__.py` | 导出新公共类型;最终发布时同步版本 | | `src/polygateway/ports.py` | complete 增必填模式参数;说明工具进展与单 choice 契约 | | `src/polygateway/client.py` | chat 新模式校验、消息/overlay 快照、组合拒绝;不重写治理入口 | | `src/polygateway/transports/_openai_completion.py`(新) | 协议结构校验、每尝试聚合、非流式快照;无 I/O/计时 | | `src/polygateway/transports/openai_compat.py` | error 检查、解析器接线、投影/usage/空补全/DONE、统一进展事件 | | `src/polygateway/middleware/retry.py` | 模式传入、completion 搬运;无重试/对冲算法改写 | | `src/polygateway/middleware/cache.py` | 模式 key、嵌套序列化/重建、缺协议 miss、序列化降级 | | `tests/unit/test_openai_completion.py`(新) | 纯协议聚合与非流式校验的源命名测试 | | `tests/unit/test_openai_compat.py` | 真实 transport 的 SSE/非流式/error/raw/DONE/活性测试 | | `tests/unit/test_types.py`, `test_client.py`, `test_ports.py`, `test_cache.py` | 公共类型、校验、端口、缓存往返与兼容 | | `tests/unit/test_retry.py`, `test_hedge.py`, `test_stall_hedge.py`, `test_deadline.py`, `test_backpressure.py` | 模式传递、错误重试、工具活性/对冲、取消与结算 | | `tests/integration/test_governance_stack.py`, `test_redis_cache.py`, `test_redis_cross_connection.py` | 完整链路、真实缓存往返、必要 fake 签名适配 | | `tests/e2e/conftest.py` | 现有取证 transport 包装显式转传模式,不改变 thinking 矩阵判据 | | `tests/e2e/test_openai_tools_live.py`(新) | 受控少量真实工具双轮冒烟,独立 slow 用例 | | `tests/unit/test_package.py` | LICENSE 文件/包元数据回归 | | `LICENSE`, `pyproject.toml` | 标准 Apache-2.0 与打包元数据;不捆绑 reference/ | | `README.md`, `CHANGELOG.md`, `.env.example`, `research-wiki/ARCHITECTURE.md` | 新模式、限制、raw 配置、缓存迁移、同步桥接说明 | | `research-wiki/findings/2026-10-01-issue29-license-audit.md`(新) | 分发源码第三方来源核查证据与范围 | | `research-wiki/graph/edges.json`, `index.md`, `log.md`, `schemas/llm-calls.md`, `metrics/call-telemetry-coverage.md` | 审查通过后的设计/计划/复用遥测关系注册,不新增表或指标实体 | 其余测试若显式调用 complete 必须补参数,仅机械适配;不重构不相关 fixture。`thinking.py`/能力表/streaming.py 算法不在预期改动内。不要为“兼容 SDK”创建不存在的 openai_sdk.py。 ## 2. 跨任务接口 T1 定义公共字段,T2–T5 均消费同一类型名,禁止再起 tool_response/raw_response 别名。 ```python ResponseMode = Literal["text", "openai"] @dataclass(frozen=True) class OpenAIChatCompletion: """单 choice 协议结果,message/usage 是独立 JSON 快照。""" message: dict[str, Any] finish_reason: str | None response_id: str | None usage: dict[str, Any] | None ``` 公共与端口变化均是追加参数/字段: ```python # GatewayClient.chat 的末尾 keyword-only 参数;其余参数保持原样。 response_mode: ResponseMode = "text" # ChatRequest 末尾字段。 response_mode: ResponseMode = "text" # Transport.complete 末尾必填 keyword-only 参数。 response_mode: ResponseMode # TransportResult / LLMResponse 末尾字段。 completion: OpenAIChatCompletion | None = None ``` `build_cache_key` 在已有 keyword-only 参数之后增加 `response_mode: ResponseMode = "text"`,仅非 text 时参与摘要。缓存重建只依赖内核类型/本层校验,不 import transports;若复用协议类型重建的最低形态检查,把纯 JSON 快照检查放类型自身的具名构造方法,不把 transport 的 SSE 状态机下沉到内核。 T2 内部模块只由同目录 transport 消费,不成为公共导出。采用以下窄接口(内部类型在该模块定义): ```python @dataclass(frozen=True) class ChatDelta: """一帧提取结果;progress 表示真实生成进展。""" content: str reasoning_content: str progress: bool ``` ```python class ChatCompletionAccumulator: """每次 transport 尝试独享的单 choice 聚合状态。""" def __init__(self, *, response_mode: ResponseMode) -> None: ... def add_chunk(self, chunk: dict[str, Any]) -> ChatDelta: ... def finish(self) -> OpenAIChatCompletion: ... def parse_chat_completion(body: dict[str, Any]) -> OpenAIChatCompletion: ... ``` 上述 `...` 是签名约定而非待交付占位实现。聚合器抛含判据的 TransientError(operation=chat);openai_compat 负责补选中源上下文、复用有界摘要。聚合器不判断 DONE、不读时钟;transport 掌握线路完整性。text 模式可共用帧提取与进展识别,但不调用严格 openai finish,保持旧文本工具容忍边界。 ## 3. 分任务与独立验收 ### T0 — 审查与来源前置核查 - [x] T1 前已核查分发来源,见 findings/2026-10-01-issue29-license-audit.md;发现不兼容复制即停止。 - [ ] 父会话安排全新上下文原生 subagent 审查设计/计划,重点:单 choice、未知增量字段、身份重复/冲突、raw/managed、缓存错误降级及取消。 - [ ] 核对每条意见,修订文档并记录接受/不接受的理由;如改变用户已批边界,走主管决定,不静默改契约。 - [ ] 在隔离树注册文档关系,复用 llm-calls schema/call-telemetry-coverage 指标;不在主树运行生成器。 - [ ] 文档审查通过后才调用 commit skill 提交设计/计划;当前阶段禁止提交。 验证命令:`wc -l research-wiki/designs/2026-10-01-issue29-openai-fidelity-design.md research-wiki/plans/2026-10-01-issue29-openai-fidelity.md` → 分别 ≤400、≤1000;`git diff --check` → 无错误。Wiki 命令经 `conda run -n PolyGateway python .claude/tools/research_wiki.py --help` 核对实际参数后执行 add_entity/add_edge/rebuild_index;检查生成 diff 不改原有条目正文。 ### T1 — 公共契约贯穿完整治理链 文件:types.py、__init__.py、ports.py、client.py、middleware/retry.py;单元 types/client/ports/retry;所有显式 fake complete 签名。 先补测试:默认 text 不变、新类型可导入、末尾带默认字段不破旧构造;非法 response_mode、openai+structured、n=2/0/True 在适用边界拒绝;保真消息与嵌套 overlay 脱离调用方容器,返回上一轮 assistant 和 role=tool 请求 JSON 逐字段相同。 实现:chat 校验放在 context/handler 前;选源后非法 source.extra_body.n 在 transport HTTP 前 RequestRejected;模式作为必填端口参数穿透重试/对冲,_build_response 原样搬 completion。不把模式塞进发给上游的 payload。 验收:调用级拒绝不发 HTTP;源级拒绝结算/释放正常;自定义 transport fake 看见准确模式;既有旧构造回归全绿。命令: ```bash conda run -n PolyGateway pytest tests/unit/test_types.py tests/unit/test_client.py tests/unit/test_ports.py tests/unit/test_retry.py -q ``` 先红测试须为行为断言或缺失 API 的明确证据,记录基线 SHA 与测试名;绿后提交点:`feat: add explicit OpenAI response contract`。 ### T2 — 内聚协议解析器与 error 帧修复 文件:新增 _openai_completion.py、openai_compat.py;新增 test_openai_completion.py,扩展 test_openai_compat.py。 补测 SSE/非流式/缓存缺 role、非 assistant role;合法 role-only 起始帧后工具成功。先红测试至少含下表各组;复用现有 SSE/MockTransport,不引入第二套 HTTP fake 框架。 | 组 | 输入与精确预期 | | --- | --- | | 并行工具 | 2 工具交错 index;同帧两工具;name/arguments 分片;空白/Unicode/引号逐字相等;最终按 index 排序 | | 身份 | id/type 同值重复只保留一次,冲突失败;缺 id/type/name/arguments、重复 id、bool/负数 index、非 function 类型失败 | | 文本 | 同帧正文+推理均保留;缺省/null/空串区别;原消息 think 标签不剥,旧投影仍剥 | | envelope | 顶层数组/null、choices/delta/tool_calls 非容器、坏字段类型、多 choice/非零 choice index 均受控失败 | | 非流式 | 完整消息、扩展字段、usage/finish/id 全保留;工具参数不做业务 JSON 修复;原响应对象改动不影响快照 | | error | 首帧 error、正文后 error+usage+DONE、error=null、error={}、salvage 配置下 error 都立即失败;text/openai 两模式参数化 | 复用现有 summarize_body/compose_message,断言异常与遥测诊断有界,不打印工具参数正文。默认文本模式不因无用工具字段的严格 finish 校验而新增失败,但不吞顶层 error。无新 HTTP 状态映射。 命令:`conda run -n PolyGateway pytest tests/unit/test_openai_completion.py tests/unit/test_openai_compat.py tests/unit/test_http_error_body.py -q` → PASS;提交点:`fix: preserve chat deltas and reject upstream error frames`。 ### T3 — 完成语义、活性与非流式接线 文件:openai_compat.py、ports.py docstring;test_openai_compat.py、test_streaming.py。 先红:tool-only + DONE 成功 attempts=1;空文本且空工具失败;正文+坏工具不成功;openai 缺 DONE 即使 missing_done=salvage 仍失败;text salvage 保持;finish_reason=length 原样交回,不解析 arguments。非流式工具同样成功,两事件永不置位、ttft/stall=None。 按设计接线:一帧一进展,同帧多个字段只记一个 chunk_time;真正非空工具增量/首次身份触发事件,重复身份和 role/usage/finish/空片段不触发。看门狗仍包进展迭代器,stall 派生/净额取整不动。 测试以受控 Event/FakeClock 驱动,避免用几十毫秒竞争制造脆弱测试:持续工具片段撑过 TTFT/inter-token;只有注释/usage 必超时;工具首进展设置 first_token_event;真实停顿计入 max_inter_token/stall,两字段与正文相同口径。 命令:`conda run -n PolyGateway pytest tests/unit/test_openai_completion.py tests/unit/test_openai_compat.py tests/unit/test_streaming.py -q` → PASS;提交点:`feat: complete tool responses with unified stream liveness`。 ### T4 — 完整协议缓存往返与隔离 文件:middleware/cache.py;test_cache.py、tests/integration/test_redis_cache.py。 先红测试:同消息 text/openai key 不同、旧默认 text key 字节不变;tools、tool_choice、raw effort、tool result、assistant arguments 改动均 miss;相同请求完整 completion round-trip,非流式扩展字段不丢,message 的 null/缺省可区别;usage 缺省/null 均为 None;openai 缺 completion/null/坏 message/坏工具条目 miss 后回源,不冒 dict 假装 dataclass。 检查命中历史 response_id 不变、本次 call_id 重建、attempts=0、cache_hit=true、cost=0;变更一次命中消息不污染下一次命中;旧 text 缓存继续可读。失败路径无 set;序列化/backend set 抛错 warning 后仍返回结果;CancelledError 原样穿透。 实现保真重建校验不能 import transport(import-linter 必守);内核值类型可提供纯值构造校验,协议拼接算法只保留在 transport;避免两份 SSE/tool 聚合逻辑。 命令: ```bash conda run -n PolyGateway pytest tests/unit/test_cache.py -q conda run -n PolyGateway pytest tests/integration/test_redis_cache.py -q conda run -n PolyGateway lint-imports ``` 真实 Redis 专用测试 namespace,沿既有 fixture 清理自有 key,不 flush 共享 DB;未配置 skip 必须记录为未覆盖,发布前补实测。提交点:`fix: isolate and round-trip OpenAI completion caches`。 ### T5 — 完整链路、对冲、取消与遥测不变量 文件:test_retry.py、test_hedge.py、test_stall_hedge.py、test_deadline.py、test_backpressure.py、tests/integration/test_governance_stack.py、test_redis_cross_connection.py、tests/e2e/conftest.py;生产 retry 仅修必要搬运漏项,不改算法。 先红→绿证据须覆盖真实 OpenAICompatTransport 接入 GatewayClient,而不是只用返回预制 completion 的 fake 证明解析成功: | 场景 | 断言 | | --- | --- | | 第一次部分正文/工具→error→DONE,第二次正常 | 只返回第二次 completion,attempts=2;第一次 error 的字段不会污染结果或缓存 | | 工具持续进展 | 首 token 对冲及时止窗,中段 event 复位,未错误触发 | | 真沉默触发对冲 | 副路完整工具结果胜出,返回自己的 id/usage,输家不泄露半成品 | | primary 超时但副路尚在运行 | 不提前判总失败;两败仍只烧一次超级尝试预算 | | 流中/准入中/退避中取消与 deadline | CancelledError/CallDeadlineExceeded 类型保留,permit/inflight/task 收口,TPM 保守结算 | | 观测与降级 | 正常/失败/cache_hit 遥测沿单 helper;attempt 行/terminal 行口径不变;后端写失败不影响结果 | 命令: ```bash conda run -n PolyGateway pytest tests/unit/test_retry.py tests/unit/test_hedge.py tests/unit/test_stall_hedge.py tests/unit/test_deadline.py tests/unit/test_backpressure.py -q conda run -n PolyGateway pytest tests/integration/test_governance_stack.py tests/integration/test_redis_cross_connection.py -q ``` 不删除“不需要失败计费”对应的现有失败遥测/attempts/结算;本任务不新增失败 token 取证。提交点:`test: cover governed tool retries hedges and cancellation`。 ### T6 — 来源审计、Apache-2.0 与用户文档 文件:LICENSE、pyproject.toml、test_package.py、新 license-audit finding、README、CHANGELOG、.env.example、ARCHITECTURE;设计/计划 Wiki 注册关系。 | 工作 | 验收 | | --- | --- | | 来源审计复核(初审前置 T0) | 查 tracked 分发文件的移植/参考/版权注释及具体片段;列内部原创授权记录,外部只读 reference 的路径/许可/实际使用范围;未发现不等于法律认证 | | 第三方义务 | 对实际复制片段核实许可、保留通知;发现 AGPL 不兼容复制须上报,不借用户授权覆盖第三方 | | LICENSE | 使用标准 Apache-2.0 全文,不自行重写;版权归属沿项目元数据,不猜用户真实姓名;NOTICE 仅在实际需要时新增 | | 包元数据 | 当前 setuptools>=68,采用 `license = {file = "LICENSE"}` 兼容现有后端;验证 wheel/sdist 包含 license,不为 PEP 639 单独提高构建依赖 | | 文档 | 新 chat 示例 ≤15 行;response_mode 与 raw 所有权分开;单 choice、未知 SSE 方言失败、非流式、length、无 DONE 不打捞、缓存旧值迁移、取消/线程桥接限制写清 | `.env.example` 只解释 raw-only 必须去掉源级受管意图,不加模式 env 键。README 应说明“完整协议结果”仅四字段及已定义 SSE 字段,不能暗示返回所有顶层 logprobs/created 等;上游模型使用 LLMResponse.model_reported,不把 model 配置别名当真实版本。 ARCHITECTURE 更新 §5 类型/签名、§6.2 空补全与 error、§7.1 DONE 与工具协议、§7.2/7.6 工具活性、§7.5 缓存维度,并明确这些只是批准方向的增量,不引入 Agent Loop。站点下线,无具体 Wiki 页面可同步。 验证:`conda run -n PolyGateway pytest tests/unit/test_package.py -q` 先红后绿;`git diff --check`;构建验收见 T8。提交点:`docs: document faithful chat and Apache-2.0 distribution`。 ### T7 — 少量真实工具冒烟与独立验证 新增 tests/e2e/test_openai_tools_live.py,复用 tests/e2e/conftest.py 的请求取证/输出机制,不为本次重跑整个 thinking 矩阵。fixture 的 complete 显式转传 response_mode 是机械接线,不改取证判分算法。 测试使用通用无业务领域的函数,如 echo_value;强制工具选择但工具在测试内执行纯函数,库本体不执行。流式、非流式各一次工具请求,随后带原 assistant+tool 消息做第二轮;断言 ID、finish、arguments 可用和请求消息相等。并行两工具完整逐字拼接的硬门由确定性 fixture 保证,不把模型偶尔不发两个工具解释为库聚合正确。 真实测试标 slow/requires_llm,预算与超时不紧于现有 `.env` 生产配置。raw=max 使用已配支持模型的 raw-only 源;不发明新模型/API。Markdown 安全报告记录模式、源/model_reported、attempts、finish、工具数、结果/失败原因;不输出 key、敏感消息或完整参数。费用/网络异常如实呈现,不宽泛 skip。 命令: ```bash conda run -n PolyGateway pytest -m slow tests/e2e/test_openai_tools_live.py tests/e2e/test_smoke_gateway.py -q make ci ``` 全套件由当前前台执行;若预计长跑需 tmux,禁用缓冲、保存原退出码,不在 pytest 末尾接管道。生成唯一日志路径 `tests/outputs/issue29/<任务>--<时间>.log`,不提交产物。无新增功能代码的当前阶段仅跑过单元基线,不预填完成框。 父会话安排全新上下文 verifier 独立查实际 diff 与测试输出。若修改了准入/取消/退避生产逻辑,补 `tests/integration/test_redis_governance_time.py` 和 `test_redis_cross_connection.py` 对应 slow 子集;仅机械传参/协议解析时记录无 Lua/退避算法交集的理由。慢测试 skip/失败不得当通过。 - [ ] 审查员检查依赖铁律、未知字段策略、旧文本回归与大对象保留成本。 - [ ] 每项行为能链接红绿日志、命令、SHA、退出码;基线失败必须归因,不能“重跑绿了”掩盖。 - [ ] 合并前测试/独立审查通过;提交均调用 commit skill,不夹带主树既有文档差异。 ### T8 — 发布与 issue 外部验收(父会话持有,不由本设计任务执行) 发布版本已由人类最终指定为 1.3.9(取代未发布的 1.4.0),不能在规划中冒称已发布。遵守 CLAUDE.md §4.4.1 全步骤:README/CHANGELOG/两处版本先完成 → 合并 main/push → 合并后 lint/全套件/相交 slow → tag push → 构建/twine check → registry 上传 → 实际下载核验 → Release/挂库/包页核验。 | 发布门 | 可接受证据 | | --- | --- | | 构建 | `conda run -n PolyGateway python -m build` 和 twine check 成功;解包核 LICENSE、许可元数据、completion 类型/参数/解析器均在产物中 | | 安装 | 在独立临时环境从私有索引下载/安装已发布版本;必要时 --no-build-isolation 避免索引无 setuptools;核来源/hash,不误用本地 editable | | 外部页面 | registry 包正文与仓库链接、Gitea Release/tag 实际可见;不以 POST 返回码代替最终状态 | | 下游 | 以发布包运行不含业务逻辑的 tool 双轮接入验收;给 dissect3 说明同 loop 线程桥接和 raw-only 配置,不在本计划越权修改其业务仓 | | 关闭 issue | 再查询 open issue,#29 评论附版本/验收/限制与缓存迁移说明后关闭;若出现新 issue 单独定范围,不假称本计划涵盖未来问题 | ## 4. 自审清单与残余边界 | 需求 | 覆盖任务 | | --- | --- | | 工具双并行、消息往返、raw=max、非流式 | T1–T3、T7 | | error+DONE 所有模式失败、attempts=2 | T2、T5 | | 缺 DONE 不 salvage 工具、length 不修复 | T3 | | 活性、对冲、取消、准入/结算 | T3、T5 | | 完整缓存、模式隔离、旧默认 key 与污染迁移 | T4、T6 | | Apache 授权与第三方来源、分发验证 | T6、T8 | | 测试先红后绿、独立审查、外部发布完成 | 各任务、T7、T8 | 当前残余:首轮代码独审已完成,修复后待父会话最终复核;严格 SSE 方言会拒绝未定义增量字段,不承诺任意 OpenAI 兼容网关;旧文本毒化缓存只能由使用方迁移身份;公共 dataclass 嵌套 JSON 可变,靠快照隔离而非深冻结;模型真实冒烟依赖外部可用性。以上均需在文档和验收中如实保留,不当成全部自动解决。 ## 5. 本轮实施记录(2026-10-01,未发布) P1 最终 assistant role、P2 来源核查前置均已采纳,证据见来源核查 finding。 T1–T6 代码/文档/许可已落实;T7 工具真实冒烟、Redis、质量门已执行,独立代码审查由父会话接续;T8 禁止本 worker 执行。 | 验证 | 实际结果/证据 | | --- | --- | | 基线红 | tests/outputs/issue29/baseline-red.log:error+DONE 未抛、双文本丢 reasoning、模式 API 缺失,3 failed | | 扩展红绿 | expanded-red.log 19 failed(git archive 0e29dea 的 src,不改主树);expanded-green.log 同19 passed | | 防御红绿 | defense-red.log 3 failed:usage 裸错误/空 tool_calls 丢失;defense-green.log 同3 passed | | 全量 | ci-final.log + ci-final.exit=0:1812 passed、23 skipped、110 deselected,覆盖率95%;之后仅增测试/文档,无生产变更 | | 最后定向 | targeted-final.log:264 passed,包含后增的非流式事件/取消/managed冲突/名称分片回归 | | 真实缓存 | test_redis_cache.py 6 passed,专用随机 key,无共享数据清理 | | 真实工具 | live-final.log + live-final.exit=0:流式/非流式双轮2 passed,101.34s;安全Markdown在 tests/outputs/issue29/live | | 构建 | /tmp/pgw-issue29-dist-final 的 wheel/sdist、twine check、LICENSE/源码字节核验通过;仍1.3.8本地测试产物,绝非发布 | 23 skips 为17个已转专用时间语义的 Redis 契约变体、6个缺私有图像语料的 OCR 测试;未把这些当本次通过。110 deselected 为默认 slow;未重跑全模型 thinking 矩阵,因为只机械转传端口参数、未改其判据或能力表。 未提交代码,供父会话独立验收完整工作区。conda 启动有基础环境 RequestsDependencyWarning(pytest本体无该告警),pi-lens 使用错误环境时的缺包/枚举提示已用 conda 实证排除,不据此改变依赖。 Wiki add_entity 会覆写无frontmatter同名文件,现场检查发现后已从本会话原始 tool-write 精确恢复两文档,并加 frontmatter 后保留 P1/P2 修订;没有丢失设计内容。 补充最终证据:unit-final.log 1678 passed(23.84s),smoke.log + smoke.exit=0 为既有真实 chat 冒烟4 passed(97.18s);未跑昂贵全模型矩阵。源代码最后变更早于 ci-final,后续只增测试/文档;最后单元覆盖全部新增测试。 ## 6. 审查修复与1.4.0准备(2026-10-01,未发布) 已读取首轮独立报告并核验采纳 P2 空产物缓存、Minor 测试双向依赖,详见 [审查处置](../reviews/2026-10-01-issue29-cache-review.md)。本轮只在隔离 feature 树写入,主树既有脏文档未改;不合并、不 push/tag/上传、不关issue。 | 本轮命令/证据(日志均在 tests/outputs/issue29,不提交) | 实际结果 | | --- | --- | | 新缓存回归修复前:review-cache-red.log | 10 failed、1 passed:五种无效产物×两种缓存投影误命中;合法tool-only通过 | | 四模块定向:review-cache-green.log | 268 passed,17.71s;包含11项新增缓存回归 | | 真实Redis+包测试:review-redis-package.log | 13 passed,2.66s(6 Redis、7包) | | 首次 lint / make ci | 测试import顺序失败;已修正,不作为通过证据 | | tmux make ci:review-ci-final.log / .exit=0 | 1827 passed、23 skipped、110 deselected,317.28s;95%覆盖;格式102文件、ruff通过、依赖契约1 kept/0 broken | | 远端 tags 与 registry simple | 最大均1.3.8,没有1.4.0;版本两处改1.4.0,README约束>=1.4.0,<2,CHANGELOG定版 | | build / twine / 解包:review-build-final.log、review-twine.log、review-artifacts.log | 1.4.0 wheel/sdist 均通过;所有Python源码、README、标准LICENSE逐字相同,Version/License-File正确且无reference | | README数字断言 | inspect.signature 实测 TelemetryRecorder.record_llm_call 为38字段,未凭记忆更新 | wheel SHA256 `3186d01d7710c3b5ef727b59f95e8c2db0821277a79491ffb913dd2ce34a888d`;sdist SHA256 `b254dedf65d25673cf57986a613a1f4e9895da8b5be1e6ee241f00065a95ad90`。这些是隔离树本地构建,不是registry产物。解包探针首次使用email默认ASCII解码比较中文README产生误报,改为METADATA正文原始字节比较后通过,未改包来迎合错误探针。 跳过项仍为17个独立slow Redis时间变体及6个缺私有图像语料OCR;110 slow未选中。本轮不重复付费网关:复用前轮流式/非流式工具双轮2通过和chat冒烟4通过,当前生产改动只统一空产物判据,工具/文本正常行为已有定向与全套件证明;合并后slow发布门由父执行。构建有setuptools许可表格弃用提醒(兼容setuptools>=68设计),并有基础conda RequestsDependencyWarning;均不等于当前构建或测试失败。 按commit skill提交feature全部实现、修复、许可与发布准备,原main脏文件及运行产物不纳入。提交后交父最终独立复核;T8外部发布尚未完成,不能提前关闭#29。 ## 7. 版本定案与历史文档归档(2026-10-01 EDT / 2026-10-02 UTC) 用户最终指定本次发布 __1.3.9__,取代尚未打 tag/上传的 1.4.0。上节 1.4.0 构建散列、测试结果与历史提交标题均是当时实证,保留原样,不冒充 1.3.9 产物。README 安装约束、能力标题、CHANGELOG 与两处版本同步;自定义 `Transport.complete(response_mode=...)` 适配要求及旧缓存更换 namespace/salt 提醒保持不变。CHANGELOG 使用执行环境本地日期 2026-10-01(EDT),知识库时间戳明确使用 UTC。 历史六文档独立归档提交 `ce10881`;采纳独审发现,仅补 #24 implements 边缺少的 plan/design 两节点。验证旧新节点/边/日志并集完整、120 个索引链接与计数一致、三文件仅空白/空引用格式、无冲突标记。剩余 15 个历史未注册端点以及 wiki lint 的 15 条孤立/稀疏提示均未扩大处理。原始备份 `/tmp/pgw140-release` 及 stash 保留。 本轮只准备与本地构建,不合并、不 push/tag/上传、不关闭 issue;后续独审及发布外部验收仍是硬门。相关功能代码未变,可复用 `/tmp/pgw140-release/main-ci.log` 的 1828 项通过、95% 覆盖及 `main-slow.log` 的 6 项真实网关通过(205.81s);本轮另执行包/协议定向、质量检查和 1.3.9 构建解包验证。 | 本轮证据(`/tmp/pgw139-prepare/`) | 实际结果 | | --- | --- | | source.log / tests.log | 显式 `PYTHONPATH=/home/iomgaa/Projects/PolyGateway/src` 确认源码位置及1.3.9;包+缓存+协议四模块276 passed,12.43s,无新增行为测试 | | check.log | `make check` 格式、ruff、依赖契约通过,1 kept/0 broken | | docs-validation.log / wiki-lint.log | #24两端点补齐;原新记录保全、120链接计数通过;存量15个端点缺口及15条lint提示未清理 | | remote-tags.txt / registry-simple.html | 2026-10-02 UTC读取远端tag与匿名simple均无1.3.9/1.4.0,无版本冲突;发布前仍须复查 | | build.log / twine.log / artifacts.log / unpacked-import.log | 1.3.9 wheel/sdist构建、twine及全Python源码/README/LICENSE逐字核验通过;解包路径独立导入成功,38遥测字段实测不变 | 本地 wheel SHA256 `45306557152fd44f8135928041e47924834c3b4039c586f72d521f51b4590dd3`;sdist SHA256 `8f455973e7fef71811e2b86f5a14cb03469d893ac9720b902f522d2b1a8dcd40`。产物位于 `/tmp/pgw139-prepare/dist`,不是已发布包。构建仅有已知许可证表格弃用提示、conda基础环境依赖警告;不为清警告增加依赖。