a2a00c0ef2
_minimal_fields and the pre_135 acceptance dicts missed the two new columns, KeyErroring against migrated 39-column physical tables (caught by the pre-merge integration gate; production path is signature-gated and unaffected). Verifier gaps P2-1/P2-2 closed: full suite 1764 passed, PG 30 passed, lint green.
10 KiB
10 KiB
1.3.8 streaming-stall 合并前独立验证报告(verifier,全新上下文)
- 仓库:
/home/iomgaa/Projects/PolyGateway;分支feature/1.3.8-streaming-stall - HEAD 核实:
.git/HEAD→ref: refs/heads/feature/1.3.8-streaming-stall;.git/refs/heads/feature/1.3.8-streaming-stall=8489b8ea50308ca75e0876d293fef7feddf9b086(即8489b8e)✓ - 能力声明(重要): 本 verifier 会话只有 read/grep/find/ls 四类只读工具,无 shell 执行能力(角色纪律: 禁止 shell、禁止写文件)。因此动作 b(套件重跑)、c 的重跑部分、d(行为抽测)、e(
make lint重跑)无法由我本人执行;我已亲自读取实现方落盘的全部日志与全部相关源码做静态+证据核实,运行时必须由 supervisor 按文末清单补跑后方可合并。pi-lens/LSP 诊断未作为任何判据(指令 g)。
结论
有条件通过(OK with notes): T1–T5 全部声明在源码与落盘证据两个维度均核实为真;红绿证据链真实(红日志含真实失败因、绿日志计数单调递增且与提交序一致)。两个证据缺口(见发现 P2-1/P2-2)必须补跑: integration 套件无任何落盘证据、且本会话无法亲跑任何运行时命令。
逐声明验证证据
a) 提交序列(静态替代 git log)
.git/logs/HEAD reflog 末端逐行亲读,分支自 main a28d944(1.3.7)拉出后序列:
| 提交 | 主题 | 对应 |
|---|---|---|
03cbf4c / 97de410 / 929d60e / 6f3a620 |
docs: 设计 + 评审勘误 + 计划 | 文档前置 |
901a193 |
feat: content event + stall accounting to transport port | T1 |
53bcf43 |
feat: generation_ms 净口径重定义 | T2 |
e0b0be0 |
feat: stall_ms/stall_count 遥测列 | T3 |
2ac05a2 |
feat: opt-in 中段沉默对冲 | T4 |
ca8743b |
docs: 净口径与中段对冲文档 | 文档 |
| 8489b8e(HEAD) | docs: resolve branch review note(content_event 接线终态注释) | 文档 |
与声明序列(901a193/53bcf43/e0b0be0/2ac05a2/ca8743b/8489b8e + 文档提交)逐项一致 ✓
T1 端口契约 —— 成立
src/polygateway/ports.pyTransport.complete: kw-only 参数列含content_event: asyncio.Event | None,无默认值(与first_token_event同一约定,docstring 明示 1.3.8 #27/#28)✓src/polygateway/types.py:619-628TransportResult.stall_ms: float|None=None/stall_count,docstring 钉死 None(无从观测)vs 0.0(观测过零沉默)区分、尾部不计 ✓types.py:683-689SourceConfig.stall_threshold_ms: int = 1000,docstring 明示"严格大于才计";types.py:734-743_validate_stall_threshold拒 bool/非 int/≤0 ✓transports/openai_compat.py:88-109纯函数_stall_from_chunk_times:len<2 → (None,None)(L98-99);gap_ms > threshold_ms严格大于(L106);无超阈 →(0.0,0.0)(L109);只遍历相邻对(zip times/times[1:])→ 尾部天然不计 ✓openai_compat.py:608-618流式循环: 每增量 chunkchunk_times.append(now)+content_event.set();L634 由_stall_from_chunk_times(chunk_times, source.stall_threshold_ms)派生两值进 TransportResult(L643-644)✓- 非流式
_complete_once(L698-769): 收两事件永不置位,TransportResult 不传 stall 字段(默认 None)✓
T2 净口径 —— 成立
types.py:331-336CallStats.stall_ms/stall_count: int|None = None;types.py:322-328generation_msdocstring 重定义为净口径(含 clamp、还原公式、排除条款)✓- 唯一换算点
middleware/retry.py:671-681_record_winner_sample:net_ms = max(0, wall_ms - (stall_ms or 0))(clamp 到 0 ✓);None 透传不退减 ✓ - 取整唯一处
retry.py:376-378(墙钟/stall 同点 int 化,墙钟=generation_ms+stall_ms 可还原成立)✓ - embedding/ocr 路径:
record_generation的 stall 参数默认 None(types.py:386-387),既有调用点不传 → 恒 None ✓
T3 遥测 —— 成立
telemetry/schema.pyCOLUMNS亲数 38 项(末两项 stall_ms/stall_count,L227-228);SQLITE_DDL(L66-67)与PG_DDL(L110-111)均含两列;SQLITE_BACKFILL(L146-147)与_PG_BACKFILL_DECLS(L175-176)列序对齐 ✓ports.pyTelemetryRecorder.record_llm_call38 个 kw 参数(末两个 stall_ms/stall_count,无默认值)✓- 迁移幂等: SQLite
sqlite.py:125-143先PRAGMA table_info探测、column in existing: continue跳过、duplicate column 竞态视为成功;PGpostgres.py:352-369同款先探测后 ALTER ✓ - 取消输家行 stall 恒 None:
retry.pyCancelledError 分支self._emit(..., error=label)不传 stall →_emit默认 None(L774-775);emitteremit_cache_hit/emit_terminal_failure显式 None(middleware/telemetry.py:515-516,570-571)✓
T4 中段对冲 —— 成立
config.py:201hedge_stall_after_s: float|None = None(默认关闭);_load_hedge(L801-807)读{SCOPE}__HEDGE__STALL_AFTER_S;_load_stream(L756-774)读{SCOPE}__STREAM__STALL_THRESHOLD_MS;STREAM已进_RESERVED_SEGMENTS(L57)✓- 三守卫唯一事实源
check_hedge_assembly(L810-912): stall ≥ 有效最小值(inter_token_timeout_s or timeout_s回落)→ ValueError(L888-894);stall ≥ call_deadline_s → ValueError(L895-899);单源 warning(L900-906);两阈值皆 None 才早退(审查 B2)✓;GatewaySettings.__post_init__与GatewayClient.__init__共用同一份(config.py:391-401 / client.py:255-263)✓ - Embedding/OCR scope 对冲键 warning:
_warn_hedge_keys_on_non_stream_scope(config.py:915-927),被 EmbeddingSettings(L950)与 OcrSettings(L996)__post_init__调用 ✓ - 编排
retry.py: 仅 stall+非流式 → 逐字单路(L290-301);两阶段触发窗_past_hedge_window(L591-652):阶段 1 首 token 前走 AFTER_S、仅 stall 时须等首 token(防 pre-TTFT 误吞);阶段 2 循环asyncio.wait(timeout=stall_after_s, FIRST_COMPLETED)+ N3① 超时后复检content_event.is_set()防误触发 + N3② check→clear 无 await;触发后 FIRST_COMPLETED 竞速(L538-539);对冲路恒content_event=None(L533);输家cancel()前置_HEDGE_LOSER_ATTR标记(L568-571),_attempt 取消分支据此标hedge_cancelled且不 record_failure(不喂熔断,L414-429)✓ - 三层可调: env 键 →
GatewaySettings.stall_threshold_ms(config.py:206)→from_settings恒分发(client.py:543);直传GatewayClient(stall_threshold_ms=...)经dataclasses.replace分发且重跑__post_init__校验(client.py:264-270)✓
T5 默认关闭回归 —— 静态成立 + 落盘证据
- 代码门:
retry.py:279if self._hedge_after_s is None and self._stall_after_s is None:→ 单路first_token_event=None, content_event=None(注释明示"逐字 1.3.7 单路路径,默认关闭回归门据此成立")✓ - 落盘:
tests/outputs/138/t4/green-unit.log末行1688 passed, 17 skipped in 54.90s(与声明 5 的 1688 一致)✓
c) 红绿证据真实性抽查 —— 真实
- t1 red: ImportError
_stall_from_chunk_times(功能不存在); green: 260 passed ✓ - t2 red: 6 failed(CallStats 无 stall_ms 属性、record_generation 拒 stall kw、净口径 5000≠1800、clamp 5000≠0 等精确断言); green: batch 40 passed / unit 1608 / unit+contracts 1669 ✓
- t3 red: 14 failed(COLUMNS 缺两列、
$占位符 36≠38、真实 SQLiteno such column: stall_ms、幂等补列断言红); green: batch 238 / unit 1673 ✓ - t4 red: 16 failed(RetryMW 拒
stall_after_skw、settings 无hedge_stall_after_s、STREAM 段造出假源stream_1、三守卫 DID NOT RAISE);green: batch D 169 passed、contracts 61 passed ✓ - t4/t5 lint: ruff
All checks passed!+ import-linterContracts: 1 kept, 0 broken✓ - 计数链单调: 1602(T1)→1608(T2)→1673(T3)→1688(T4),与逐批新增用例一致;红日志失败因均为"功能尚不存在"类,非环境噪声 ✓
f) 文档一致性 —— 一致
- CHANGELOG 未发布段: 行为变更(口径重定义+还原公式+None 条款+取消输家恒 NULL)、遥测两列(36→38,旧行不回填)、中段对冲(默认关闭/独立生效/三守卫/19.0% 触发率诚实标注)✓
- README §"1.3.8 生成时间口径与中段沉默对冲"(L115-140):
generation_ms定义句"净生成时间 = 赢家墙钟 − Σ(> STALL_THRESHOLD_MS 的相邻增量 chunk 沉默)"与代码max(0, wall-stall)一致;能力表"遥测必录 38 字段"(L26)、逻辑调用统计段(L27)、配置表两键(L137-138)与代码一致 ✓ .env.exampleL83-89:STREAM__STALL_THRESHOLD_MS=1000与HEDGE__STALL_AFTER_S两键注释与守卫文案一致 ✓- ARCHITECTURE.md §7.2(L504/506)净口径+两阶段触发窗登记段、§7.5(L569/571)38 字段与 stall 两列登记段,与代码行为一致 ✓
发现列表
- P2-1(证据缺口,合并前必须补):
tests/outputs/138/下无任何 tests/integration 运行证据;动作 b 要求pytest tests/unit tests/contracts tests/integration。本 diff 直接触及 PG 遥测列(tests/integration/test_postgres_telemetry.py的_EXPECTED_COLUMNS已含 stall 两列、占位符/列序断言只在真实 PG 上有效)与治理栈,integration 未跑 = PG 侧补列/写入路径只有静态与 SQLite 证据。 - P2-2(流程限制): 本 verifier 无 shell,动作 b/c 重跑/d/e 全部无法亲跑;现结论中"套件绿"的依据是我亲读的实现方落盘日志(文件真实、失败因真实、计数链自洽),非我本人执行。合并前须由 supervisor 补跑下方命令清单,输出落
tests/outputs/138/verify/。
supervisor 必须执行的命令(全部 conda run -n PolyGateway,禁管道,落 tests/outputs/138/verify/)
git log --oneline main..HEAD(核对序列;我已于 reflog 静态核实,仍建议权威跑一次)pytest tests/unit tests/contracts tests/integration -q(记 exit code 与计数;unit 期望 1688,contracts 期望 61)- 关键用例重跑(现绿确认):
pytest tests/unit/test_retry.py::TestGenerationMs tests/unit/test_stall_hedge.py::TestStallHedgeTrigger::test_stall_recheck_prevents_false_trigger tests/unit/test_stall_hedge.py::TestStallHedgeWatchdogAndFailure::test_watchdog_kills_primary_hedge_leg_survives tests/unit/test_telemetry.py::TestStallColumns -q - 行为抽测 d①-③(流式假传输端到端 stall/净 generation_ms;仅 STALL_AFTER_S 下沉默触发对冲且 hedge_won;两键不设时 hedges=0/hedge_won=False)
make lint
合并判定: OK with notes —— 静态与落盘证据全绿;P2-1/P2-2 补跑通过后即可合并,若补跑出现任何红则转 BLOCK。