shangfangjian
|
49d78136a1
|
fix(P0-02): 积分榜改为追加快照(append-only) + available_at cutoff
去掉 uq_standings_league_season_team,改为 (league, season, team, available_at) 唯一;
每次采集 INSERT 新行(available_at=now),ON CONFLICT DO NOTHING,不覆盖旧行。
standings_slice(before):DISTINCT ON (team_id) WHERE available_at<=cutoff
ORDER available_at DESC;before=None → cutoff=now()。
公开 list_standings 取每队最新可用快照(子查询 max available_at)。
迁移 0023 + 切片/路由/docs 同步;测试 test_p0_standings_cutoff(5/5)。
284 测试全绿。
|
2026-09-22 02:45:50 +08:00 |
|
shangfangjian
|
a00364d4a7
|
perf+unify: matches 列表查询优化 + Standings 统一数据源
matches 列表:selectinload 加 load_only 限定列(League.code/Team.name,name_zh/
MatchStats.home_xg,away_xg),补 stats 加载消除 N+1(m.stats 此前懒加载)。
详情接口保持完整 options;游标分页/响应字段/空值语义不变。
Standings 改用 useLeagues() 统一数据源(API 优先,失败回退本地常量),
LEAGUES 常量扩展 CL/EL;无数据联赛显示虚线 tab + 空态(非隐藏)。
|
2026-09-22 01:35:06 +08:00 |
|
shangfangjian
|
92f50fa5d4
|
feat: 采集任务状态跟踪 ingest_jobs
新增 ingest_jobs 表(UUID/task/params/status/result/error/时间戳),
POST /ingest/bzzoiro 启动前插入 job(pending)→ 后台 running → success/failed,
响应新增 job_id(兼容原 message)。
Admin GET /admin/ingest/jobs/{id} 与 /admin/ingest/jobs?limit= 只读查询;
Collection 页提交后轮询 job 至终态,展示真实 result/error 汇总。
迁移 0019_ingest_jobs + 分批 get_uow/BzzoiroSource/IngestFailure 不变。
全量测试 270 通过。
|
2026-09-22 01:34:55 +08:00 |
|
shangfangjian
|
e15b554ba3
|
feat: 球队实体一致性 — 归一化咽喉 + team_aliases 别名机制
events/standings 创建 Team 前均经 team_names.normalize(已有,确认),
TeamRepository.get_or_create 收敛为归一化唯一咽喉 + info 日志。
新增 team_aliases 表(NFKD 归一别名 → teams.id FK CASCADE),
定位三步链:normalize(name) → teams.name → team_aliases → insert。
不自动合并历史重复队;提供 POST /api/v1/admin/teams/aliases 显式添加。
迁移 0020_team_aliases + Admin 别名管理端点(admin_teams.py)。
全量测试 270 通过。
|
2026-09-22 00:27:53 +08:00 |
|
shangfangjian
|
4b0d6ee58a
|
chore(P3): baseline 落库下沉 + MatchPredictPanel 拆分 + 多 worker/CSRF 文档
P3-2 baseline 落库从路由下沉到服务层(predict_baseline 内直接落库),
删除路由层 _persist_baseline,三种模式统一 result.prediction_id,对外 JSON 不变。
P3-1 MatchPredictPanel.PredictionPanel 拆为 OutcomePanel/AgentsPanel/ReasoningPanel
三个子组件,本文件保留 PredictModal/PredictProgress/Spinner,对外导出路径不变。
P3-3 docs 加 ⚠️ 多 worker 陷阱红字 + STRICT_SINGLE_WORKER 环境变量(启动期强制拒绝多 worker)。
P3-4 docs 新增「同站部署 vs 跨站 CSRF」节。
|
2026-09-21 23:29:09 +08:00 |
|
shangfangjian
|
45497d2112
|
refactor: admin_settings.py 按职责拆分为 4 个模块
681 行单文件拆为(保留 admin_settings 为 include_router 聚合入口):
- admin_datasources 数据源列表/连通性测试/KeyRing/ingest status (5 路由)
- admin_config settings CRUD + 运行日志 (4 路由)
- admin_llm LLM agents/models/ping (3 路由)
- admin_quality stats/data-completeness/data-quality (4 路由)
所有路由仍挂 /api/v1/admin 且带 dependencies=[Depends(require_admin)]。
app.py 注册方式不变(仍 import admin_settings.router)。
|
2026-09-21 23:28:58 +08:00 |
|
shangfangjian
|
66f0844798
|
feat: standings Bronze 血缘补齐 + 队名归一 MVP
standings 成功 upsert 后写入 RawEvent(source_record_id=standings:{league}:{season})
+ DataLineage(target_table=standings),与 events/stats 管线对称。
队名归一化收敛到 TeamRepository.get_or_create 唯一咽喉点,
创建新 Team 时 info 日志打出原始名与归一后名;
Admin 新增 GET /api/v1/admin/team-name-duplicates 只读接口,
启发式列出近似重名候选(大小写变体/子串/前缀碰撞),不做自动合并。
|
2026-09-21 23:28:46 +08:00 |
|
shangfangjian
|
317a5e338a
|
refactor: bzzoiro.py 按管线拆分为 5 个模块
单文件 852 行按职责拆分,保持 BzzoiroSource 与 get_source("bzzoiro") 行为不变:
- bzzoiro_common HTTP 抓取(多 key 轮换) + 字段转换原语
- bzzoiro_events fetch_bzzoiro_events + BzzoiroSource.ingest + Bronze 补写
- bzzoiro_standings standings 管线
- bzzoiro_stats stats 回填
- pipeline_write RawEvent/IngestFailure/DataLineage 写入助手
子模块运行期经聚合门面 src.data.bzzoiro 解析可替换协作者,
单文件时代的 bz.* monkeypatch 语义完全保留。
路由 import 已指向新模块(ingest.py / schedules.py)。
|
2026-09-21 23:27:48 +08:00 |
|
WorkBuddy
|
a24017eb69
|
feat(api): 比赛上下文与联赛列表改公开只读(P1-2/P1-3)
- GET /matches/{id}/context 移除 require_admin:公开站详情页「近况/交锋」
数据来源,匿名 401 会导致前端静默空态;响应结构不变,不触发 LLM
- GET /leagues 改公开只读:公开站联赛筛选动态加载;仅返回
id/code/name/country 四个展示字段,不含配置或密钥信息
- 前端新增 useLeagues hook:优先请求 /api/v1/leagues,失败/空回退
本地五大联赛常量(已知代码保留中文标签,新联赛按 API 名称追加)
- 新增 tests/test_public_readonly_api.py(6 项):匿名 200/404、响应形状、
路由依赖声明检查(matches 路由无 require_admin)+ 判别力守卫
(ingest 路由必须检出 require_admin,防检测器恒真)
|
2026-09-21 20:55:26 +08:00 |
|
WorkBuddy
|
5c7fdce0a3
|
debt(D2): 统一预测结果类型为 PredictResult,路由去 dict 分支
- PredictResult 扩展可选字段 mode/agent_outputs/agent_weights/prompt_tokens/completion_tokens
- MultiPredictResult 变为 PredictResult 别名(保留 R4 守卫标记与 re-export)
- baseline 改返回 PredictResult(修复 backtest 对 baseline AttributeError 的潜伏 bug)
- 预测路由单一属性映射,删除全部 isinstance(result, dict) 分支
- _persist_baseline 属性化,baseline upsert 语义不变(prompt_version/token/latency 同前)
- TDD: 5 新测试 + test_baseline.py 属性化;全量 257 passed
|
2026-09-21 19:23:50 +08:00 |
|
shangfangjian
|
8c87b9d024
|
fix(critical): 修复调度器静默失效、数据源缺失与前端类型错误
C1 定时任务静默失效(4 层缺陷):
- scheduler.py: croniter(expr, datetime.now) 未调用 now(),
导致 TypeError 被吞、next_run 恒为 None(最深一层)
- scheduler.py: _calc_next 非法 cron 静默吞异常 -> 改为构造期抛 ValueError
- scheduler.py: _run_loop 一次异常即永久停摆 -> 增加异常隔离
- scheduler.py: sleep(min(wait,60)) 使运行期 cron 变更最长 60s 才生效
-> 改为固定 SLEEP_TICK 轮询
- app.py / schedules.py: 3 处 register() 第 2 参误传 task 类型名
C3 EvalPage.tsx: 引用未导入的 EmptyState -> 改为已导入的 EmptyText
(tsc --noEmit 由 1 error 变为 0 error)
新增 tests/test_scheduler_registration.py: 9 项行为回归测试
|
2026-09-21 17:04:04 +08:00 |
|
 shangfangjianandnew-provider/LongCat-2.0 <
