feat: P0-02/P0-03/P0-05 数据库时间语义与约束

P0-02: MatchStats 增加 source/source_record_id/retrieved_at/available_at
        context_builder 过滤统计数据时检查 available_at <= cutoff
P0-03: Prediction 增加 match_kickoff_at/prediction_created_at/prediction_cutoff_at
        明确区分比赛时间/预测创建时间/数据截止时间
P0-05: Prediction 增加 status 字段(success/failed/degraded)
        数据库 CHECK 约束

Alembic: 0005_prediction_status_and_stats_provenance

P1-02: injuries as_of 不再截断为 date,保持 datetime 精度
This commit is contained in:
shangfangjian
2026-09-15 02:04:25 +08:00
parent c657e04679
commit 0980c2242a
9 changed files with 122 additions and 13 deletions
+4 -3
View File
@@ -190,11 +190,13 @@ async def get_injuries_for_match(db, team_id: int, match_date, as_of=None) -> li
match_date: 比赛日期
as_of: 截止时间(cutoff)。只返回 retrieved_at <= as_of 的记录。
用于回测时防止"未来采集的数据"泄漏到历史预测。
必须保持 timezone-aware datetime,不会截断为 date。
"""
from sqlalchemy import and_, or_, select
from sqlalchemy import or_, select
from src.db.models import Injury
# 只处理 match_date:去掉时间部分,仅比较日期
if hasattr(match_date, "date"):
match_date = match_date.date()
@@ -206,9 +208,8 @@ async def get_injuries_for_match(db, team_id: int, match_date, as_of=None) -> li
)
# 回测防泄漏: 只使用 as_of 时间点之前已采集的数据
# 注意: as_of 保持 datetime,不截断为 date,避免错误排除同日合法数据
if as_of is not None:
if hasattr(as_of, "date"):
as_of = as_of.date()
stmt = stmt.where(Injury.retrieved_at.is_not(None))
stmt = stmt.where(Injury.retrieved_at <= as_of)