SPB Git

spb/wp36_uqo

Public
13.1 KB · 115 lines markdown
1# WP36 — Data access and schema audit (Phase 0)23**Date of audit:** 2026-11-01 (snapshot taken 2026-11-01 ≈ 02:50 America/Toronto, last sync in snapshot 2026-11-01 06:49:42 UTC).4**Auditor:** lead research agent (Claude Code), on behalf of S.-P. Boucher (UQO).5**Status of the gate:** PASSED for H1, H2, H5 and the cross-sectional/dispersion parts of H4; CONDITIONAL for H3 (association only) and H6 (construction + internal validation only; no external forecasting test possible — see §7).67## 1. Source inventory (evidence-backed)89| Item | Finding | Evidence |10|---|---|---|11| Platform | Auto-Ka (www.auto-ka.com), independent Quebec used-vehicle aggregator built and operated by the author (Groupe KA). | `M4M64b:~/auto-ka/README.md`, `mld status` (node M4M64b, port 8095, PM2 `auto-ka-web` + `auto-ka-sync`). |12| Authorized access path | **Owner-approved, read-only copy of the production SQLite database** (`sqlite3 .backup`), taken on the production node, personal-account table dropped before transfer. No scraping of Auto-Ka, no use of the public HTTP API, no bypass of `robots.txt` (`Disallow: /api/`). | `data/raw/autoka-snapshot-20261101.db` (1.35 GB, mode 0444), SHA-256 in `data/raw/autoka-snapshot-20261101.db.sha256` (verified after transfer). |13| Documented API | FastAPI endpoints `/api/vehicles`, `/api/vehicles/{uid}` (includes price history), `/api/stats/*`, `/api/sources`, `/api/dealers` — documented in README but disallowed to crawlers; **not used** for this paper (the DB copy is strictly richer). | README §"API principale". |14| Upstream data-generation process | 143 registered sources (131 dealer websites "direct", 11 portals, 1 marketplace = Kijiji private sellers) crawled by 31 connector modules; each cycle re-reads every source, normalises each listing to one schema, hashes content, logs price changes, and marks a listing inactive after `MISS_GRACE = 2` consecutive absences; removals are suspended when a drift alert fires (volume ≤ 25 % of the 5-sync median, or ≥ 80 % null prices). VIN-based cross-source de-duplication elects a canonical listing. | `autoka/db.py` lines 150–310, `autoka/dedup.py`, `data/sources.json`. |15| Crawl cadence | Full cycle every ≈ 3.3 h on average (585 cycles between 2026-08-12 12:30 UTC and 2026-11-01 06:49 UTC; min 0.64 h, max 13.4 h; **no gap > 24 h** for any source). ≈ 7 observations per listing-day. | `sync_log` (83 531 rows). |16| Model APIs | **None required.** The paper uses no LLM/external model API; no credential verification needed. | — |1718## 2. Schema (tables kept in the research snapshot)1920| Table | Rows | Role / key fields |21|---|---|---|22| `vehicles` | 273 265 | One row per listing `uid = source:external_id`. Fields: make, model, trim, year, price, price_label, mileage_km, transmission, fuel, drivetrain, body_type, colours, engine, doors, seats, vin, stock_number, dealer_name, city, region, lat/lng, description, features (JSON), details (JSON), images (JSON), carfax_url, content_hash, `first_seen`, `last_seen`, `updated_at`, `miss_count`, `active`, `kind` (auto/moto/scooter), `dup_of`, `dup_sources`. |23| `price_log` | 428 484 | `(uid, ts, price)` — one row at first observation and **one row per price change** (not per observation). `price = NULL` = price withdrawn from display. |24| `sync_log` | 83 531 | One row per (source, cycle): found, added, updated, removed, ok, message, stats JSON (null-price rate, null-km rate, missed, alert). |25| `dealers` | 138 | Geocoded registry of direct dealer sources (address, phone, website, city, lat/lng). |26| `recalls` | 109 186 | Transport Canada recalls keyed by make/model/year (public data). |27| `vin_decode` | 4 655 | Decoded VIN attributes (partial coverage). |28| `detail_cache` | 77 039 | Opaque per-connector payload cache; not used. |29| `users` | — | **Dropped** from the research snapshot (personal accounts). |3031Timestamps are Unix epoch seconds (UTC). `first_seen` = first observation; `last_seen` = last observation; for inactive rows `updated_at` = time the listing was declared inactive (two consecutive misses after `last_seen`).3233## 3. Temporal coverage and panel structure3435| Quantity | Value |36|---|---|37| Observation window | 2026-08-12 12:32 UTC → 2026-11-01 06:49 UTC (**81 days**, 585 full crawl cycles) |38| Listings ever observed | 273 265 (auto 271 992; moto 1 218; scooter 55) |39| Active at snapshot | 62 821 (auto 62 052) ; inactive (exited) 210 444 |40| New listings per month (first_seen) | Aug 99 859 (incl. 46 k stock on day 1, **left-censored**) ; Sep 85 452 ; Oct 87 355 |41| Price observations | 428 484 rows for 270 909 uids; 61 962 uids with ≥ 2 price points, 26 576 with ≥ 3 |42| Monthly price-log rows | Aug 124 379 ; Sep 147 476 ; Oct 155 766 |43| Listing duration (inactive, all sources) | p10 0.74 d, p25 0.93 d, **p50 2.6 d**, p75 13.9 d, p90 35.1 d — the low quantiles are driven by *sampled* portals (see §5) |4445**A longitudinal listing panel therefore exists, but it is short (11.5 weeks) and starts with a left-censored stock.** Listing-level dynamics (H2, H5) are feasible; market-level time series (H6) have at most 81 daily / 11 weekly points.4647## 4. Field coverage (null rates, all 273 265 listings)4849| Field | Null/empty | Field | Null/empty |50|---|---|---|---|51| price | 1.7 % | make / model | 0.0 % / 0.0 % |52| mileage_km | 0.4 % | year | 0.1 % |53| trim | 5.6 % | VIN | 33.3 % (AutoTrader 100 %, Kijiji 79 %, Otogo 18 %, direct dealers ≈ 0 %) |54| body_type | 56.3 % | fuel | 35.1 % |55| transmission | 32.2 % | drivetrain | 37.7 % |56| region | 9.4 % | city | 1.7 % |57| lat/lng | 4.8 % | dealer_name | 0.0 % |58| stock_number | 57.8 % | exterior colour / engine | 56 % / 57 % |5960Price integrity: 2 164 listings at price ≤ 1 $ (placeholders), 29 between 1 and 500 $, 1 632 between 500 and 2 000 $, 506 above 250 000 $, 5 above 1 M$ (max 26.5 M$ — data error). `price_label` empty for 6 739. Mileage ≤ 10 km: 1 588 (new/demo or placeholder); > 500 000 km: 48. Year < 1990: 131; year = 2027: 784 (new-model-year stock). Hedonic-eligible core (auto, canonical, 2005 ≤ year ≤ 2026, 1 000 ≤ km ≤ 400 000, 2 000 ≤ price ≤ 250 000, make & model present): **242 508 of 259 133** canonical auto listings.6162## 5. Source-level quality (decisive for the dynamic analyses)6364Measured from `sync_log` and `vehicles`; "reactivation share" = (sum of `removed` events − inactive uids) / removed events, i.e. the share of exit events that were later reversed (flicker).6566| Source (type) | Listings | Mean found / cycle | Exits with duration < 1 d | Reactivation share | Verdict |67|---|---|---|---|---|---|68| otogo (portal, full inventory, VIN ≈ 82 %, exact GPS, 538 dealers) | 79 045 | 24 719 | 30 % | 0.44 | **Keep for levels and dynamics with flicker-robust exit rule**; uid stable per dealer listing (only 1.7 % of VINs have > 1 otogo uid, mostly genuine dealer-to-dealer transfers) |69| autousagee (AMVOQ portal, full inventory, 391 dealers) | 28 858 | 11 973 | 5 % | 0.04 | Keep |70| direct dealer websites (136 sources, 50 223 listings, 17 801 active) | 50 223 | — | 4.8 % | mostly ≤ 0.1 | **Core dynamic sample** (exceptions below) |71| hgregoire, automobileendirect, megacentre, clubautozone (banners) | 11 038 | — | low | 0.10–0.21 | Keep |72| autotrader (portal, **sliding window capped at 2 000 of > 4 000**) | 65 526 | 1 853 | 11 % (mean duration 2.2 d) | 0.12 | **Exclude from dynamics** (sampled, no VIN); eligible for cross-sectional hedonics only with a flag |73| cargurus (portal, **capped at 500**) | 37 501 | 507 | 78 % | 0.17 | **Exclude from dynamics**; cross-section only |74| kijiji (private sellers, no VIN 79 %, trim missing 55 %) | 11 874 | 3 041 | 15 % | 0.04 | Separate "private-seller" segment; excluded from dealer analyses |75| leprixdugros (banner) | 6 124 | 1 019 | 11 % | **0.94** | Connector flicker: exclude from exit/markdown hazards |76| albioccasion (rate-limited 429) | 2 057 | 853 | — | 0.52 | Exclude from dynamics |77| baiecomeaugm, septilesgm, stjeromeautodepot, excelmoto (404 / connector failures 214–271 cycles) | < 500 each | — | — | 0.85 / 0.39 / — | Exclude |78| classeauto:-98 | 1 uid | — | — | — | Identity collision (36 194 price rows, 48 distinct prices): exclude uid |7980Other anomalies: 3 451 uids show A→B→A price oscillation (e.g. `otogo:1694844` alternating 37 840 / 40 794 $ twice a day for weeks — two feed variants of the same listing); 11 479 of 121 239 price changes occur < 24 h after the previous one. A "sustained price path" rule is therefore required before any markdown analysis (see `research/analysis_plan.md`).8182Among non-portal sources, price changes are **100 532 cuts vs 11 447 rises** (mean cut 3.4 %, mean rise 15.0 % — rises are dominated by placeholder/oscillation artefacts).8384## 6. Geographic and dealer coverage8586Active canonical listings by administrative region (2026-11-01): Montérégie 8 744, Capitale-Nationale 5 442, Laurentides 4 999, Montréal 4 511, Chaudière-Appalaches 3 605, Laval 3 036, Lanaudière 2 965, Mauricie 2 060, Estrie 1 965, Centre-du-Québec 1 652, Bas-Saint-Laurent 1 504, Outaouais 1 342, Abitibi-Témiscamingue 1 265, Saguenay–Lac-Saint-Jean 1 027, Côte-Nord 799, Gaspésie–Îles-de-la-Madeleine 291; missing region 4 754 (to be recovered from lat/lng). 138 geocoded direct dealers; otogo adds 538 dealer names with exact GPS; 16 308 direct-dealer VINs are also observed on otogo (cross-source consistency checks for exits).8788Representativeness: the direct-dealer registry over-weights Capitale-Nationale, Bas-Saint-Laurent, Chaudière-Appalaches and Côte-Nord relative to population (registry built by the operator, not sampled). External benchmarks: see `reports/external_benchmarks_inventory.md`.8990## 7. Feasibility matrix (H1–H6)9192| Hypothesis | Feasible? | Sample | Limits |93|---|---|---|---|94| H1 nonlinear depreciation (hedonic asking prices) | **Yes** | 242 k canonical listings; first-observed price per listing (or listing-month panel) | Asking prices, not transactions; composition; dealer effects collinear with region for single-site dealers |95| H2 markdown hazard | **Yes** | Dynamic sample (direct dealers + otogo + autousagee + banners), listing-day risk set, flicker-robust price paths | Left-censoring of the day-1 stock (46 k); 81-day window → right-censoring heavy for long spells |96| H3 competitor response | **Association only** | Local competitor sets (same make/model/year ± 1, radius 25/50 km) from GPS | No exogenous variation; reflection problem; common shocks → report as conditional association with event-study diagnostics |97| H4 regional segmentation | **Yes (cross-section + within-spec dispersion)** | Hedonic residuals by region with model-trim-year cohorts | Dealer FE absorb region for single-location dealers → use dealer-group/chain FE variants |98| H5 listing exit & relative price | **Yes, exit ≠ sale** | Same as H2; exit = final absence ≥ 7 d | No transaction data; validation limited to cross-source consistency (direct site vs otogo) and relisting detection |99| H6 AMLI | **Construction + internal validation only** | Daily/weekly market-level panel, 81 days | **No out-of-sample forecasting test of external economic variables is possible** with ≤ 3 monthly points; stated as a documented limitation |100101## 8. Recommended extraction method (adopted)1021031. Immutable raw snapshot: `sqlite3 .backup` on M4M64b → drop `users` → `VACUUM` → SHA-256 → zstd → scp → verify (done 2026-11-01; `data/raw/`, read-only, **never committed**).1042. `src/ucml/ingest`: read-only DuckDB/Polars extraction to Parquet in `data/interim/` (vehicles, price_log, sync_log, dealers), with a manifest (row counts, min/max timestamps, SHA-256 of the source).1053. All downstream transformations versioned in `src/ucml/*` with tests; exclusion log in `data/processed/exclusions.csv`.106107## 9. Data governance108109- **Public vs restricted fields.** Make/model/trim/year/price/mileage/attributes/region/city/dealer name are public asking-price information published by dealers. VIN, stock number, listing URL, images, free-text descriptions and exact coordinates are treated as *restricted*: kept only in `data/raw` and `data/interim` (not committed, not released), used solely for linkage (VIN de-duplication, relisting detection, dealer geography). Released/processed tables carry anonymised dealer IDs (`d####`) and listing IDs (`l#######`), region/city and 1 km-rounded coordinates.110- **Personal information.** The `users` table was dropped before the data left the production node. Kijiji private-seller listings may contain phone numbers in free text: descriptions are never exported from `data/interim`; the private-seller segment is analysed only through structured fields.111- **Retention.** Raw snapshot retained for the life of the paper on the author's encrypted laptop and the production node; processed Parquet retained with the repository; nothing is pushed to any third-party service.112- **Attribution.** Data source cited as "Auto-Ka (www.auto-ka.com), operator's database snapshot of 2026-11-01"; dealer sites are the ultimate sources (listed in `data/sources.json`, mirrored in `data/processed/sources_registry.csv`).113- **Permitted use.** Owner-authorised academic research use by the platform operator; no redistribution of listing-level raw data.114- **Access control.** Snapshot mode 0444, directory excluded by `.gitignore`.115
Files · main
Menu

Theme