|
ae89d0f04f
|
feat: 数据采集管线基础设施接线 + 数据管线管理页
后端:
- bzzoiro 采集成功后写入 RawEvent(Bronze 层原始事件存档)
- 采集失败写入 IngestFailure(死信队列,支持重试)
- 写入 DataLineage(ETL 血缘追踪)
- 新增 DataQualityScheduler(每小时自动质量检查)
- 新增 /api/v1/admin/data-quality 端点(质量检查 + 手动触发)
- 新增 /api/v1/admin/ingest-failures 端点(失败记录 + 重试)
- 新增 /admin/llm/ping 端点(LLM 连通性测试,不依赖比赛)
- lifespan 启动 quality_scheduler
前端:
- 新增「数据管线」管理页(/admin/data-pipeline)
- 采集失败记录列表(状态/重试次数/错误类型)
- 数据质量检查结果(通过/未通过/严重度)
- 手动触发质量检查按钮
- 失败记录重试按钮
- 预测历史:比赛信息内嵌(日期/队名/主客徽标/赛果自动填充)
- 导航统一为 React Router Link
- AdminStats 类型扩展(matches/stats/standings 真实计数)
Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
|
2026-09-21 10:04:26 +08:00 |
|
 shangfangjianandnew-provider/LongCat-2.0 <
|
b6e367a640
|
Code Review 第二轮修复:前端 HTTP 统一 + 数据采集可靠性
F1: 统一前端 HTTP 客户端
- 新增 frontend/src/lib/http.ts(共享客户端,统一超时/错误/401 处理)
- Matches.tsx 的列表/分页/进行中/预测请求改用 http 客户端
- 公开站与 Admin 行为一致
D2: events 采集按联赛分批提交
- _run_bzzoiro 改为 per-league 独立事务,避免超长事务
- 单联赛失败不影响其他联赛
F3: 仪表盘真实计数
- admin_stats 补充 matches/stats/standings 真实聚合
- Dashboard 展示比赛总数/已完赛/统计行/积分榜
F4: LLM 连通性测试不依赖 match_id=1
- 新增 POST /admin/llm/ping 端点(只发一次 chat,不依赖比赛)
- testLLMConnection 优先调用 ping,失败回退旧方式
F5: 导航改用 React Router Link
- App.tsx 中 <a href> 全部替换为 <Link to>
D5: 删除 away_possession 死代码
- bzzoiro.py 中移除计算与注释
D1: 管线基础设施表文档化
- RawEvent/IngestFailure/DataQualityCheck/DataLineage 添加「预留未启用」注释
Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
|
2026-09-21 03:06:52 +08:00 |
|
 shangfangjianandnew-provider/LongCat-2.0 <
|
675e176603
|
fix: 修复 Code Review 发现的 4 个 High + 1 个 Medium 问题
High-1/2: baseline mode 违反 DB CHECK 约束
- ck_mode_enum 扩展为 ('single','multi','baseline')
- baseline 的 run_type 从 'baseline' 改为 'live'(符合现有约束)
- 新增迁移 0017_mode_baseline
High-3: 限流日志 NameError: ip 未定义
- deps.py:190 的 logger.warning 中 ip → client_ip
High-4: 生产 Cookie 缺少 Secure 标志
- auth.py 登录时根据 APP_ENV 设置 secure=True(生产)
Medium-5: 降级日志参数类型错误
- orchestrator.py:266 ok_reports(list) → len(ok_reports)(int)
附加: PredictRequest mode 字段加 pattern 校验,与 DB 约束同源
Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
|
2026-09-21 02:44:32 +08:00 |
|
shangfangjian
|
0a6af0657a
|
预测历史:比赛信息内嵌到预测API + 实际比分自动填充
后端:
- PredictionOut 新增 match 字段(内嵌比赛信息)
- list_predictions 返回完整比赛数据(日期/队名/赛果/主客徽标)
- 新增 _match_dict() 辅助函数序列化比赛对象
前端:
- 移除独立的 fetchMatches 调用,直接使用 p.match
- 实际比分自动从比赛赛果填充
- 显示:比赛日(M/D) + 主客队徽标 + 队伍中文名
- 赛后一键结算(使用比赛实际赛果)
Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
)
|
2026-09-21 01:54:30 +08:00 |
|
shangfangjian
|
a9e85a5d62
|
修复定时任务更新接口:支持部分更新
PUT /schedules/{id} 原来要求完整 ScheduleIn(所有字段必传),
前端只传 {enabled} 时因缺少 task/cron 校验失败。
→ 新增 ScheduleUpdate schema(所有字段可选)
→ update_schedule 仅更新提供的字段
→ 使用最终值同步调度器
Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
)
|
2026-09-21 01:45:19 +08:00 |
|
 shangfangjianandnew-provider/LongCat-2.0 <
