refactor: 以 bzzoiro 为唯一数据源的全面重构
数据源统一为 bzzoiro,移除 Understat 与 injuries:
- 删除 src/data/understat.py / injuries.py 及相关测试
- 删除 injuries 模型与表;扩展 match_stats(xG 之外增加 big_chances/fouls)
- 新增 standings 表(联赛积分榜:位置/积分/xG/走势/分区)
- matches 表增加 source_event_id 血缘列,支撑统计回填
采集管线(bzzoiro 三条管线):
- events:赛程/比分(/events/),记录 source_event_id
- standings:积分榜快照(/leagues/{id}/standings/)
- stats:已完赛比赛详细统计回填(/events/{id}/stats/)
预测增强:
- standings_slice 替代 injuries_slice;积分榜专家替代阵容完整性专家
- AGENT_META runtime_config 同步更新
管理后台:
- ingest 路由重写为单一 bzzoiro 入口 + task 参数(events/standings/stats/all)
- 新增 /admin/data-completeness 数据完整性分析 API
- 数据源状态页简化为 bzzoiro 单源
前端:
- 采集页重构为任务驱动(比赛/积分榜/统计回填/全量)
- 新增「数据完整性」可视化页(覆盖率矩阵/字段完整率/健康摘要)
- 新增主站积分榜页(/standings)与比赛详情完整统计面板
- agent 名称同步更新(injuries→standings)
迁移 0015_bzzoiro_single_source 已在容器内验证通过,后端测试全部通过。
Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
This commit is contained in:
co-authored by
new-provider/LongCat-2.0 <
parent
ec8f36abb2
commit
f05dc1ae15
@@ -5,8 +5,9 @@
|
||||
2. _is_stats_available: available_at is None + cutoff is None(实盘) → 可用(兼容旧数据)
|
||||
3. _is_stats_available: available_at > cutoff → 不可用
|
||||
4. _is_stats_available: available_at <= cutoff → 可用
|
||||
5. 写入策略: available_at = match_date + 2h 缓冲
|
||||
5. 写入策略: bzzoiro 写入 available_at 使用 match_date + 2h 缓冲
|
||||
6. cutoff 在缓冲内时不可用(available_at > cutoff → False)
|
||||
7. stats 回填(bzzoiro event stats)也使用 2h 缓冲
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -73,37 +74,26 @@ class TestIsStatsAvailable:
|
||||
|
||||
|
||||
class TestWriteBufferStrategy:
|
||||
"""验证 bzzoiro/understat 写入 available_at 使用 match_date + 2h 缓冲。"""
|
||||
"""验证 bzzoiro(events + stats 回填)写入 available_at 使用 match_date + 2h 缓冲。"""
|
||||
|
||||
def test_bzzoirot_new_match_available_at_is_two_hours_after_kickoff(self):
|
||||
"""bzzoiro 新建比赛时 available_at 应为开球 + 2 小时。"""
|
||||
"""bzzoiro 新建比赛(stats 回填创建 MatchStats)时 available_at 应为开球 + 2 小时。"""
|
||||
import inspect
|
||||
from src.data import bzzoiro
|
||||
|
||||
source = inspect.getsource(bzzoiro)
|
||||
# 验证:使用 timedelta(hours=2) 作为缓冲
|
||||
assert 'timedelta(hours=2)' in source, \
|
||||
"bzzoiro 应使用 match_date + timedelta(hours=2) 作为 available_at"
|
||||
|
||||
def test_bzzoirot_existing_match_uses_two_hour_buffer(self):
|
||||
"""bzzoiro 更新已有比赛时也应使用 2 小时缓冲。"""
|
||||
def test_bzzoirot_multiple_writes_use_two_hour_buffer(self):
|
||||
"""bzzoiro 多处写入(创建/更新)都应使用 2 小时缓冲。"""
|
||||
import inspect
|
||||
from src.data import bzzoiro
|
||||
|
||||
source = inspect.getsource(bzzoiro)
|
||||
# 两处写入都应使用 timedelta(hours=2)
|
||||
count = source.count('timedelta(hours=2)')
|
||||
assert count >= 2, f"期望至少 2 处 timedelta(hours=2),实际 {count} 处"
|
||||
|
||||
def test_understat_uses_two_hour_buffer(self):
|
||||
"""understat 回填 xG 时也应使用 2 小时缓冲。"""
|
||||
import inspect
|
||||
from src.data import understat
|
||||
|
||||
source = inspect.getsource(understat)
|
||||
assert 'timedelta(hours=2)' in source, \
|
||||
"understat 应使用 match_date + timedelta(hours=2) 作为 available_at"
|
||||
|
||||
def test_cutoff_within_buffer_makes_stats_unavailable(self):
|
||||
"""cutoff 在 2 小时缓冲内时,统计学不可用(回测防泄漏)。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user