8.7 KiB
8.7 KiB
九个审查点已全部核对完毕。以下为完整审查报告。
1.3.8 流式中段沉默分支:整分支合并前审查
- 结论先行:可合并(OK with notes)。无阻断项;2 条建议级(P2)发现,均不阻塞合并。
- 范围:
main a28d944...HEAD ca8743b(代码提交 901a193/53bcf43/e0b0be0/2ac05a2 + 文档提交)。审查方式:只读,未运行 git/pytest(审查纪律),一切裁决以当前工作区源码 + 测试 + 文档实读为证据;绿态证据引自findings/2026-09-11-streaming-stall-validation.md登记的命令输出。
逐点裁决表
| # | 审查点 | 裁决 | 关键证据 |
|---|---|---|---|
| 1 | 取消穿透 | 通过 | retry.py:596-645 _past_hedge_window 两阶段均逐字套用"waiter.cancel() → await waiter → CancelledError 时 cancelling() 判外部取消穿透"既有范式;阶段 1(:608-622)、阶段 2 循环内(:630-642)、对冲在途(_attempt_hedged Phase 5 :540-556 + except BaseException 收口 :557-567 逐字保留)三时点全部穿透。测试:test_stall_hedge.py::test_external_cancel_during_stall_wait_penetrates(阶段 2 内取消,无残留任务、permit 释放、asyncio.all_tasks() 前后相等)+ test_hedge.py:501 既有取消用例未动 |
| 2 | Event 并发纪律 | 通过 | 与计划 §3.6 伪代码逐点比对:①复检 is_set() 在 primary.done() 之后、触发之前(retry.py:638);②is_set()→clear() 紧邻无 await(:638-639);③对冲路恒 content_event=None(:513 Phase 4);④每轮自建 waiter(:630);⑤等待者唯一(编排单点等待,waiter 进 finally 收口后才进下一轮)。唯一偏差:阶段 1 的 waiter 创建被提升到 if 分支外(:608),功能等价且更简洁,非问题 |
| 3 | 净口径换算唯一处 | 通过 | 全库 int(.*stall 仅 retry.py:377-378 两处相邻行(同一次换算);net = max(0, wall_ms − (stall_ms or 0)) clamp 收敛在 _record_winner_sample(:575-590),单路(_record_generation)与对冲赢家(_register_hedge)共用。None 透传五路径逐一核实:非流式(_complete_once 永不置位、TransportResult 默认 None)、chunk<2(_stall_from_chunk_times 返回 (None,None),openai_compat.py:98-99)、两败(_register_hedge(winner_sink=None) 不记 generation、stall 保持 None)、embedding/ocr(record_generation 不带 stall kw,embedding.py/ocr.py 零改动已 grep 证实) |
| 4 | 看门狗汇合 | 通过 | Phase 5"先了结的是失败则等另一路"(retry.py:540-543)逐字复用;看门狗掐死 → StreamLivenessTimeout→TransientError→_attempt 既有失败分支(breaker.record_failure/attempt_fails/遥测 error 行照常,:415-437)。测试 test_stall_hedge.py::test_watchdog_kills_primary_hedge_leg_survives 断言熔断失败样本 +1、主路 error 行携 TransientError 对象、副路正常行——N9 不对称(掐死喂熔断 vs 输家取消不喂)未改任一 |
| 5 | 配置守卫 | 通过 | check_hedge_assembly 返回 `tuple[float |
| 6 | 遥测链路 | 通过 | 协议 +2 参无默认值(ports.py:343-344,共 38 参,test_ports.py:324 钉住);_AttemptUsage.of() 不从 response 取(B2 裁决 b,telemetry.py:219-223);emit_attempt 显式转发、emit_cache_hit/emit_terminal_failure 显式 None(:465-466/:515-516/:570-571);_record +2 参透传(:616-617/:686-687);schema 五编辑点齐备且保序对齐(schema.py:66-67/110-111/146-147/175-176/227-228)物理列 39;DDL 幂等有测试(test_telemetry.py:460-480 二次初始化零 ALTER、:485-503 manual 档点名两条新 ALTER);test_hedge.py:145-148 RecordingEmitter 显式全签名 +2 kw(B1)已同步。附带:sqlite.py:146 计数已同步 38;postgres.py:411 docstring 本就无字段计数文本,计划"计数同步"对它无对象,无残留"36"字样(全 src grep 证实) |
| 7 | 默认关闭回归 | 通过 | 入口门第一分支(两阈值皆 None)逐字走 1.3.7 单路且 first_token_event=None, content_event=None(retry.py:285-295);第二分支(仅 stall + 非流式)同形(:297-307);T1 阶段单路调用点恒传 None 已并入最终形态;SourceConfig.stall_threshold_ms 默认 1000 只影响计量(这是已批准的 P1 行为变更本体,CHANGELOG 行为变更段已披露,非回归);findings 登记批次 E 门:1688 passed, 17 skipped 且既有语义断言一行未改 |
| 8 | 反 gold-plating | 通过 | 全 src grep 1.3.8 标记仅落在计划 §2.1 清单内 8 个文件(ports/types/config/client/retry/telemetry/schema/openai_compat);errors.py/deadline.py/streaming.py/middleware/{ratelimit,breaker,structured,cache,admission}.py/embedding.py/ocr.py/tests/contracts/** 零新增引用(仅既存 issue #8 stall-window 语境);无 except Exception: pass、无 print()、日志全 loguru、公共函数类型注解齐全;缓存指纹 build_model_fingerprint 只取 model/extra_body/thinking 三件套(client.py:125-164),stall_threshold_ms 不进指纹——改阈值不触发缓存冷启动,无意外副作用 |
| 9 | 测试质量 | 通过(带 1 条 P2) | 批次 D 复检用例确实走到"waiter 正常完成 → is_set→clear→continue"路径(不是平静场景:chunk 压在 0.049s、阈值 0.05s,复检-继续被真实执行);对冲赢家净口径、看门狗记账、两败一次预算、取消穿透、对冲路恒 None 的断言强度与 test_hedge.py 同档(同一设施范式 + 逐次身份记录 + 任务泄漏断言)。test_stall_hedge.py 还主动补了计划外的 test_single_leg_attempt_row_carries_stall(T3 缺口钉:chat 成功行经 _emit 端到端落 stall 两值),属范围纪律内的测试加固,非 gold-plating |
发现列表
阻断(B):无。
建议(N/P2):
- N1(P2)
retry.py:369-371注释阶段性残留:_attempt内content_event=content_event处注释仍写"本阶段(T1)所有调用点恒传 None = 不观测;T4 才在启用 stall 对冲的流式原路上接真事件"。T4 已落地,该缝现在转发的是调用方传入的真事件,"本阶段(T1)"措辞会让后来者误以为代码停在 T1 中间态。最小修:把"本阶段(T1)…T4 才…"改为终态表述("未启用 stall 对冲时调用方传 None;启用时流式原路携真事件,对冲路恒 None")。不影响行为,可合并后随手改。 - N2(P2)复检用例时序余量仅 1ms:
test_stall_hedge.py::test_stall_recheck_prevents_false_trigger用chunk_after=0.049s对阈值0.05s,与本文件自定"容差 4–10×"纪律相逆(此处是反向边界,宽余量反而测不到复检路径,故取值本身可辩护);且真实 loop 钟下"chunk 与超时同一 pass 到达"不可确定性复现,该用例实际测到的是"超时前一刻到达 → 复检-继续",严格同 pass 竞态仍只剩代码走查兜底(已走查,正确)。风险是 CI 抖动下 sleep 晚醒 >1ms 会假触发使transport.calls多出 s2 而红。计划 §7 已预留缓解(调宽至 0.45× 阈值并记 findings),合并不阻塞,建议观察首轮 CI 表现。
残余风险与说明
- 本审查为只读静态审查 + 已登记绿态证据复核,未重跑测试;合并前按 CLAUDE.md §4.4.1 第 4 步仍需跑 slow 交集子集(Redis 时间语义变体 +
test_smoke_gateway.py),test_thinking_live.py矩阵按 2026-09-10 决议不跑(复用 1.3.7 证据)。 _past_hedge_window复检窗口只能收窄不能归零(计划 §8 已诚实标注),属已批准残留。- 对冲取消与外部取消同时到达时可能误贴
hedge_cancelled标签,retry.py:418-423注释已声明记账方向一致、属已批准可接受残留。
Merge verdict: OK with notes(N1/N2 不阻塞;建议合并后小修 N1 注释)。
结论:可合并(OK with notes)。发现计数:阻断 0 / 建议 2(N1 retry.py:369-371 注释阶段性残留;N2 test_stall_hedge.py 复检用例 1ms 时序余量偏紧)。