# Verification checks (P4) — 2026-10-30 | check | outcome | |---|---| | 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 |