| Clean re-run (results.json, forecasts.csv, exclusions.csv deleted, analysis.py re-run): byte-identical results.json and forecasts.csv |
PASS |
| forecasts.csv has 144 rows, 36 origins × 2 horizons × 2 models |
PASS |
| target_date = origin_date + h months exactly; target > origin for all rows |
PASS |
actual column equals data value at target (empty iff data missing: 2 pairs, target 2025-10-01) |
PASS |
| naive forecast = latest non-missing observation ≤ origin (incl. origin 2025-10 → 2025-09 value) |
PASS |
| n_evaluated_h1 = n_evaluated_h3 = 35 recomputed from ledger |
PASS |
| RMSE/MAE for both models and both horizons recomputed independently from forecasts.csv |
PASS |
| rel_improvement = 1 − rmse_model/rmse_naive recomputed |
PASS |
| MAE ≤ RMSE for every model/horizon; all RMSE > 0 |
PASS |
| Exclusion ledger: 945 − 1 − 3 = 941 = n_analysed |
PASS |
| No look-ahead: setting every observation after the origin to 99 leaves model forecasts unchanged (origins 2023-07, 2025-10, 2026-06; h=1,3) |
PASS |
| first_origin ≤ last_origin |
PASS |
| Magnitude vs baseline: model forecasts differ from naive by at most 0.016 pp (AR coefficients ≈ 0.04, −0.04), consistent with RMSEs within 2.4% of naive |
PASS (noted: model is nearly a random walk) |
| data/UNRATE.csv SHA-256 unchanged |
PASS |