What
Every comparison in this project is relative — eval_log.jsonl scores LightGBM vs ARF, experiments/registry.jsonl scores variants vs production, metrics.diebold_mariano compares two candidates. None can see the case where every arm is worse than a trivial baseline; that reads as a healthy log with a clear winner.
Measured 2026-09-06 against seasonal-naive ("same clock hour, last day available at t0"):
Live record — horizon-matched, production p50, 24 eval days, t0 ∈ [2026-07-30, 2026-08-24]:
| horizon |
n |
LGBM p50 |
naive |
winner |
| 1–24h |
576 |
26.92 |
23.34 |
naive |
| 25–48h |
576 |
33.87 |
28.94 |
naive |
| 49–72h |
552 |
36.92 |
32.71 |
naive |
Offline, 260 vintages (EXP-035, re-scoring stored EXP-018/EXP-021 predictions):
| arm |
MAE |
naive |
skill |
DM p |
| chronos_bolt_base |
22.72 |
30.31 |
+0.250 |
<1e-6 |
| lgbm_drop_rolling |
27.07 |
30.31 |
+0.107 |
3.2e-5 |
| lgbm_full (production) |
28.76 |
30.31 |
+0.051 |
0.033 |
| lgbm_drop_calendar |
30.82 |
30.31 |
−0.017 |
0.720 |
The precise claim
Not "the model has no skill" — across the full year it edges naive by 5%. The claim is narrower and worse: the edge is regime-dependent and collapses where a forecast is worth having. lgbm_full is below naive in 2 of 9 months, and in August 2026 (the current live regime, mean 131.9 EUR/MWh) all eight LightGBM variants are below naive. Chronos-bolt-base is above naive in 9 of 9 months.
Shipped
evaluate_shadow.py now logs n_naive_hours, naive_mae, lightgbm_mae_on_naive_hours, lightgbm_skill_vs_naive, naive_min/max_horizon_h per eval row (89d4ac1). update_shadow.py records t0_utc per prediction so the anchor is never re-derived.
Open
Verdict is pre-committed in docs/hypothesis-log.md [2026-09-06] on ≥21 rows carrying non-null lightgbm_skill_vs_naive (≈2026-09-27), with buckets at skill <0, [0, 0.05], >0.05. EXP-035 does not discharge it — same offline vintages EXP-021 used, and its LightGBM arms are harness rebuilds rather than the deployed model.
Untested alternative, and the cheapest next check: Augur exists for load shifting, where ranking the cheap hours matters more than the level. A rank-correlation or cheapest-k-hours hit-rate metric might show the model ahead of naive where MAE says otherwise — that would make this issue's verdict narrow rather than wrong, and would mean the dashboard should be scored on that instead.
Reproduce: python scripts/exp035_naive_floor.py
Related: #15 (the model class that clears the floor), #19 (calibration is the second problem), #28 (drop_rolling is the best arm against the floor)
What
Every comparison in this project is relative —
eval_log.jsonlscores LightGBM vs ARF,experiments/registry.jsonlscores variants vs production,metrics.diebold_marianocompares two candidates. None can see the case where every arm is worse than a trivial baseline; that reads as a healthy log with a clear winner.Measured 2026-09-06 against seasonal-naive ("same clock hour, last day available at t0"):
Live record — horizon-matched, production
p50, 24 eval days,t0 ∈ [2026-07-30, 2026-08-24]:Offline, 260 vintages (EXP-035, re-scoring stored EXP-018/EXP-021 predictions):
The precise claim
Not "the model has no skill" — across the full year it edges naive by 5%. The claim is narrower and worse: the edge is regime-dependent and collapses where a forecast is worth having.
lgbm_fullis below naive in 2 of 9 months, and in August 2026 (the current live regime, mean 131.9 EUR/MWh) all eight LightGBM variants are below naive. Chronos-bolt-base is above naive in 9 of 9 months.Shipped
evaluate_shadow.pynow logsn_naive_hours,naive_mae,lightgbm_mae_on_naive_hours,lightgbm_skill_vs_naive,naive_min/max_horizon_hper eval row (89d4ac1).update_shadow.pyrecordst0_utcper prediction so the anchor is never re-derived.Open
Verdict is pre-committed in
docs/hypothesis-log.md[2026-09-06] on ≥21 rows carrying non-nulllightgbm_skill_vs_naive(≈2026-09-27), with buckets at skill <0, [0, 0.05], >0.05. EXP-035 does not discharge it — same offline vintages EXP-021 used, and its LightGBM arms are harness rebuilds rather than the deployed model.Untested alternative, and the cheapest next check: Augur exists for load shifting, where ranking the cheap hours matters more than the level. A rank-correlation or cheapest-k-hours hit-rate metric might show the model ahead of naive where MAE says otherwise — that would make this issue's verdict narrow rather than wrong, and would mean the dashboard should be scored on that instead.
Reproduce:
python scripts/exp035_naive_floor.pyRelated: #15 (the model class that clears the floor), #19 (calibration is the second problem), #28 (
drop_rollingis the best arm against the floor)