|
0a5a14cbbb
|
采集任务支持手动触发 + 定时调度(cron)
后端:
- 新增 Scheduler + ScheduledTask 核心模块(croniter 解析 cron 表达式)
- 新增 Schedule 数据模型(alembic 0016)
- 新增 /api/v1/admin/schedules CRUD 接口
- lifespan 启动时注册默认定时任务并加载数据库配置
- 默认任务:每日比赛/积分榜/30分钟统计回填(默认禁用)
前端:
- 设置页新增「定时任务」管理区块
- 支持:新建/启用禁用/立即执行/删除定时任务
- 显示:任务ID、类型、cron表达式、上次执行时间/状态
依赖:新增 croniter>=2.0
Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
|
2026-09-21 01:36:54 +08:00 |
|
 shangfangjianandnew-provider/LongCat-2.0 <
|
c586a38b3a
|
修复积分榜"body stream already read"错误
两个根因:
1. src/api/routes/standings 端点使用 func.max() 但未导入 func → NameError(500)
→ 在 matches.py 的 sqlalchemy 导入中加入 func
2. 前端 api.ts 错误处理中先调 res.json() 失败后回退 res text(),
但 Response body 流只能读一次 → "body stream already read"
→ 改为先 res.text() 再 JSON.parse(),避免重复读取
Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
|
2026-09-20 20:05:40 +08:00 |
|
 shangfangjianandnew-provider/LongCat-2.0 <
|
f52ec8b963
|
feat: bzzoiro 多 API Key 轮换,遇限流自动切换
新增 KeyRing 轮换环(src/data/key_ring.py):
- 支持逗号/分号/换行分隔多个 key,单 key 场景零开销
- 遇到 429 自动标记当前 key 冷却(默认 60s)并立即切换到下一个 key
- 全部 key 冷却时等待最早恢复的 key,避免无谓重试
- 热更新 key 列表(增删 key 无需重启)
- 进程级单例,按 base URL 隔离
后端集成:
- bzzoiro._fetch_json_async 接入 KeyRing,429 立即轮换(不等待)
- 新增 /admin/keyring/status 端点展示 key 环状态
- 新增 /admin/keyring/cooldown/reset 紧急重置冷却
- BZZOIRO_KEY 配置描述提示多 key 支持
- mask_value 多 key 显示数量(如 "3 个 key(末段 …XXXX)")
- 清理已移除 injuries 的 API_FOOTBALL_KEY 配置项
前端:
- 数据源页新增 Key Ring 状态面板(每个 key 可用/冷却状态 + 重置按钮)
- 配置项脱敏展示支持多 key 计数
测试: 新增 24 个 KeyRing 单元测试 + 2 个 bzzoiro 轮换集成测试,全部通过。
Co-Authored-By: new-provider/LongCat-2.0 <<EMAIL>>
|
2026-09-20 19:40:20 +08:00 |
|
 shangfangjianandnew-provider/LongCat-2.0 <
