feat(had): cluster-robust event-study inference + clustered sup-t band#612
Conversation
|
Overall Assessment Executive Summary
Methodology
Code Quality
Performance
Maintainability
Tech Debt
Security
Documentation/Tests
|
773e1fe to
f94625b
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings found. Executive Summary
Methodology
Code Quality No findings. Performance No findings. The clustered branch draws multiplier blocks and stores only Maintainability
Tech Debt No findings. The former event-study Security No findings. Documentation/Tests No blocking findings. The previous registry drift is cleaned up, and the added tests cover the previously missing weighted continuous and unweighted mass-point clustered event-study paths. Review note: I did not run the test suite locally because the environment failed on missing |
f94625b to
1ec33ff
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
Methodology
Code Quality No findings. Performance No findings. The clustered branch aggregates IFs to cluster level and stores bootstrap perturbations as Maintainability
Tech Debt No findings. The prior TODO deferral for HAD event-study Security No findings. Documentation/Tests
Local verification: attempted targeted |
1ec33ff to
f725991
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
Methodology
Code Quality No findings. Performance No findings. The clustered bootstrap aggregates IFs to cluster level and stores only Maintainability No findings. Tech Debt No findings. The old HAD event-study Security No findings. Documentation/Tests
|
HeterogeneousAdoptionDiD.fit(aggregate="event_study") now honors cluster= end-to-end on both designs: cluster-robust per-horizon pointwise CIs (continuous CCT + mass-point 2SLS) AND a cluster-robust simultaneous sup-t confidence band. Previously cluster= was ignored on the nonparametric event-study path (with a UserWarning) and the weighted mass-point cband=True case raised NotImplementedError. The clustered sup-t band adds a dedicated branch to _sup_t_multiplier_bootstrap: it aggregates the per-unit influence function to cluster level and draws cluster-level Rademacher multipliers, so the perturbation variance is the raw cluster sandwich sum_c s_c^2. This reconciles to each path's analytical cluster-robust SE via a path scalar: 1.0 for continuous (the lprobust cluster meat carries no g/(g-1) correction) and sqrt(G/(G-1)) for mass-point (restoring the CR1 finite-sample factor the returned IF omits). Validated bootstrap-free: sqrt(sum_c (scale*s_c)^2) == se to atol=1e-10 on the real IF for both paths, plus the H=1 -> 1.96 reduction on the clustered branch. cluster= + survey= is rejected (both designs) - route clustering through survey_design=SurveyDesign(psu=<col>). Single cluster -> NaN band + RuntimeWarning. Unclustered fits are byte-unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LHDijzf8zHXk5T8ahS2mKi
f725991 to
c436dc2
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment ✅ Looks good. No unmitigated P0/P1 findings. Executive Summary
Methodology
Code Quality No findings. Performance No findings. The clustered bootstrap aggregates IFs to cluster level and generates Maintainability No findings. Tech Debt No findings. The old HAD event-study Security No findings. Documentation/Tests
|
Summary
HeterogeneousAdoptionDiD.fit(aggregate="event_study")now honorscluster=end-to-end on both designs (continuous CCT local-linear + mass-point 2SLS): cluster-robust per-horizon pointwise CIs and a cluster-robust simultaneous sup-t confidence band. Previouslycluster=was silently ignored on the nonparametric event-study path (with aUserWarning), and the weighted mass-pointcband=Truecase raisedNotImplementedError._sup_t_multiplier_bootstrap: aggregates the per-unit influence function to cluster level and draws cluster-level Rademacher multipliers, so the perturbation variance is the raw cluster sandwichΣ_c s_c². This reconciles to each path's analytical cluster-robust SE via a path scalar — 1.0 for continuous (thelprobustcluster meat carries nog/(g-1)correction) and√(G/(G-1))for mass-point (restoring the CR1 finite-sample factor the returned IF omits).cluster=+survey=is rejected on both designs (route clustering throughsurvey_design=SurveyDesign(psu=<col>)). Single cluster → NaN band +RuntimeWarning. Unclustered fits are byte-unchanged.Methodology references (required if estimator / math changes)
HeterogeneousAdoptionDiDevent-study inference (cluster-robust CCT / 2SLS SEs + clustered sup-t simultaneous band)docs/methodology/REGISTRY.md("Note (HAD clustered event-study sup-t band)") with the variance-family reconciliation. The reconciliation identity is the validation:sqrt(Σ_c (scale·s_c)²) == setoatol=1e-10on the real influence function for both paths, plus theH=1 → 1.96sup-t reduction.cluster=+survey=rejected (Binder-TSL would override the cluster-robust SE).Validation
tests/test_had.py— newTestEventStudyClusterBand(deterministic IF/SE reconciliation for both paths, end-to-end continuous + weighted mass-point clustered bands,cluster=+survey=rejection, single-cluster NaN, determinism); clustered variant + single-cluster case added toTestSupTReducesToNormalAtH1; two former mass-point rejection tests converted to assert the now-supported behavior; the stale "cluster ignored" test flipped to assert cluster-robust threading. Fulltest_had.pysuite: 393 passed / 2 skipped.Security / privacy
🤖 Generated with Claude Code