shangfangjian
|
06e973d34d
|
fix(concurrency): 消除 model 覆盖的模块级变量中转(并发串味)
R4 首版实现用模块级 _ACTIVE_MODEL_OVERRIDE 中转 model override,
理由是不想改动 run_specialists 的签名(既有测试会 mock 它)。
但 backtest.py:225 会 asyncio.gather 并发 8 场预测(Semaphore(8)),
每场都调用 predict_match_multi —— 模块级变量会被并发调用互相覆盖,
导致 A 场的预测用上 B 场的模型。这是静默的正确性缺陷。
改为: run_specialists 新增 model_override 形参,一路显式下传;
删除模块级变量。同步更新 6 处 mock 签名。
新增 3 个守卫并做变异验证:
- test_r4_no_module_level_model_override_global (源码级,可判别)
- test_r4_run_specialists_accepts_model_override_parameter
- test_r4_dispatch_passes_override_to_specialists
变异测试: 重新引入全局变量方案 → 两个守卫变红;还原 → 全绿。
注: 曾尝试写并发行为测试,但真实 run_specialists 会访问数据库,
测试环境下不稳定(ConnectionRefusedError),会是 flaky 的假证据,
故改用清晰的源码级判别守卫,并在注释中说明原因。
240 passed / 1 skipped; tsc 0 error; vite build 成功。
|
2026-09-21 17:52:45 +08:00 |
|
shangfangjian
|
50a6753ff8
|
test: 修正 selectin 守卫的假阳性(变异测试发现)
原断言对「关系声明到下一注解」的整段(含注释)做 lazy="selectin"
子串匹配;而 Match.league 声明正下方的注释里恰好也写着该字样,
导致移除真实 kwarg 后测试依旧通过(变异测试确认)。
改为只匹配 relationship(...) 括号内内容,并加注释说明该假阳性。
验证: 干净代码通过 → 移除 league 的 lazy 后失败 → 还原后又通过。
全套 238 passed / 1 skipped。
|
2026-09-21 17:36:07 +08:00 |
|
shangfangjian
|
951faf31df
|
test: 修复 13 个腐化用例,套件恢复全绿且顺序无关
按「测试腐化(a)/ 源码缺陷(b)/ 测试污染(c)」逐项定性,仅改 tests/:
- 外机绝对路径(4): 迁移文件路径改为相对仓库根解析(沿用
test_regressions._read 约定),断言内容保持不变。
- cutoff 用例(4+1): mock 未生效的真因是 _agent_provider 被换成同步
lambda,await 抛 TypeError 被生产代码吞掉后 IndexError;改为 async
mock 并按 run_specialists/load_match_header/_agent_provider 的真实契约
打补丁。degraded 用例再加 _upsert_prediction 顶层 kwargs(model)采集。
- 陈旧断言(3): agent 键按现契约断言中文映射;h2h mock 改 async;
Match.stats 按设计为 lazy="select",从 MATCH_RELATIONS 移出并单独
固化该设计决定。
- P0-3 守卫(1): seg 越界扫到下游 stats 管线导致误报,改为按缩进收口;
合法形状含经 raw 派生变量中转的写法,并补元测试确保守卫仍能抓到回归。
- 交叉污染(6): test_multi_agent_cutoff 用 patch.object 精确还原,消除
裸赋值泄漏的同步 mock;现已验证顺序无关。
|
2026-09-21 17:31:36 +08:00 |
|
shangfangjian
|
11da4d3631
|
fix(critical): 修复评审确认的 R1-R5 五处缺陷
R1 429 key 轮换路径调用不存在的 _km → NameError(且位于凭证脱敏日志行):
改用 src/data/key_ring._mask,全树不再有 _km 调用。
[注: 该改动已随另一工作流提交 9ccda4b 一并入库]
R2 ingest_bzzoiro_standings 被截断(return 前无 upsert 逻辑,standings 表
永不写入、total_upserted 恒为 0):从 f05dc1a 移植完整实现,按
(league_id, season, team_id) upsert,保留逐联赛错误隔离,不加 db.commit()。
[注: 同上,已随 9ccda4b 入库]
R3 src/llm/agents/orchestrator.py 完成日志把 list 喂给 %d → logging TypeError:
改为 len(ok_reports),与同文件降级日志行写法一致。
R4 mode=multi 静默丢弃调用方传入的 model:predict_match_multi 新增
model 关键字参数,经 _ACTIVE_MODEL_OVERRIDE 下传至 _agent_provider,
显式 model 优先级最高;override 生效时跳过 provider 缓存读写以免串味,
并在 predict.py 派发点透传。
R5 回测把字符串日期直接与 timestamptz 列比较:新增 _parse_date_bound 助手,
支持 YYYY-MM-DD / 完整 ISO / datetime / None,裸日期按 UTC 锚定,
结束日取当天末刻(闭区间,避免最后一天被静默排除),非法输入抛 ValueError。
新增 tests/test_review_required_fixes.py 覆盖 R1-R5(R2/R4 为行为测试),
20 项全通过。
|
2026-09-21 17:19:24 +08:00 |
|
shangfangjian
|
b9d7b6423e
|
test(c2): 补齐导入次序回归,注明环状导入为预期且可自愈
test_bzzoiro_source_registry.py 增至 11 项:
- 新增 TestImportOrderSelfHeal:用独立子进程验证两种真实导入次序
(sources 先 / bzzoiro 先)下注册表均可用。该缺陷只在真实模块初始化
时序下成立,mock 照不出来,故不 mock。
- 新增未知名字仍抛 ValueError 的契约守卫。
src/data/sources.py:补全 _load_sources 文档,说明首次装载失败属正常的
环状导入(bzzoiro 仍在初始化),失败时保持 _loaded=False 使后续
get_source()/list_sources() 调用可重试装载(自愈)。
验证:
- tests/test_bzzoiro_source_registry.py:11 passed
- 两种导入次序实测均输出 bzzoiro ['bzzoiro']
|
2026-09-21 17:13:57 +08:00 |
|
shangfangjian
|
9ccda4bf51
|
fix(critical): 恢复 bzzoiro events 采集管线,消除数据源注册表静默失效
C2 数据丢失修复。重构提交 6a49940 删除了 src/data/bzzoiro.py 中的
fetch_bzzoiro_events 与 BzzoiroSource 后未做替换,同时 sources.py 用
`try/except Exception: pass` 吞掉了 ImportError,导致:
- _SOURCES 注册表恒为空
- get_source("bzzoiro") 恒抛 ValueError("未知数据源: bzzoiro")
- src/api/routes/ingest.py 与 schedules.py 运行时全线失效,
且日志中无任何导入错误痕迹
修复内容:
1. 从 f05dc1a 恢复并移植 events 管线:
- fetch_bzzoiro_events():分页抓取 /events/(纯异步,复用现有 _fetch_json_async)
- @register class BzzoiroSource + ingest():保留原签名
(db, *, leagues, date_from, date_to, status),保持「不 commit,
事务由调用方 UnitOfWork 控制」的契约,并保留单联赛抓取失败的
错误隔离(记录 error 后 continue)
- 复用现有 _to_date / _to_int_or_none / _match_key,未重复定义
- 血缘字段继续使用与 nm 配对的 raw(避免 P0-3 回归)
2. sources.py:导入失败改为 logger.exception 记录,新增 _loaded 标记
保证 _load_sources() 至多执行一次;失败时不置位以便后续重试。
get_source() 对真正未知的名字仍抛 ValueError。
验证:
- 新增 tests/test_bzzoiro_source_registry.py(8 项):注册表非空、
get_source/list_sources 可用、ingest 签名契约、不再静默吞异常
- test_regressions.py:3 failed -> 2 failed
- 全量:14 failed -> 13 failed,通过数 190 -> 199
注意事项:未改动任何 caller(routes/ingest.py、routes/schedules.py 原样
可用,证明签名保持正确)。
|
2026-09-21 17:10:17 +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 |
|