feat(compare-alert): 报警末帧列补「停留Xs」(dwell-only,不显总帧数) #226

Merged
guke merged 8 commits from feat-compare-alert-last-frame-dwell into main 2026-08-07 19:13:24 +08:00
Member

描述

Summary

  • 飞书报警卡片「末帧」列:给 failed(T1/T2/T6) 与 cancelled 兜底两条末帧路径补「末帧所在屏停留 Xs」,
    区分「一到结算页就崩(停留<1s)」vs「在结算页干转 40s 才放弃」;T5 卡死路径不变。
  • trace_stuck.py:抽 _last_segment(末段扫描+时长,卡死判据与末帧停留共用);StuckPoint 加 dwell_ms;
    last_step / read_stuck_points.last 附 dwell;删重构后无人调用的 _platform_stuck。
  • compare_alert_worker.py:新增 dwell-only 的 _fmt_last(只显环节·页面+停留,不显总帧数,
    规避「总帧数配末段时长」误导);failed / cancelled 兜底两处接上。
  • 无新增列、无落库、无迁移。
描述 ## Summary - 飞书报警卡片「末帧」列:给 failed(T1/T2/T6) 与 cancelled 兜底两条末帧路径补「末帧所在屏停留 Xs」, 区分「一到结算页就崩(停留<1s)」vs「在结算页干转 40s 才放弃」;T5 卡死路径不变。 - trace_stuck.py:抽 _last_segment(末段扫描+时长,卡死判据与末帧停留共用);StuckPoint 加 dwell_ms; last_step / read_stuck_points.last 附 dwell;删重构后无人调用的 _platform_stuck。 - compare_alert_worker.py:新增 dwell-only 的 _fmt_last(只显环节·页面+停留,**不显总帧数**, 规避「总帧数配末段时长」误导);failed / cancelled 兜底两处接上。 - 无新增列、无落库、无迁移。
guke added 7 commits 2026-08-07 18:12:44 +08:00
failed / cancelled 兜底两种末帧路径补「末帧所在屏停留 Xs」,
新增 StuckPoint.dwell_ms(与 stuck_ms 语义分离),dwell-only 显示
规避「总帧数配末段时长」误导;缺 ts/时钟回退降级只显环节。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5 个 TDD task:抽 _last_segment + StuckPoint.dwell_ms(重构)、
last_step 附 dwell、read_stuck.last 附 dwell、worker _fmt_last 接线、回归+lint。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
末段扫描+时长算法抽成 _last_segment 供三处复用;StuckPoint 新增
dwell_ms(默认 None、承载末帧所在屏停留),T5 行为不变。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
failed 末帧路径拿到「末帧所在屏停留」;frames 仍为总帧数、口径不变。
worker 调用同步传 max_tail(格式化留待接线)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cancelled 兜底末帧拿到末段停留;循环改为每平台一次 _last_segment,
判卡死与末帧候选共用同一次末段扫描,零增量 IO。顺带删重构后
无人调用的 _platform_stuck(逻辑已被 read_stuck_points 内联)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
failed 与 cancelled 兜底两条末帧路径用 _fmt_last 显示环节·页面+末段停留;
只带 dwell、不带总帧数,规避原注释担心的「总帧数配末段时长」误导;
缺 ts/时钟回退降级只显环节。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- read_stuck_points 最忙平台末帧损坏 → last fallthrough 到干净平台
  (重构最险分支的回归测试,原只在一次性验证脚本里)
- _fmt_last round 边界:500→<1s、999→停留1s
- continue 注释点明与旧版 _platform_stuck→None 等价

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Member

🤖 review-pr 深审结论

🟢 看着没问题(置信度 0.9)。把「末段扫描」抽成单一 _last_segment,卡死判据(≥threshold)与末帧停留(dwell)复用它;末帧路径新增「停留Xs」展示(dwell-only,不显总帧数)。对既有卡死检测行为保持,纯增量。

