From 6c4ab949cd79f55de7cb8a96813c2fdcdb38a087 Mon Sep 17 00:00:00 2001 From: igerber Date: Tue, 26 May 2026 13:39:21 -0400 Subject: [PATCH] ConleySpatialHAC methodology-review-tracker promotion + Bertanha-Imbens 2014 citation correction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three bundled changes: 1. ConleySpatialHAC methodology-review-tracker promotion (In Progress → Complete). - METHODOLOGY_REVIEW.md L91 + L1262-1290 flipped Complete with full Verified Components / Test Coverage / R Comparison Results inline table / Corrections Made / Deviations / Outstanding Concerns structure, with Last Review = 2026-05-26. - New tests/test_methodology_conley.py (~1600 LoC; 10 classes; 60 tests, 5 of them @pytest.mark.slow). Paper-equation-numbered Verified Components walk-through covering: * Eq. 4.2 cross-sectional sandwich (pairwise-distance specialization; Eq. 3.13 is the lattice-indexed form reserved for grid coordinates) * Eq. 4.2 HC0 + rank-1 limits + K(0) = 1 diagonal contribution * Andrews (1991) HAC lag truncation matching conleyreg::time_dist.cpp * Haversine convention with Earth radius 6371.01 km (matches conleyreg::haversine_dist) * Phase 2 panel block-decomposed sandwich at atol=1e-12 (internal cross-check vs hand-coded reference + cluster time-invariance contract) * Wave A #120 sparse k-d-tree numerical correctness (sparse-vs- dense bit-identity at atol=1e-10 on cross-sectional, panel, and sparse-with-cluster paths) * R conleyreg v0.1.9 parity at atol=1e-6 on 6 fixtures (3 cross-sectional + 3 panel) + sparse-forced cross-sectional + sparse-forced panel + time-asymmetric kernel literal-matching Three dedicated deviations-area classes: * TestConleyLibraryExtensions (6 tests, no R correspondence): combined spatial+cluster product kernel Wave A #119 (two limit-fixture anchors), callable conley_metric validation Wave A #123, sparse k-d-tree activation Wave A #120, indefiniteness guard on Bartlett + uniform kernels. * TestConleyDeviationsFromR (3 tests): 1-D radial Bartlett vs paper's 2-D separable Eq. 3.14, time-label normalization, independent temporal kernel deferred. * TestConleyDeferrals (5 tests): fail-closed NotImplementedError / TypeError contracts for LinearRegression + survey_design, DiD/MPD/TWFE + survey_design (estimator-level via conley.py::_validate_conley_estimator_inputs), Conley + weights (rejected for any weight_type — pweight, aweight, fweight), SyntheticDiD + Conley (TypeError), wild_bootstrap + Conley. - tests/test_conley_vcov.py extracted 1135+ LoC out (4248 → 3113); defensive surface preserved (input validation, NaN/inf guards, dispatch-level validity, estimator-level integration smoke tests, set_params atomicity, sparse-path activation thresholds + density- gate fallback). Module docstring refreshed to describe its current defensive-regression role. 2. Stale priority-queue cleanup at METHODOLOGY_REVIEW.md L1386: - PreTrendsPower removed (already Complete since 2026-05-19). - ConleySpatialHAC removed (this PR). - Substantive-review-blocked renumbered #2-#5 → #1-#4. - Consolidation-pass-blocked renumbered #6-#8 → #5-#6. 3. Bertanha-Imbens 2014 citation correction across 16 sites: - linalg.py × 8, conley.py × 1, llms-full.txt × 2, REGISTRY.md × 4, spillover.rst × 1. - NBER w20773 is on FRD external validity, NOT weighted spatial-HAC. - The boundary is now framed as a tri-part contract: * Shipped — SpilloverDiD + Conley + survey via Wave E.1/E.2/E.3 (PR #468/#474/#482, stratified-Conley sandwich on PSU totals with within-PSU serial Bartlett HAC for lag_cutoff > 0); TwoStageDiD + Conley + survey via Wave E.3 parity (PR #485). * Deferred (generic linalg surface, any weight_type) — DiD/MPD/ TWFE/LinearRegression generic path + Conley + survey_design; LinearRegression / compute_robust_vcov Conley + weights rejected for pweight, aweight, AND fweight (weighted Conley is not implemented on the generic linalg surface). * Open methodological question (subset) — the pweight / survey_design portion of the deferral additionally lacks a canonical methodological extension of Conley (1999) for weighted spatial-HAC under probability sampling. - REGISTRY sites use canonical `**Note (open methodological question):**` label wrapper per CLAUDE.md "Documenting Deviations". - Historical CHANGELOG entries (pre-[Unreleased]) intentionally retain Bertanha-Imbens 2014 attribution as accurate records of past release claims. Verification: - pytest tests/test_methodology_conley.py: 60 tests (55 unit + 5 slow) pass. - pytest tests/test_methodology_conley.py + tests/test_conley_vcov.py: 176 pass + 5 slow deselected (preserves pre-edit baseline coverage 176 vs original 175 + 1 new uniform-kernel indefiniteness guard). - grep -rn "Bertanha" diff_diff/ docs/ benchmarks/: 0 hits. - black + ruff clean. Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 6 + METHODOLOGY_REVIEW.md | 83 +- diff_diff/conley.py | 12 +- diff_diff/guides/llms-full.txt | 4 +- diff_diff/linalg.py | 87 +- docs/api/spillover.rst | 6 +- docs/methodology/REGISTRY.md | 13 +- tests/test_conley_vcov.py | 1331 ++--------------------- tests/test_methodology_conley.py | 1709 ++++++++++++++++++++++++++++++ 9 files changed, 1962 insertions(+), 1289 deletions(-) create mode 100644 tests/test_methodology_conley.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c34e2d8..a4f5a2b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added +- **ConleySpatialHAC methodology-review-tracker promotion: In Progress → Complete.** Closes the Conley (1999) *Journal of Econometrics* 92(1) primary-source review on the methodology-review tracker. The paper review on file at `docs/methodology/papers/conley-1999-review.md` was previously merged (2026-05-09); this PR is the F.L.I.P. consolidation — new `tests/test_methodology_conley.py` with paper-equation-numbered Verified Components walk-through (~1600 LoC; 10 classes; 60 tests, 5 of them `@pytest.mark.slow`). Coverage: Eq. 4.2 cross-sectional sandwich (pairwise-distance specialization; the project's paper review identifies Eq. 4.2 page 18 as the real-valued/pairwise form, with Eq. 3.13 reserved for the lattice-indexed form), Eq. 4.2 HC0 + rank-1 limits, Andrews (1991) HAC lag truncation matching `conleyreg::time_dist.cpp`, haversine convention with Earth radius 6371.01 km, Phase 2 panel block-decomposed sandwich at `atol=1e-12`, sparse k-d-tree dense-vs-sparse bit-identity (Wave A #120 numerical correctness), and R `conleyreg` v0.1.9 parity at `atol=1e-6` on 6 fixtures (3 cross-sectional + 3 panel) plus the sparse-forced and time-asymmetric kernel parity contracts. Three dedicated deviations-area classes: `TestConleyLibraryExtensions` (Wave A library extensions — combined spatial+cluster product kernel #119, callable conley_metric validation #123, sparse k-d-tree activation #120, indefiniteness guard), `TestConleyDeviationsFromR` (1-D radial Bartlett vs paper's 2-D separable Eq. 3.14, time-label normalization via `np.unique`, independent temporal kernel deferred), and `TestConleyDeferrals` (5 fail-closed `NotImplementedError`/`TypeError` contracts: LinearRegression + survey_design, DiD/MPD/TWFE + survey_design, Conley + weights, SyntheticDiD + Conley, wild_bootstrap + Conley). Methodology-anchored tests extracted from `tests/test_conley_vcov.py`: full classes `TestConleyDirectHelper`, `TestConleyReductions`, `TestConleyReductionsAddendum`, `TestConleyParityR`, `TestConleyParitySpacetime`, `TestConleyPanelHelper`, `TestConleySparseRParityForced`; plus methodology-anchored tests from `TestConleyKernels`, `TestConleyDistanceMetrics`, `TestConleySparse`. File drops 4248 → 3113 lines after extraction. Defensive surface preserved: input validation, NaN/inf guards, dispatch-level validity, estimator-level integration smoke tests, set_params atomicity, sparse-path activation thresholds + density-gate fallback. `METHODOLOGY_REVIEW.md` row L91 promoted to **Complete** with `Last Review = 2026-05-26`; detail block rewritten with Verified Components / Test Coverage / R Comparison Results inline table / Corrections Made / Deviations / Outstanding Concerns. Priority queue at L1386 pruned: PreTrendsPower removed (already Complete since 2026-05-19) and ConleySpatialHAC removed (this PR); substantive-review-blocked renumbered #2-#5 → #1-#4 and consolidation-pass-blocked renumbered #6-#8 → #5-#6. + ### Added / Changed - **EfficientDiD `vcov_type` threading + Results metadata harmonization (Phase 1b interstitial #4, permanently narrow).** `EfficientDiD(vcov_type=...)` now accepts `{"hc1"}` only (default). Analytical-sandwich families `{classical, hc2, hc2_bm}` and `conley` are REJECTED at `__init__` / `set_params` with methodology-rooted messages — EfficientDiD uses influence-function-based variance per Chen-Sant'Anna-Xie (2025) achieving the semiparametric efficiency bound; the per-unit EIF aggregation has no single design matrix on which hat-matrix leverage or Bell-McCaffrey Satterthwaite DOF can be defined. `cluster=` (Liang-Zeger CR1 on cluster-aggregated EIF) and `survey_design=` (TSL on combined IF) paths are unchanged. **BC break on `EfficientDiDResults`:** the `cluster` field renamed to `cluster_name`; new `n_clusters` + `vcov_type` fields added; `to_dict()` method added (mirrors TripleDifferenceResults). `DiagnosticReport._pt_hausman` updated to read the renamed `cluster_name` field for the Hausman pretest replay (`diff_diff/diagnostic_report.py:2444`). `EfficientDiD.set_params(vcov_type=bad)` raises immediately rather than deferring to `fit()` — intentional eager-validation pattern matching EfficientDiD's existing handling of `pt_assumption`/`control_group` etc, diverging from `ImputationDiD`/`TripleDifference`/`CallawaySantAnna` (which use sklearn mutate-then-validate-at-use). Survey-PSU bootstrap path returns NaN SE when fewer than 2 independent PSUs are available (was ≈0 SE from BLAS roundoff). New summary block: `Variance estimator: