| Clean re-run of out/analysis.py (deleted results.json, forecasts.csv, exclusions.csv) reproduces byte-identical results.json and forecasts.csv |
PASS |
| forecasts.csv has 192 rows, 48 per (model, horizon) |
PASS |
| target_date = origin + h months for all rows |
PASS |
| last_target_date_used <= origin − 2 months for all rows (GDP rule; incl. estimation sample) |
PASS |
| last_predictor_date_used <= origin − 1 month for model rows; empty for naive |
PASS |
| actual equals data gdp_yoy of target month |
PASS |
| naive forecast equals gdp_yoy(t−2) |
PASS |
| RMSE/MAE recomputed from ledger match results.json; rel_improvement identity holds |
PASS |
| MAE <= RMSE, all RMSE > 0 |
PASS |
| Exclusion ledger: 345 − (7+3+19) = 316 = n_analysed |
PASS |
| In-script asserts: 48 origins, no missing actuals, lt<=t−2, lp<=t−1 |
PASS |
| Magnitudes: model RMSE (0.74/0.95) below naive (0.81/1.14), same order of magnitude; plausible |
PASS |