Phase 3 — as-of data pipeline, leakage tests, baselines (2026-10-27)
Artefacts: scripts/01_build_analytic.py → data/processed/analytic.parquet (631,866 sales; house 422,542 / condo 122,976 / plex 86,348); 02_splits.py (train 379,310 / validation 72,132 / test 96,935 / holdout 83,489; LLM subsamples 240/600/300 over 35 strata; spatial-holdout flag 59,770 rows); 04_geo.py (flood coverage 39.9 % of rows, 1.18 % of those in a flood zone; 97.0 % DA match); 03_features.py → feature_matrix.parquet (35 numeric + 8 categorical; exact as-of neighbour features); 05_leakage_audit.py → results/data/leakage_audit.json (9/9 PASS). Two leaks caught and fixed during development: K-nearest neighbour capping let future sales crowd out past ones (existence leak); a positional join misaligned rolling municipality features.
Baselines: scripts/10_train_baselines.py (A hedonic ridge with municipality trends and grid FE; B hierarchical shrinkage + repeat-sales blend, w_repeat = 0.25 on validation; C LightGBM random search of 10 configurations tuned on validation, best num_leaves 255 / lr 0.02 / 256 rounds; D AVM = LightGBM point + 5 quantile models + split-conformal 90 % scaling; CatBoost and XGBoost as robustness; spatial-holdout retraining without Outaouais, Abitibi-Témiscamingue, Bas-Saint-Laurent). Prediction records in results/runs/baselines/predictions.parquet. Timings in the run manifest.
Failed checks: none in the audit. Note: calendar-quarter fixed effects cannot be extrapolated out of time; the hedonic uses municipality-specific linear trends + cubic global trend + month-of-year effects instead (documented in the code).