SPB Git

spb/wp26_uqo

Public
7.0 KB

# Author: Simon-Pierre Boucher — simon-pierre.boucher@uqo.ca

# Phase 6 (addendum) — prospective evaluation set (2026-10-27)

Status at the time of writing: data layer, bundle, runner option, tests, documentation, baselines and the E and F live runs complete; the G (2-round debate) live run still running in the background (resumable, capped). The numbers in §4 are the state when this report was written; re-run the status commands in §5 for the final counts and append them here.

# 1. Artefacts

artefact content
data/raw/prospective_2026-10-27.parquet, prospective_units_2026-10-27.parquet, .manifest.json raw fetch (gitignored, contains addresses — never printed)
scripts/61_build_prospective.py WP 22 cleaning re-implemented on the new rows + WP 26 funnel → analytic contract; builds the runner bundle
data/processed/prospective_analytic.parquet 1,182 rows, ANALYTIC_COLUMNS, validate_analytic passes
results/data/prospective_summary.json manifest, funnel, exclusion flags, class / region / tercile counts, bundle summary
data/processed/prospective_bundle/{analytic,splits,llm_subsamples,geo_features}.parquet snapshot ∪ prospective (633,048 rows); split prospective; 40-row stratified subsample (18 strata); geo features
src/agentic_valuation/experiments/run_arm.py, scripts/30_run_arm.py RunSpec.data_dir / --data-dir (backward compatible; not among the freeze-hashed files)
tests/test_experiments_datadir.py 4 tests (defaults untouched; loads redirected; mock end-to-end run on a bundle; default manifest unchanged) — 8/8 pass with tests/test_agents_run_arm.py
scripts/62_prospective_baselines.py refit A/B/C/D (+CatBoost/XGBoost) with the 10_train protocol, predict the prospective rows
docs/prospective_set.md what, when, funnel, column mapping, bundle, extension procedure

# 2. Manifest and funnel

Fetch (read-only SSH, M3U96a live DB, 2026-10-27): 36,826 live rows dated ≥ 2026-07-01 → 1,444 new rows absent from the 2026-10-21 snapshot, dates 2026-10-06 … 2026-10-13, 1,434 roll units (every new row matched). Freeze digest recorded in the manifest: f0e9d6a94b0387f9….

Funnel: 1,444 → roll matched 1,444 → no WP 22 exclusion flag 1,251 (−193: land 96, non-residential 56, assessment-ratio outlier 26, same-parcel/same-date price conflict 8, shared parcel 5, multi-parcel candidate 2; duplicates of a snapshot sale 0) → class ∈ {house, condo, plex} 1,182 (−69) → coordinates / parcel id / price band / municipality lookup 1,182 (−0). 1,182 rows: house 856, condo 161, plex 165; Montréal CMA 459, Québec CMA 99, Outaouais 57, other 567; terciles 270 / 411 / 501; 321 with a prior snapshot sale; 0 new constructions; roll in force 2024-07-01 (391), 2023-07-01 (595), 2022-07-01 (192), earlier (4). Class source: roll 1,175, provider 7.

Subsample: stratified_subsample(..., n_by_split={"prospective": 40}), seed 20261027 → 40 rows, 18 strata (e.g. Montréal CMA|house|3: 7, other|house|1: 6, other|house|2: 6).

# 3. Runner change (diff summary)

RunSpec.data_dir: Path | None = None; data_base(synthetic, data_dir=None); load_analytic, select_subsample, feature_backend take data_dir; run_arm_async passes spec.data_dir; manifest gains data_dir and reports the actual data_source / geo_cache paths. CLI: --data-dir. Frozen prompts, configs, roles, protocols and aggregation untouched (check_freeze scope does not include experiments/run_arm.py).

# 4. Runs (state when this report was written — background jobs still running)

Chained by logs/prospective_runs.sh (log logs/prospective_runs.log), concurrency 3 because eight other live runs (final, final_small, holdout, validation ablations) share the keys:

run id arm n cap state
prospective_E_single_llm_mixed_random_mid E 40 10 USD done: 40 transcripts, 280 prediction rows, 40 calls, 0.82 USD, 0 failures, 0 turn errors
prospective_F_independent_mixed_random_mid F 40 30 USD done: 40 transcripts, 280 prediction rows, 480 calls, 9.36 USD, 0 failures (1 turn error, retried)
prospective_G_debate_r2_mixed_random_mid G r2 40 90 USD running (143 calls, 3.36 USD at the time of writing; ≈ 1.4 USD/property expected)

Mock dry run on the real bundle before going live: packets of prospective subjects carry no price, comparables are dated ≤ cutoff (sale date − 1), market index and geo context present.

Baselines (scripts/62_prospective_baselines.py --trials 10, 1,090 s, results/runs/prospective_baselines/): feature matrix on the bundle 452,624 rows in 62 s; as-of invariance max |Δ| = 0.0 on train/validation rows vs data/processed/feature_matrix.parquet; hyper-parameters, repeat-sales weight (0.15410) and conformal scale (1.07583) identical to the main run. Predictions: 7,092 rows (1,182 × 6 arms, split = "prospective"). Console summary on the 1,182 prospective sales (absolute log error; the formal evaluation with clustered uncertainty is 20_evaluate.py):

arm mean median
A_hedonic 0.2186 0.1430
B_hierarchical 0.2069 0.1252
C_gbm 0.2179 0.1452
C_catboost 0.2146 0.1346
C_xgboost 0.2218 0.1411
D_avm 0.2024 0.1297

# 5. Exact commands

text
python3 scripts/60_fetch_prospective.py
python3 scripts/61_build_prospective.py                 # --date 2026-10-27 ; --no-bundle
zsh logs/prospective_runs.sh                            # E → F → G, resumable (see docs/prospective_set.md §6)
python3 scripts/62_prospective_baselines.py --trials 10
python3 -m pytest tests/test_experiments_datadir.py tests/test_agents_run_arm.py -q
# status
grep -E "wrote|SPEND|Traceback|chain finished" logs/prospective_runs.log
for r in E_single_llm F_independent G_debate_r2; do ls results/runs/prospective_${r}_mixed_random_mid/transcripts | wc -l; done
python3 -c "import json,glob;[print(f, sum(json.loads(l)['cost_usd'] for l in open(f))) for f in glob.glob('results/ledger/prospective_*.jsonl')]"
tail -12 logs/62_prospective_baselines.log
# evaluation (after the runs)
python3 scripts/20_evaluate.py --split prospective --splits data/processed/prospective_bundle/splits.parquet

# 6. Decisions and open points

  • Geography by municipal-code lookup (not the snapshot's spatial join); boroughs imputed from the snapshot's municipality × 1 km cell mode (24 % filled). Documented in docs/prospective_set.md §3.
  • Prospective terciles use the snapshot's class cut points (the snapshot's own terciles are rank-based within the table; the two coincide at the cut points).
  • Sales dated 2026-10-06/07 fall inside the holdout window but were absent from the snapshot: they are prospective by construction (registered after the snapshot), not holdout rows.
  • The prospective sample covers one week of registrations and 40 LLM subjects: a consistency check of the test/holdout results, not a primary endpoint. Not evaluated yet (20_evaluate.py --split prospective once the runs finish). No git commit was made.
Files · b780d9effbc0d688f848faf14e38219f6088143b
Menu

Theme