fix: 死信表真正接线 + 前端 HTTP 收敛与状态修正 #9

Merged
shangfangjian merged 1 commits from fix-deadletter-frontend-cleanup into main 2026-09-21 18:39:09 +08:00
Collaborator

概要

按审查报告的「建议优先级」收尾三项:

1. 死信表真正写入(Medium-1)

  • events / standings / stats 三条管线抓取失败时调用新增的 _safe_write_ingest_failure 写入 IngestFailure(entity_type 分别为 events / standings / match_stats,stats 带上游 source_record_id,raw_payload 含联赛/赛季/日期/比赛 ID 上下文)
  • 写入器「尽力而为」:死信写不进去只记 warning,不影响采集主流程
  • 顺带修复一个潜伏 bug: standings 失败路径的 league_r 初始化缺 errors 键,原代码一进 except 就 KeyError 并顶掉原始异常 —— 这条失败路径此前从未跑通
  • 更新 IngestFailure 模型 docstring(「预留未启用」已过时)
  • 新增 tests/test_ingest_deadletter.py 6 例(假 db + monkeypatch,与 R2 同范式),已做变异验证(空实现 → 4 例变红)

2. Admin HTTP 收敛(Medium-2)

  • admin/api.ts 改为 lib/http.ts 的薄门面(对外签名不变:api 四方法 / ApiError / UNAUTHORIZED_EVENT / API_BASE / 认证函数)
  • UNAUTHORIZED_EVENT 定义移至共享层,断开 lib→admin 反向依赖
  • 5 处消费方(AdminLayout/components/Login/Config/Settings)无需改动

3. 状态口径与死字段(Medium-3 残留 + Medium-5)

  • STATUS_META 的死键 live 改为 in_play(normalize.py 口径:上游 live 归一化为 in_play,库里不存在 live),另补 paused/postponed/cancelled/suspended,进行中比赛不再显示「原文状态+灰色」
  • 移除无人消费的 DashboardStats.total_matches(items.length 近似,上限 100);Dashboard 已在用 /admin/stats 的精确 COUNT(此项主路径此前已修,本 PR 清理残留字段防误用)

验证

  • 后端全量 pytest: 246 passed, 1 skipped
  • 前端 tsc && vite build: 通过(注:本机 node_modules 曾缺 react-router-dom,已补装)
  • 新增测试经变异验证具备判别力
  • 报告中未动的项:Matches.tsx 拆分(1386 行)、Repository 空壳分层、predict 路由 dict/dataclass 分支 —— 属结构性重构,另行处理
## 概要 按审查报告的「建议优先级」收尾三项: ### 1. 死信表真正写入(Medium-1) - events / standings / stats 三条管线抓取失败时调用新增的 `_safe_write_ingest_failure` 写入 `IngestFailure`(entity_type 分别为 events / standings / match_stats,stats 带上游 source_record_id,raw_payload 含联赛/赛季/日期/比赛 ID 上下文) - 写入器「尽力而为」:死信写不进去只记 warning,不影响采集主流程 - **顺带修复一个潜伏 bug**: standings 失败路径的 `league_r` 初始化缺 `errors` 键,原代码一进 except 就 KeyError 并顶掉原始异常 —— 这条失败路径此前从未跑通 - 更新 IngestFailure 模型 docstring(「预留未启用」已过时) - 新增 `tests/test_ingest_deadletter.py` 6 例(假 db + monkeypatch,与 R2 同范式),已做变异验证(空实现 → 4 例变红) ### 2. Admin HTTP 收敛(Medium-2) - `admin/api.ts` 改为 `lib/http.ts` 的薄门面(对外签名不变:api 四方法 / ApiError / UNAUTHORIZED_EVENT / API_BASE / 认证函数) - `UNAUTHORIZED_EVENT` 定义移至共享层,断开 lib→admin 反向依赖 - 5 处消费方(AdminLayout/components/Login/Config/Settings)无需改动 ### 3. 状态口径与死字段(Medium-3 残留 + Medium-5) - `STATUS_META` 的死键 `live` 改为 `in_play`(normalize.py 口径:上游 live 归一化为 in_play,库里不存在 live),另补 paused/postponed/cancelled/suspended,进行中比赛不再显示「原文状态+灰色」 - 移除无人消费的 `DashboardStats.total_matches`(items.length 近似,上限 100);Dashboard 已在用 /admin/stats 的精确 COUNT(此项主路径此前已修,本 PR 清理残留字段防误用) ## 验证 - 后端全量 `pytest`: **246 passed, 1 skipped** - 前端 `tsc && vite build`: **通过**(注:本机 node_modules 曾缺 react-router-dom,已补装) - 新增测试经变异验证具备判别力 - 报告中未动的项:Matches.tsx 拆分(1386 行)、Repository 空壳分层、predict 路由 dict/dataclass 分支 —— 属结构性重构,另行处理
WorkBuddy added 1 commit 2026-09-21 18:37:43 +08:00
- bzzoiro events/standings/stats 抓取失败写入 IngestFailure 死信(尽力而为,
  写入失败不影响主流程);顺带修复 standings 失败路径 league_r 缺 errors 键
  的 KeyError —— 该路径此前从未跑通,一旦失败会顶掉原始异常
- admin/api.ts 收敛为 lib/http.ts 薄门面,消除第二套 HTTP 实现;
  UNAUTHORIZED_EVENT 定义移至共享层,断开 lib→admin 反向依赖
- STATUS_META 死键 live 改为 in_play(对齐 normalize.py 口径),
  补 paused/postponed/cancelled/suspended;移除无人消费的
  DashboardStats.total_matches(items.length 近似,上限 100)
- 新增 tests/test_ingest_deadletter.py(6 例,变异验证判别力)
shangfangjian merged commit f6c0145c32 into main 2026-09-21 18:39:09 +08:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: shangfangjian/Profeto#9