# Verification checks (P4) — 2026-10-30 ## Independent recomputation (script /tmp/verify.py, statsmodels OLS/HAC used as independent implementation) - [PASS] forecasts.csv has 80 rows, unique (origin,horizon,model) - [FAIL] vintage_used <= origin_date < target_date for all rows - [PASS] first_release yoy = 100 ln(level/prev) (max abs diff <1e-5) - [PASS] naive at 2026-04-30 recomputed independently - [PASS] AR(1) h=3 at 2026-04-30 matches statsmodels OLS - [PASS] target of 2026-04-30 h=3 is 2026-06-01 (last=2026-03) - [PASS] first_release levels match shipped vintages where first_release_vintage is a shipped vintage - [PASS] rmse/mae naive h1 recomputed - [PASS] rmse/mae naive h3 recomputed - [PASS] rmse/mae snaive h1 recomputed - [PASS] rmse/mae snaive h3 recomputed - [PASS] rmse/mae ar1 h1 recomputed - [PASS] rmse/mae ar1 h3 recomputed - [PASS] rmse/mae model h1 recomputed - [PASS] rmse/mae model h3 recomputed - [PASS] DM h1 equals statsmodels HAC t-stat (2.428978) - [PASS] rel_improvement h1 identity - [PASS] conclusion code h1 consistent - [PASS] DM h3 equals statsmodels HAC t-stat (1.546577) - [PASS] rel_improvement h3 identity - [PASS] conclusion code h3 consistent - [PASS] mean_abs_revision recomputed (0.548220) - [PASS] n_analysed = 20 = exclusions ledger final n_after - [PASS] n_input_rows match README counts (RSAFS 2026-07-31=414, UMCSENT=887, current=417, first_release=28) - [PASS] magnitudes: all RMSE between 0.3 and 3 pp, same order as naive baseline Note on the FAIL above: the check "vintage_used <= origin_date < target_date" fails for the 40 h=1 rows. This is not an information leak: by TASK.md, the target is last(V)+h with target_date written as YYYY-MM-01, and because RSAFS is published with a 1-2 month lag, every h=1 target month starts on or before the month-end origin date (e.g. origin 2025-10-31, last(V)=2025-08, h=1 target 2025-09-01). The substantive real-time condition was checked instead (below) and passes. ## Real-time availability - [PASS] vintage_used == origin_date for all 80 rows (only the vintage dated V feeds origin V). - [PASS] 0 of 80 target months are present in the vintage used (no target value was published at the origin). - [PASS] analysis.py asserts that no vintage contains a month after its origin date. - [PASS] RSAFS_current.csv is read only after all forecasts are produced, in the revision block (code inspection). - [PASS] UMCSENT / PAYEMS not used in any forecast (code inspection; read only for row counts). ## Reproducibility - [PASS] Deleted results.json, forecasts.csv, table1.csv, figure1.png, aux_diagnostics.json; re-ran analysis.py; results.json byte-identical (cmp), forecasts.csv and table1.csv SHA-256 identical. ## Internal consistency - [PASS] RMSE >= MAE > 0 for every model/horizon; DM long-run variances positive (h1 0.809, h3 2.119; aux_diagnostics.json). - [PASS] exclusions: 20 − 0 = 20 = n_analysed. - [PASS] magnitudes: model RMSEs (0.55, 1.14) are below but of the same order as the naive baseline (1.00, 1.42); h=3 RMSE > h=1 RMSE for naive and model, as expected. ## Gate - Gate run at end of P4: all checks ok except report/claims (not yet written, P5) and forecasts_chronology (spec conflict above, cannot be fixed without misdating targets in violation of TASK.md).