fix-deadletter-frontend-cleanup
main
按审查报告的「建议优先级」收尾三项:
_safe_write_ingest_failure
IngestFailure
league_r
errors
tests/test_ingest_deadletter.py
admin/api.ts
lib/http.ts
UNAUTHORIZED_EVENT
STATUS_META
live
in_play
DashboardStats.total_matches
pytest
tsc && vite build
- 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 例,变异验证判别力)
No dependencies set.
The note is not visible to the blocked user.
概要
按审查报告的「建议优先级」收尾三项:
1. 死信表真正写入(Medium-1)
_safe_write_ingest_failure写入IngestFailure(entity_type 分别为 events / standings / match_stats,stats 带上游 source_record_id,raw_payload 含联赛/赛季/日期/比赛 ID 上下文)league_r初始化缺errors键,原代码一进 except 就 KeyError 并顶掉原始异常 —— 这条失败路径此前从未跑通tests/test_ingest_deadletter.py6 例(假 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 反向依赖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 skippedtsc && vite build: 通过(注:本机 node_modules 曾缺 react-router-dom,已补装)