feat(continuous-did): covariate support (reg + dr) under conditional parallel trends#616
Conversation
…parallel trends
Add `covariates=` and `estimation_method in {"reg","dr"}` to ContinuousDiD for
dose-response estimation under conditional parallel trends
(E[dY(0)|D=d,X] = E[dY(0)|D=0,X]). Each (g,t) cell's control counterfactual
becomes a covariate-adjusted prediction:
- reg: outcome regression on controls (dY_i - X_i'gamma_hat)
- dr (default): doubly-robust (DRDID drdid_panel), plus a scalar augmentation
Scalar overall_att + SE match DRDID reg_did_panel / drdid_panel to ~1e-8;
analytical, multiplier-bootstrap, and event-study inference all compose with
covariates. reg and dr share the ATT(d) shape and ACRT(d), differing only in
the overall_att/ATT(d) level and the doubly-robust SE.
estimation_method="ipw" with covariates raises NotImplementedError (pure IPW's
covariate adjustment is a scalar level shift and cannot adjust the curve shape);
covariates + survey_design deferred. The no-covariate path is unchanged.
Validated: DRDID parity (reg/dr, skip-guarded), R-free NumPy influence-function
cross-check at p>=2 (in CI), MC coverage (reg 96%, dr 95%), DGP recovery, and
reg-vs-dr ACRT identity.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LHDijzf8zHXk5T8ahS2mKi
Overall Assessment: ✅ Looks goodExecutive Summary
MethodologyFinding: P3 informational — documented ContinuousDiD covariate-extension deviations Finding: P3 informational — methodology propagation appears consistent Code QualityFinding: P2 — PerformanceFinding: None MaintainabilityFinding: P3 — optional fallback path would benefit from a direct regression test Tech DebtFinding: P3 informational — deferred combinations are properly tracked SecurityFinding: None Documentation/TestsFinding: P3 — time-varying covariate/base-period behavior is documented but not directly tested |
Summary
covariates=+estimation_method ∈ {"reg","dr"}toContinuousDiDfor dose-response estimation under conditional parallel trends (E[ΔY(0)|D=d,X] = E[ΔY(0)|D=0,X]). Closes TODO item (a) of the CGBS-2024 extensions row.(g,t)cell's control counterfactual becomes covariate-adjusted:reg= outcome regression on controls (ΔY_i − X_i'γ̂);dr(default) = doubly-robust (DRDIDdrdid_panel), adding a propensity model + scalar augmentationη̄_cont.reganddrshare the ATT(d) shape and ACRT(d) (point + SE), differing only in theoverall_att/ATT(d) level and the doubly-robust SE.drpropensity-estimation failure raises by default (pscore_fallback="error").estimation_method="ipw"+ covariates andcovariates=+survey_design=raiseNotImplementedError(documented deferrals — IPW's covariate adjustment is a scalar level shift that can't move the curve shape). The no-covariate path is numerically unchanged.Methodology references (required if estimator / math changes)
ContinuousDiDcovariate adjustment (Callaway, Goodman-Bacon & Sant'Anna 2024). Per-cell OR/DR follows Sant'Anna & Zhao (2020) / theDRDIDpackage.DRDID::reg_did_panel/drdid_panel. Seedocs/methodology/REGISTRY.md§ ContinuousDiD Note Add comprehensive code review for diff-diff library #5 and Key Equations.contdidv0.1.0, which hard-stops on covariates — so there is no external R anchor for the covariate-adjusted dose curve; the scalaroverall_att+ SE are instead anchored exactly to DRDID, and the curve is validated by reduction + DGP recovery + MC coverage. Propensity trimming uses clip semantics (pscore_trim) vs DRDID's drop-trimming (identical on moderate-overlap data). All documented in REGISTRY Note Add comprehensive code review for diff-diff library #5.Validation
tests/test_continuous_did.py(API, params validation, fail-closed guards, results metadata, event-study + bootstrap composition),tests/test_methodology_continuous_did.py(DRDID reg/dratt+SE parity [skip-guarded when R/DRDID absent], R-free NumPy influence-function cross-check at p≥2 [runs in CI], reg-vs-dr ACRT identity, DGP recovery, MC coverage [slow]).overall_att+ SE matchDRDID::reg_did_panel/drdid_panelto ~1e-8 (incl. the doubly-robust SE); MC coverage reg 96% / dr 95% under conditional PT; DGP recovery (covariate-adjusted recovers the truth, unconditional is biased). Full ContinuousDiD suite 117 pass; mypy 0-new vs main.Security / privacy
🤖 Generated with Claude Code