From fad11feac8f78e4f62cb5cce748c9b4b585f566d Mon Sep 17 00:00:00 2001 From: igerber Date: Mon, 1 Jun 2026 06:23:34 -0400 Subject: [PATCH] Bump version to 3.5.0 Promote the [Unreleased] CHANGELOG block to [3.5.0] (2026-06-01) and sync the version string across pyproject.toml, rust/Cargo.toml, diff_diff/__init__.py, diff_diff/guides/llms-full.txt, and CITATION.cff (date-released 2026-06-01). Release highlights since v3.4.2: new SyntheticControl estimator (ADH 2010) with in-space placebo inference; PowerAnalysis, StaggeredTripleDifference, and ConleySpatialHAC methodology-tracker completions (PowerAnalysis includes a panel variance behavior change); completion of the vcov_type Phase 1b initiative (EfficientDiD + TwoStageDiD) plus SunAbraham/WooldridgeDiD conley threading; scale-invariant rank detection and rank-guarded DR/OR influence-function SEs. Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 3 +++ CITATION.cff | 4 ++-- diff_diff/__init__.py | 2 +- diff_diff/guides/llms-full.txt | 2 +- pyproject.toml | 2 +- rust/Cargo.toml | 2 +- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bd213d8..8613b2ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [3.5.0] - 2026-06-01 + ### Added - **PowerAnalysis methodology-review-tracker promotion: In Progress → Complete, with a panel-variance correction (behavior change).** Closes the Bloom (1995) + Burlig, Preonas & Woerman (2020) source audits on the tracker (PR-A #506 added both paper reviews + under-review Notes; this PR validates the source against the code and reconciles the discrepancies). **Behavior change:** the analytical *panel* DiD variance was the Moulton design-effect factor `(1+(T−1)·rho)/T`, wrong two ways versus the source — wrong period-scaling (~4× too small at `rho=0`, `m=r=5` versus the iid DiD benchmark) and the **opposite `rho`-sign** (it *raised* the MDE as within-unit correlation grew). It is replaced by the within-unit equicorrelated special case of Burlig et al. Eq. 2, `Var(ATT) = sigma² · (1/n_T + 1/n_C) · (1/n_pre + 1/n_post) · (1 − rho)`, in which within-unit (serial) correlation *lowers* the MDE because the difference-in-differences cancels the shared within-unit component. So `PowerAnalysis.mde` / `power` / `sample_size` (and the `compute_*` wrappers) now return a **smaller** MDE / required N as `rho` rises for **all** designs; the 2×2 path matches Bloom's `2σ²` at the default `rho = 0` and is continuous with the panel form at `n_pre = n_post = 1`. New input validation, enforced for **all** designs *before* the 2×2-vs-panel router: `n_pre >= 1`, `n_post >= 1`, `rho ∈ [−1/(T−1), 1)` (`T = n_pre + n_post`), finite `sigma >= 0`, positive group counts, and `treat_frac ∈ (0, 1)` now raise `ValueError` (previously invalid two-period shapes and out-of-range `rho` fell through to `basic_did` silently). The `(1 − rho)` factor applies at `T = 2` too — the 2×2 path is Burlig's `m = r = 1` special case (footnote 11), so a nonzero `rho` is no longer silently ignored there, while `rho = 0` still recovers Bloom's `2σ²`. The MDE multiplier stays the **normal (z)** Bloom multiplier (a deliberate large-sample approximation to Burlig's t, documented as `**Deviation from R:**`) — unchanged. New `tests/test_methodology_power.py` (Bloom Table 1 multipliers; 2×2 + panel closed forms; a literal-equicorrelated Monte-Carlo validation of the panel variance; `sample_size`↔`mde` round-trip; input-guard + `rho`-at-`T=2` + `compute_*` wrapper validation; base-R `qnorm` parity at `benchmarks/data/r_power_golden.json`, generator `benchmarks/R/generate_power_golden.R`); the two `tests/test_power.py` ICC-direction tests were inverted to Burlig's sign. REGISTRY `## PowerAnalysis` equation block rewritten (z not t; corrected 2×2 / panel SE + sample-size; removed the cluster-`m` and inverted-`R²` terms that matched neither code nor source); `docs/references.rst` adds Frison & Pocock (1992) + McKenzie (2012) as the equicorrelated lineage; tutorial `06_power_analysis.ipynb` corrected. `METHODOLOGY_REVIEW.md` row promoted to **Complete** (`Last Review = 2026-05-31`); priority queue pruned; the PR-A under-review Notes removed across REGISTRY / `power.py` / `references.rst`. - **`WooldridgeDiD` outcome-fit hint:** `WooldridgeDiD(method="ols")` now emits a `UserWarning` when the outcome is binary (`{0, 1}`) or a non-negative integer count, noting that a matching nonlinear model (`method="logit"` / `method="poisson"`) is often the **more appropriate specification** for such outcomes. Following Wooldridge (2023): the nonlinear paths impose parallel trends on the link/index scale rather than in levels (level-PT is only valid for continuous/unbounded outcomes), and the paper's Section 5 simulations show the linear model both biased and less precise where the nonlinear mean holds. It is a **different identifying assumption** than linear OLS — which one fits depends on which parallel-trends restriction holds — so the warning frames it as a recommended comparison, not an automatic switch or free efficiency upgrade. OLS remains a valid QMLE for *any* response (Table 1). Always-on (suppress via `warnings.filterwarnings`); detection is high-signal (binary requires exactly `{0, 1}`; the count branch suggests Poisson — the natural unbounded-count model — for *any* non-negative integers with >2 distinct values, so bounded binomial / known-upper-bound integer outcomes are not separately distinguished from unbounded counts; fractional / continuous outcomes are not flagged). @@ -1537,6 +1539,7 @@ for the full feature history leading to this release. [2.1.2]: https://github.com/igerber/diff-diff/compare/v2.1.1...v2.1.2 [2.1.1]: https://github.com/igerber/diff-diff/compare/v2.1.0...v2.1.1 [2.1.0]: https://github.com/igerber/diff-diff/compare/v2.0.3...v2.1.0 +[3.5.0]: https://github.com/igerber/diff-diff/compare/v3.4.2...v3.5.0 [3.4.2]: https://github.com/igerber/diff-diff/compare/v3.4.1...v3.4.2 [3.4.1]: https://github.com/igerber/diff-diff/compare/v3.4.0...v3.4.1 [3.4.0]: https://github.com/igerber/diff-diff/compare/v3.3.3...v3.4.0 diff --git a/CITATION.cff b/CITATION.cff index 4ecd7ba0..1e3c3278 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -7,8 +7,8 @@ authors: family-names: Gerber orcid: "https://orcid.org/0009-0009-3275-5591" license: MIT -version: "3.4.2" -date-released: "2026-05-25" +version: "3.5.0" +date-released: "2026-06-01" doi: "10.5281/zenodo.19646175" url: "https://github.com/igerber/diff-diff" repository-code: "https://github.com/igerber/diff-diff" diff --git a/diff_diff/__init__.py b/diff_diff/__init__.py index 724eb944..ca5cdda9 100644 --- a/diff_diff/__init__.py +++ b/diff_diff/__init__.py @@ -298,7 +298,7 @@ DCDH = ChaisemartinDHaultfoeuille HAD = HeterogeneousAdoptionDiD -__version__ = "3.4.2" +__version__ = "3.5.0" __all__ = [ # Estimators "DifferenceInDifferences", diff --git a/diff_diff/guides/llms-full.txt b/diff_diff/guides/llms-full.txt index c0e2caf9..1165b241 100644 --- a/diff_diff/guides/llms-full.txt +++ b/diff_diff/guides/llms-full.txt @@ -2,7 +2,7 @@ > A Python library for Difference-in-Differences causal inference analysis. Provides sklearn-like estimators with statsmodels-style output for econometric analysis. -- Version: 3.4.2 +- Version: 3.5.0 - Repository: https://github.com/igerber/diff-diff - License: MIT - Dependencies: numpy, pandas, scipy (no statsmodels dependency) diff --git a/pyproject.toml b/pyproject.toml index 90e6a046..9c70d82d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "maturin" [project] name = "diff-diff" -version = "3.4.2" +version = "3.5.0" description = "Difference-in-Differences causal inference with sklearn-like API. Callaway-Sant'Anna, Synthetic DiD, Honest DiD, event studies, parallel trends." readme = "README.md" license = "MIT" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 83e5295d..1ad3c9a5 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "diff_diff_rust" -version = "3.4.2" +version = "3.5.0" edition = "2021" rust-version = "1.85" description = "Rust backend for diff-diff DiD library"