WP37 — Preregistration of hypotheses, samples, estimands and analysis plan
Status: FROZEN on 2026-11-01 before any hypothesis-relevant estimation (hash recorded in research/decisions.md). Amendments after this date are logged in research/decisions.md with a reason; the paper reports both the preregistered and any amended analysis.
0. What was examined before freezing (disclosure)
Phase 0–1 work looked at: table counts, per-feed coverage, the event-log data-generating process, intra-day price oscillation diagnostics (share of A→B→A reversions, number of distinct price values, weekly Jaccard of value sets), unit-price coverage, the distribution of current discount depth (1 − price/regular_price, median 0.17), UPC validity, matching precision/recall and the validation sample. No cross-banner price gap, promotion duration, index, response model or forecast has been computed. The store-mixture finding (Phase 0 report §3.3) motivated the weekly modal-price definition below; this is a data-quality decision, not a result-driven one.
1. Universe, period and units
- Snapshot
foodka-snapshot-20261101(sha2563cd7684d…), event log 2026-08-12 → 2026-11-01, 12 complete circular weeks (Thu 2026-08-13 → Wed 2026-11-04 truncated at 2026-11-01; the first partial week 2026-08-06 and the last partial week 2026-10-29 are dropped from weekly analyses unless stated). - Grocery universe = listings from feeds whose
store_formatis not pharmacy or alcohol monopoly, in categories other than {Santé et beauté, Maison et entretien, Animaux, Bébé, Alcool}, with ≥ 1 observed price and no unrealistic-price flag. - Posted price of listing i in week w = duration-weighted modal price
p_modeover the week (primary);p_min,p_max,p_twmeanas sensitivity. Unit price = posted price / parsed package quantity (per 100 g, 100 ml or unit). - Matched product = cross-banner match group built from tiers A + B (primary); A+B+C and A+B+C+D in sensitivity; groups with > 1 simultaneously active listing from the same banner-channel are flagged
ambiguousand excluded from the primary sample. - Channel: storefront vs circular. Same-banner channel links are not cross-banner comparisons.
- Clustering default: two-way by match group and by banner (banner clusters are few — 17 banners with storefront feeds — so wild-cluster bootstrap p-values are reported alongside).
2. Hypotheses
H1 — Matched-item cross-banner dispersion is economically meaningful and persistent
- Sample: product-weeks of matched groups (A+B) with ≥ 2 banners posting a price in the same week; storefront channel only (primary), circulars added in sensitivity.
- Outcome:
log p_{irw}; dispersion statistics per group-week: coefficient of variation, max–min log gap, interquartile log range. - Estimand (Model A):
log p_irw = α_iw + γ_r + ε_irw(product-week FE, banner FE). Banner effects γ_r are relative posted price levels; dispersion = sd of residual + sd of γ. Persistence: autocorrelation of the banner-pair log gapg_{i,rs,w}across weeks (AR(1) coefficient), share of pairs whose ranking never flips. - Null: median within-group max–min log gap = 0 (trivially rejected); the economic threshold we preregister is a median gap ≥ 0.05 (5 %) and AR(1) ≥ 0.5 for "meaningful and persistent".
- Controls: none beyond FE in the primary spec; sensitivity adds category × week FE.
- Missingness: a banner-week without a posted price is missing, not zero; groups with intermittent coverage are kept (unbalanced) and a balanced common-product panel is reported as robustness.
- Falsification: Metro vs Super C exact-UPC pairs (same company, two formats) should show smaller dispersion than cross-company pairs if company-level pricing coordination exists; placebo: random re-assignment of banners within group-week should yield AR(1) ≈ 0.
- Minimum duration: 8 weeks for AR(1); available.
H2 — Promotion-adjusted price volatility differs from non-promotion volatility
- Sample: listing-weeks of storefront feeds (grocery universe) with ≥ 8 observed weeks.
- Promotion state inferred (storefront): a week is "promoted" if
p_mode_w ≤ 0.90 × reference_w, where reference_w is the modal price over the trailing 8 weeks (including w) — the Nakamura–Steinsson/Kehoe–Midrigan reference filter; validated against the currenton_saleflag in the snapshot week (report agreement) and against circular items of the same banner-week when matched. - Outcome: sd of weekly log price changes (i) raw, (ii) excluding promotion weeks (reference-price series).
- Estimand: ratio of raw to reference-price volatility by banner and category; share of all weekly log changes attributable to promotion entry/exit.
- Null: ratio = 1. Clustering: by banner × category (bootstrap over listings).
- Falsification: single-store online shops (Shopify/WooCommerce feeds) must not display the 3–5-level oscillation; if they do, the store-mixture interpretation fails and H2 is re-examined at the daily frequency.
- Missingness: weeks with no observed price are dropped from the change series (no interpolation).
H3 — Promotions are associated with subsequent reference-price adjustments
- Sample: promotion episodes (≥ 1 promoted week followed by return to a non-promoted week) in storefront feeds; circular items matched to a storefront listing of the same banner (tier channel link) provide the second sample with observed
original_price. - Outcome: change in the reference price after the episode vs before:
Δ log ref = log ref_{post} − log ref_{pre}. - Estimand (Model B): transition matrix regular↔promoted; episode duration, recurrence interval, depth; event-study of log price from −4 to +4 weeks around episode end with listing FE and week FE; test of pretrends (weeks −4…−2 coefficients jointly = 0).
- Null: E[Δ log ref] = 0 (promotions neither precede nor follow reference increases). Direction is left to the data.
- Falsification/censoring: episodes censored at panel edges are excluded; overlapping episodes within the same listing are merged; placebo events at random weeks must give Δ ≈ 0.
- Minimum duration: 26 weeks for a well-powered test; with 12 weeks the test is exploratory and labelled so.
H4 — Competitor responses are strongest for close substitutes and nearby stores
- Store geography is unavailable → the "nearby stores" part is not testable and is stated as such. The testable part: banner-level weekly response of
Δ log p_{irw}to lagged rival changesΔ log p_{isw−k}(k = 0…3) within matched group, with product-week and banner FE (Model C), separately for same-company rivals (Metro/Super C; Maxi/Provigo/Club Entrepôt) vs cross-company rivals. - Estimand: distributed-lag coefficients; contemporaneous (k = 0) coefficients are not causal (common shocks, simultaneity); k ≥ 1 coefficients are descriptive lead–lag associations. No IV/quasi-experiment is preregistered because no exogenous shifter is available.
- Null: all lagged coefficients = 0.
- Clustering: two-way group × week. Falsification: placebo with rival changes shifted forward (leads) must be ≈ 0.
H5 — Package-size and assortment changes create gaps between naive and quality-consistent indices
- Sample: grocery universe, weekly, storefront + circular.
- Indices (Model D): (a) naive average posted price by category; (b) Jevons matched-model index (geometric mean of weekly log changes over listings present in both weeks); (c) fixed-basket Laspeyres with equal item weights (no expenditure weights exist — explicitly not a CPI); (d) chained version; (e) unit-price versions of (b)–(d) that re-match listings whose size label changed.
- Estimand: cumulative difference between (a) and (b) over 12 weeks; count and unit-price effect of within-listing size changes.
- Null: gap = 0. Uncertainty by listing-level bootstrap (B = 999, seed 20261101).
- Benchmark: StatCan CPI "Food purchased from stores", Quebec, Aug→Sep 2026 (2 months) — comparison only, no superiority claim.
H6 — Unconstrained minimum-price basket savings exceed savings feasible under constraints
- Basket: 30 generic items specified by category and quantity (preregistered in
config/basket.yamlbefore estimation), mapped to matched groups (A+B) and, where no matched group exists, to the cheapest listing per banner within a tight name rule (documented). - Model E: integer program minimising basket cost subject to at most K banners (K = 1…5), each item bought at one banner, availability = posted price exists that week. Travel costs are not observable; a sensitivity grid of fixed per-store costs (0, 5, 10, 20 CAD) is reported as illustrative, labelled as assumption-based.
- Estimand: savings frontier S(K) = cost(K=1 best single banner) − cost(K); share of unconstrained savings attained at K = 2.
- Null: S(∞) − S(2) = 0 (two banners capture everything).
Forecasting (Model F) — preregistered evaluation
- Target: next-week posted unit price (log) and next-week promotion indicator per listing (storefront).
- Rolling origin: train weeks 1…t, test week t+1, t = 6…11; models: seasonal naive (last week), banner-category mean reversion, ridge, LightGBM; metrics: MAE / RMSE on log price, Brier / AUC on promotion. No future information in features (strict lags only).
3. QGPAI components (Phase 5) — fixed before computation
- Comparable Price Index: Jevons matched-model index over matched groups (A+B), weekly, base = week of 2026-08-13 = 100.
- Promotion Intensity: share of listing-weeks promoted; mean depth; sd of depth — storefront (inferred) and circular (observed) reported separately.
- Retail Price Dispersion: median within-group max–min log gap (H1 statistic).
- Feasible Basket Cost: Model E cost at K = 1 and K = 2.
- Access & Affordability: not computed (no geography/income data joined); placeholder documented. Aggregation: components are published separately; an equal-weight z-score composite is shown only as an illustration with alternative weights (0.5/0.5 on components 1 and 4) — not an empirical estimate.
4. Multiple testing
Six preregistered families (H1–H6); within each, Holm correction over the primary tests. Exploratory analyses are labelled.