test: sync PG telemetry integration helpers with 1.3.8 stall columns
_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.
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
# 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.py` `Transport.complete`: kw-only 参数列含 `content_event: asyncio.Event | None`,**无默认值**(与 `first_token_event` 同一约定,docstring 明示 1.3.8 #27/#28)✓
|
||||
- `src/polygateway/types.py:619-628` `TransportResult.stall_ms: float|None=None` / `stall_count`,docstring 钉死 None(无从观测)vs 0.0(观测过零沉默)区分、尾部不计 ✓
|
||||
- `types.py:683-689` `SourceConfig.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` 流式循环: 每增量 chunk `chunk_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-336` `CallStats.stall_ms/stall_count: int|None = None`;`types.py:322-328` `generation_ms` docstring 重定义为净口径(含 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.py` `COLUMNS` 亲数 **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.py` `TelemetryRecorder.record_llm_call` 38 个 kw 参数(末两个 stall_ms/stall_count,无默认值)✓
|
||||
- 迁移幂等: SQLite `sqlite.py:125-143` 先 `PRAGMA table_info` 探测、`column in existing: continue` 跳过、duplicate column 竞态视为成功;PG `postgres.py:352-369` 同款先探测后 ALTER ✓
|
||||
- 取消输家行 stall 恒 None: `retry.py` CancelledError 分支 `self._emit(..., error=label)` 不传 stall → `_emit` 默认 None(L774-775);emitter `emit_cache_hit`/`emit_terminal_failure` 显式 None(`middleware/telemetry.py:515-516,570-571`)✓
|
||||
|
||||
### T4 中段对冲 —— 成立
|
||||
|
||||
- `config.py:201` `hedge_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:279` `if 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、真实 SQLite `no such column: stall_ms`、幂等补列断言红); green: batch 238 / unit 1673 ✓
|
||||
- t4 red: 16 failed(RetryMW 拒 `stall_after_s` kw、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-linter `Contracts: 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.example` L83-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/`)
|
||||
|
||||
1. `git log --oneline main..HEAD`(核对序列;我已于 reflog 静态核实,仍建议权威跑一次)
|
||||
2. `pytest tests/unit tests/contracts tests/integration -q`(记 exit code 与计数;unit 期望 1688,contracts 期望 61)
|
||||
3. 关键用例重跑(现绿确认): `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`
|
||||
4. 行为抽测 d①-③(流式假传输端到端 stall/净 generation_ms;仅 STALL_AFTER_S 下沉默触发对冲且 hedge_won;两键不设时 hedges=0/hedge_won=False)
|
||||
5. `make lint`
|
||||
|
||||
**合并判定: OK with notes** —— 静态与落盘证据全绿;P2-1/P2-2 补跑通过后即可合并,若补跑出现任何红则转 BLOCK。
|
||||
Reference in New Issue
Block a user