|
f05dc1ae15
|
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>>
|
2026-09-20 19:13:07 +08:00 |
|
shangfangjian
|
7b1457f0db
|
fix: 后端 API 修复
- deps.py: 依赖注入优化
- matches.py: 比赛列表查询修复
- predict.py: 预测接口参数校验修复
- orchestrator.py: 多 Agent 编排逻辑修复
|
2026-09-20 08:45:19 +08:00 |
|
shangfangjian
|
8e6ad5394e
|
fix:批量修复了一些问题
|
2026-09-19 22:51:35 +08:00 |
|
Profeto Agent
|
835d7217d0
|
完善评估能力:筛选参数 + degraded 排除 + 前端评估页
后端:
- settle_prediction 拒绝 degraded/failed(明确错误信息)
- get_eval_summary 支持 provider/model/prompt_version/mode 筛选
- 返回 filtered_settled/evaluated/skipped_degraded 等计数
- matches 游标分页方向修复(scheduled ASC 用 > 条件)
- available_at 加 2h 缓冲(近似完赛时间)
- bzzziro 统计字段映射注释(待真实响应验证)
- injuries 区分 no_local_data 与 success 空名单
前端:
- 新增 EvalPage(筛选控件 + 汇总卡片 + 准确率表格)
- 挂载 /admin/eval 路由与导航
测试:
- test_matches_cursor.py:游标方向
- test_available_at.py:2h 缓冲与回测防泄漏
- test_bzzoirot_stats.py:统计字段映射
- test_injuries_no_local_data.py:no_local_data vs success
- test_injuries_inserted_count.py:失败批不计入
- test_eval_excludes_degraded.py:degraded 排除准确率
|
2026-09-19 09:40:24 +00:00 |
|
Profeto Agent
|
6c24672e87
|
安全加固 + 数据管线修复 + 质量改进(第2批)
安全加固:
- /api/v1/predict 限流改用 get_client_ip 防 X-Forwarded-For 伪造
- 新增 TRUST_PROXY_HEADERS/REQUIRE_ADMIN_AUTH 配置,默认 fail-closed
- 生产环境管理接口未配置鉴权时拒绝(503),不再放行
数据管线修复:
- injuries IntegrityError 改用 begin_nested(SAVEPOINT)隔离批次
- injuries 空名单 vs 未配置语义区分(has_data 精确标记)
- bzzoiro 统计字段映射(shots/possession/cards) + 入库条件放宽
- available_at 语义收紧(回测防泄漏)
- team_names NFKD 去变音双重查找 + 补齐变体键
预测系统改进:
- multi-agent 全专家失败时 status=degraded 跳过终裁
- agent_weights 独立持久化到 predictions 表
新增迁移:
- 0014_predictions_agent_weights.py
新增测试(8个文件):
- test_ip_spoofing.py: 限流防伪造
- test_require_admin_fail_closed.py: 生产 fail-closed
- test_injuries_integrity_rollback.py: SAVEPOINT 隔离
- test_injuries_slice_semantic.py: 空名单 vs 未配置
- test_available_at.py: 回测防泄漏
- test_bzzoirot_stats.py: 统计字段映射
- test_team_names_normalize.py: NFKD 变体
- test_multi_agent_degraded.py: 全失败 degraded
- test_agent_weights_persist.py: 权重持久化
|
2026-09-19 08:02:57 +00:00 |
|
Profeto Agent
|
bee330f31f
|
全量修复:预测系统正确性、安全性与部署问题
P0 严重问题修复:
- 修复 form_slice/stats_slice 主客身份反转(历史比赛视角错误)
- 修复 understat.py httpx 未导入导致的 NameError
- 修复 LLM 解析失败时静默产生假成功预测(0-0 平局+置信度0.5)
预测路径修复:
- multi-agent 路径增加 backtest cutoff 透传,回测防泄漏生效
- H2H 切片汇总统计改为从当前主队视角计数
- 预测唯一约束增加 mode+run_type 维度,防止回测覆盖实盘预测
伤停管线修复:
- IntegrityError 后不再整批回滚丢数据(改用逐条 flush)
- return_date 正确解析并写入
- retrieved_at 比较统一用 date() 避免当天数据不可见
- 唯一索引改为 partial unique index(排除 NULL 重复)
- HTTP 缓存 TTL 从 7 天改为 6 小时
安全与连接管理:
- /api/v1/predict 增加内存滑动窗口限流(10次/分钟/IP)
- 预测路由改用短 session 模式,LLM 调用期间不持有 DB 连接
Docker 部署修复:
- 修复 .dockerignore 排除 *.md 导致 COPY README.md 失败
- 容器内 DATABASE_URL 使用 postgres 服务名(非 localhost)
- 启动时自动执行 alembic upgrade head
- 前端改用多阶段构建(Dockerfile.frontend)
新增测试(5个文件,24+用例):
- test_p0_home_away.py: 主客身份反转回归测试
- test_p0_parse_failure.py: LLM 解析失败回归测试
- test_multi_agent_cutoff.py: multi-agent cutoff 透传测试
- test_h2h_perspective.py: H2H 视角测试
- test_injuries_pipeline.py: 伤停管线 5 项修复测试
- test_predict_protection.py: 限流+短 session 测试
- test_prediction_unique_constraint.py: 唯一约束测试
迁移:
- 0012_injuries_partial_unique_and_return_date.py
- 0013_predictions_unique_constraint_mode_run_type.py
|
2026-09-19 06:43:55 +00:00 |
|
Profeto Agent
|
11efe91ce9
|
fix: 全方位审查问题修复(P0~P3)
P0: ORM-迁移同步
- 新增 RawEvent/IngestFailure/DataQualityCheck/DataLineage 4 个模型类
- MatchStats 补充 xg_source/xg_updated_at/xg_source_record_id 字段
- 修复 server_default=_utcnow → func.now()(4 处)
- BigInteger 导入
P1:
- log_buffer.py 移除 threading.Lock(asyncio 单线程下无需锁)
- 确认 context_builder/understat/injuries 等已有修复
P2:
- Dockerfile 新增非 root 用户 + .dockerignore
- 前端 fetchDashboard 修复 total 字段(改用 items.length)
- 前端 fetchSystemConfig 改用真实 /admin/settings 端点
- 修复 validation.py return self"" → return self
P3:
- predict.py 缓存加 _CACHE_MAX_SIZE=200 淘汰
- eval.py get_eval_summary 加 limit 参数(默认 1000)+ 返回 total_settled
- orchestrator.py agent provider 配置缓存 60s
|
2026-09-19 04:38:53 +00:00 |
|
shangfangjian
|
786f10aa11
|
feat: 核心模块增强 — 加密 + 运行时配置 + 日志缓冲
- crypto.py: API Key 加密/解密工具
- runtime_config.py: 运行时动态配置管理
- log_buffer.py: 内存日志缓冲区
- config.py: 新增加密配置项
- http_client.py: 增强重试和错误处理
|
2026-09-19 11:58:03 +08:00 |
|
WorkBuddy
|
c89bfe2af7
|
fix(P2): no_data 结构化、权重校验、鉴权与前端竞态
P2-1 no_data 门控依赖文案子串(脆弱):
- context_builder 新增 SliceResult(text/has_data/n_records),
5 个切片函数改为显式声明 has_data
- base._slice_has_data() 优先取结构化结果,str 返回仍走文案回退
(兼容既有测试 mock 与自定义切片)
- build_context 的 has_stats/has_injuries 直接取切片声明
P2-2 agent_weights 无校验即落库:
- validation 新增 AgentWeightsSchema / validate_agent_weights:
未知专家名丢弃、越界值钳制、总和非 1 时归一化
- orchestrator 落库前对 agent_weights 做校验
P2-3 1x2 与比分不一致被静默修正:
- 仍以比分修正,但补 logger.warning 暴露 LLM 自相矛盾
P2-5/P2-6 prompt 缓存不可刷新 + 缓存键不含模板内容:
- 新增 clear_prompt_cache() 供改模板后显式失效
- 缓存键纳入模板内容 hash,模板一改缓存自动失效
P2-7 ingest/backtest/settle 接口无鉴权:
- 新增 require_admin_key 依赖(X-API-Key),
ADMIN_API_KEY 未设置时放行并告警(不破坏本地开发)
- 挂到 3 个 ingest 接口 + backtest + eval/settle
P2-8 前端请求竞态 + 未使用游标分页:
- Matches.tsx 用递增 seq 丢弃过期响应,避免旧筛选结果覆盖新筛选
- 接入后端已有的 cursor 分页 + 「加载更多」按钮
附带: .env.example 补齐 LLM_TIMEOUT / 分档模型 / ADMIN_API_KEY;
tests 新增 10 个用例覆盖 P2-1/2/3。
|
2026-09-15 16:54:05 +08:00 |
|
shangfangjian
|
60e4b89822
|
docs: 统一文档与代码一致性
- 修复所有 confidence → subjective_confidence 残留(03-api, 04-agents, 05-data, 07-development)
- 修复 5 张表 → 6 张表残留(06-deployment)
- 同步 API schema 示例与实际模型一致
- 更新 predictions 表结构文档(新增 status/cutoff/input_hash 字段)
code: 修复 API 异常处理(eval/predict)和 context_builder stats 时间过滤
|
2026-09-15 02:27:48 +08:00 |
|
shangfangjian
|
0980c2242a
|
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 精度
|
2026-09-15 02:04:25 +08:00 |
|
shangfangjian
|
2c205c68b1
|
fix: 修复剩余审查问题
- ingest.py: 异常不再暴露客户端,改为通用错误消息+日志记录
- bzzoiro.py: 修复 normalize 重复调用,改为一次遍历缓存结果
- understat.py: 使用 Repository 替代原始 SQL
|
2026-09-15 01:26:15 +08:00 |
|
shangfangjian
|
53e602b4f6
|
fix: 代码审查问题修复
- unit_of_work.py: 简化为纯 session 上下文管理器,消除 double-close 风险
- validation.py: 移除未使用的 import,简化 _score_to_1x2 逻辑
- repositories.py: 将 func 导入移到模块顶层
- 更新所有 get_uow() 调用点使用新接口(yield session 而非 uow 对象)
|
2026-09-15 01:18:35 +08:00 |
|
shangfangjian
|
483cb956ba
|
refactor: Sprint 3 - 引入 UnitOfWork + Repository 架构
新增:
- src/db/unit_of_work.py: UnitOfWork 事务封装
- src/db/repositories.py: Match/Team/League/Prediction Repository
重构:
- 删除 src/data/match_lookup.py(由 Repository 替代)
- 数据源(bzzoiro/understat/injuries)不再自行 commit
- API 路由(ingest)改用 UnitOfWork
- LLM 服务(predict/orchestrator/eval/backtest)改用 UnitOfWork
事务边界统一由调用方控制,数据层不再自行决定 commit。
|
2026-09-15 00:42:05 +08:00 |
|
shangfangjian
|
cb36dc3ef9
|
feat: Sprint 2 - 概率语义 + 轻量快照 + 数据库约束
P0-05: confidence → subjective_confidence 改名(15 文件)
LLM 主观置信度与概率分离
P0-02: predictions 增加 cutoff_at + input_hash(轻量快照)
MatchContext 暴露 match_dt
单/多 Agent 路径均记录快照元数据
P2-05: 数据库 CHECK 约束
- pred_home_goals >= 0
- pred_away_goals >= 0
- subjective_confidence 0~1
- pred_1x2 IN (1,X,2)
- mode IN (single,multi)
P2-06: limit 分页约束(ge=1, le=200)
P2-01: 新增 /health/ready 就绪检查
|
2026-09-15 00:14:24 +08:00 |
|
shangfangjian
|
1166a157ec
|
feat: 添加回测框架
- 新增 src/llm/backtest.py: 回测核心逻辑
- 查询历史已完赛比赛
- 逐场预测(自动防未来信息泄漏)
- 实际比分回填 + 统计
- 1X2 准确率 / 比分 RMSE / 置信度校准
- 新增 POST /api/v1/backtest 路由
- 支持按联赛/日期范围/模式/模型筛选
|
2026-09-09 21:39:56 +08:00 |
|
shangfangjian
|
0a27b18c27
|
feat: 足球 LLM 预测服务初始提交
Profeto — 给 LLM 提供数据,让 LLM 预测足球比分。
核心模块:
- FastAPI 后端 + PostgreSQL (SQLAlchemy async)
- 多 Agent LLM 预测 (5 专家 + 终裁)
- 数据采集 (bzzoiro / understat / injuries)
- React 前端 (Vite + Tailwind)
包含:
- 数据源抽象 (DataSource 协议 + 注册表)
- Alembic 数据库迁移
- Prompt 模板 (单/多 Agent)
- 核心路径单元测试
|
2026-09-09 02:10:47 +08:00 |
|