| Clean re-run (deleted results/forecasts/exclusions, re-ran analysis.py): byte-identical results.json and forecasts.csv |
PASS |
| forecasts.csv has 144 rows, 36 unique origins |
PASS |
| target_date = origin_date + h months for every row |
PASS |
| n_evaluated_h1 = n_evaluated_h3 = 35; 36 − 35 = 1 missing target per horizon (2025-10-01) |
PASS |
| RMSE ≥ MAE > 0 for all model/horizon pairs |
PASS |
| rel_improvement = 1 − rmse_model/rmse_naive (to 1e-12) |
PASS |
| first_origin < last_origin |
PASS |
| Exclusion ledger: 945 − 1 − 3 = 941 = n_analysed |
PASS |
| Naive forecast equals latest non-missing obs ≤ origin (incl. origin 2025-10-01 → 2025-09 value 4.4) |
PASS |
| Magnitude: model forecasts within 0.2 pp of naive; model RMSE within 3% of naive RMSE |
PASS |
| Information rule: training series truncated with s.loc[:t] at each origin (code inspection); model spec fixed a priori, not tuned on evaluation errors |
PASS |