核对(合并 main 后)

  • 契约 last_step(trace_dir, *, max_tail) 新增必填 max_tail,唯一调用方 compare_alert_worker.py 已同步传入 ✓
  • 等价性 新版 seg is None → continue 与旧版「_platform_stuck→None + 独立末帧 _read_head→ps None」两处跳过等价:any_frames=Truecontinue 之前trace_stuck.py:136)就已置位,故「是否有帧」判定不变,continue 只跳过卡点/末帧候选 ✓
  • 字段 StuckPoint 同时保留 stuck_ms(卡死路径)与 dwell_ms(末帧路径),无删字段;_fmt_last 只作用于 res.last/last_step 结果(均带 dwell_ms),卡死点仍走原 stuck_ms 口径——各取所需,不串 ✓

测试/构建 已实跑(合并 main 后 worktree,venv Py3.12)

  • pytest tests/test_trace_stuck.py tests/test_compare_alert_stuck_worker.py35 passed(含作者补的 continue 分支回归 + <1s 边界)
  • 本 PR 无迁移,alembic heads 单头(savings_record_trace_id

issues:无 high/med。

  • low(可选) trace_stuck.py:144 卡死点用第 4 个位置参把局部变量 dwell_ms 传进 stuck_ms 字段(值对、语义也对,因卡死段时长即 stuck_ms);写成关键字 stuck_ms=dwell_ms 可免读者误以为在设 dwell_ms 字段。
  • low _fmt_lastround(dwell_ms/1000)(banker's rounding,1.5s→2s)——展示用,可接受。

正面:单一 _last_segment 作两处口径的真相源、等价性有注释兜底;_fmt_lastdwell_ms=None(缺 ts/时钟回退)时优雅退化为只显环节;测试覆盖到边界。

建议:可选把 :144 改成 stuck_ms=dwell_ms 关键字,纯可读性,无需阻断合并。

## 🤖 review-pr 深审结论 🟢 **看着没问题**(置信度 0.9)。把「末段扫描」抽成单一 `_last_segment`,卡死判据(≥threshold)与末帧停留(dwell)复用它;末帧路径新增「停留Xs」展示(dwell-only,不显总帧数)。对既有卡死检测**行为保持**,纯增量。 **核对(合并 main 后)** - **契约** `last_step(trace_dir, *, max_tail)` 新增必填 `max_tail`,唯一调用方 `compare_alert_worker.py` 已同步传入 ✓ - **等价性** 新版 `seg is None → continue` 与旧版「`_platform_stuck→None` + 独立末帧 `_read_head→ps None`」两处跳过等价:`any_frames=True` 在 `continue` **之前**(`trace_stuck.py:136`)就已置位,故「是否有帧」判定不变,`continue` 只跳过卡点/末帧候选 ✓ - **字段** `StuckPoint` 同时保留 `stuck_ms`(卡死路径)与 `dwell_ms`(末帧路径),无删字段;`_fmt_last` 只作用于 `res.last`/`last_step` 结果(均带 `dwell_ms`),卡死点仍走原 `stuck_ms` 口径——各取所需,不串 ✓ **测试/构建**:✅ 已实跑(合并 main 后 worktree,venv Py3.12) - `pytest tests/test_trace_stuck.py tests/test_compare_alert_stuck_worker.py` → **35 passed**(含作者补的 continue 分支回归 + <1s 边界) - 本 PR 无迁移,`alembic heads` 单头(`savings_record_trace_id`) **issues**:无 high/med。 - **low(可选)** `trace_stuck.py:144` 卡死点用第 4 个位置参把局部变量 `dwell_ms` 传进 `stuck_ms` 字段(值对、语义也对,因卡死段时长即 stuck_ms);写成关键字 `stuck_ms=dwell_ms` 可免读者误以为在设 `dwell_ms` 字段。 - **low** `_fmt_last` 用 `round(dwell_ms/1000)`(banker's rounding,1.5s→2s)——展示用,可接受。 **正面**:单一 `_last_segment` 作两处口径的真相源、等价性有注释兜底;`_fmt_last` 在 `dwell_ms=None`(缺 ts/时钟回退)时优雅退化为只显环节;测试覆盖到边界。 建议:可选把 `:144` 改成 `stuck_ms=dwell_ms` 关键字,纯可读性,无需阻断合并。
guke added 1 commit 2026-08-07 19:13:14 +08:00
guke merged commit e1a6095670 into main 2026-08-07 19:13:24 +08:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: WonderableAI/shaguabijia-app-server#226