Skip to content

Commit 8a9f32c

Browse files
igerberclaude
andcommitted
dCDH heterogeneity wrap-up: terminology cleanup (codex R2 P3s)
Two P3 informational findings from R2: 1. TODO.md Tier B backlog still listed the dCDH heterogeneity df- threading and by-path placebo predict_het items as open, but PR #449 closed both. Replaced the two stale bullets with a single bullet for the remaining survey + backward-horizon allocator derivation (the one Medium follow-up explicitly tracked in the wrap-up commit). 2. Three test-prose comments still said `df = n_obs - n_params` while the implementation and REGISTRY now use `df = n_obs - rank(design)`. Updated each comment to the post-drop rank wording; full-rank designs continue to have `rank == n_params` so the SE-derivation invariants under test are unchanged. Comment-only drift; no behavior change. 317 tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent fa1268e commit 8a9f32c

3 files changed

Lines changed: 16 additions & 13 deletions

File tree

TODO.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,7 @@ Ordered paydown view across the tables above. Tier A → D is by effort × risk,
184184
- WooldridgeDiD: optional `weights="cohort_share"` on `aggregate()` (`wooldridge_results.py`)
185185
- HAD survey-design API consolidation: drop deprecated `survey=`/`weights=` kwargs (`had.py`, `had_pretests.py`; gated on next minor bump)
186186
- Survey-design resolution / collapse helper extraction across `continuous_did.py`, `efficient_did.py`, `stacked_did.py`
187-
- dCDH heterogeneity df threading: t-distribution at heterogeneity surface (or formalize the tolerance constant) (`chaisemartin_dhaultfoeuille.py`)
188-
- dCDH by_path placebo `predict_het` parity vs R `did_multiplegt_dyn(..., by_path, predict_het)` (`chaisemartin_dhaultfoeuille.py`, `chaisemartin_dhaultfoeuille_results.py`)
187+
- dCDH survey + backward-horizon `predict_het` allocator derivation: lift the warn-and-skip fallback at `_compute_heterogeneity_test` once the pre-period Binder TSL cell-period allocator is derived (currently the gate emits a `UserWarning` and falls back to forward-horizon-only heterogeneity under `survey_design + placebo + heterogeneity`) (`chaisemartin_dhaultfoeuille.py`, `docs/methodology/REGISTRY.md`)
189188
- Rust local-method solver path unification to `solve_wls_svd` + bootstrap-weight RNG parity audit (`rust/src/trop.rs`, `rust/src/bootstrap.rs`)
190189
- AI review CI workflow-contract pin test expansion (`tests/test_openai_review.py`)
191190
- In-site Sphinx render of `REPORTING.md` and `REGISTRY.md` (`docs/conf.py` + `:doc:` link migration)

tests/test_chaisemartin_dhaultfoeuille.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2870,11 +2870,12 @@ def test_heterogeneity_multi_horizon(self):
28702870
def test_heterogeneity_inference_local_invariants(self):
28712871
"""Local SE-derivation invariants for non-survey heterogeneity
28722872
inference. Post-2026-05-15 df threading: Python passes
2873-
``df = n_obs - n_params`` to ``safe_inference`` (matching R's
2874-
t-distribution); R-parity is pinned in
2873+
``df = n_obs - rank(design)`` to ``safe_inference`` (matching
2874+
R's t-distribution); for full-rank designs ``rank == n_params``.
2875+
R-parity is pinned in
28752876
``tests/test_chaisemartin_dhaultfoeuille_parity.py``. This local
28762877
test verifies the SE-derived fields are wired correctly
2877-
without requiring back-derivation of ``n_params``:
2878+
without requiring back-derivation of ``rank``:
28782879
``t_stat = beta / se``; ``conf_int`` symmetric around ``beta``
28792880
with positive half-width; ``p_value`` in ``[0, 1]``.
28802881
Without these checks a regression isolated to the inference
@@ -10354,12 +10355,13 @@ def test_per_path_heterogeneity_finite_under_known_signal(self):
1035410355
def test_per_path_heterogeneity_inference_local_invariants(self):
1035510356
"""Local SE-derivation invariants for non-survey per-path
1035610357
heterogeneity inference. Post-2026-05-15 df threading: Python
10357-
passes ``df = n_obs - n_params`` to ``safe_inference``; R-parity
10358-
is pinned in
10358+
passes ``df = n_obs - rank(design)`` to ``safe_inference``
10359+
(full-rank designs have ``rank == n_params``); R-parity is
10360+
pinned in
1035910361
``tests/test_chaisemartin_dhaultfoeuille_parity.py::
1036010362
TestDCDHDynRParityByPathHeterogeneity``. Verifies SE-derivation
1036110363
wiring (``t_stat = beta/se``, symmetric ``conf_int`` around beta,
10362-
``p_value`` in ``[0, 1]``) without back-deriving ``n_params``.
10364+
``p_value`` in ``[0, 1]``) without back-deriving ``rank``.
1036310365
Mirrors
1036410366
``TestHeterogeneityTesting::test_heterogeneity_inference_local_invariants``.
1036510367
"""

tests/test_chaisemartin_dhaultfoeuille_parity.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,11 +1410,13 @@ def test_parity_multi_path_reversible_predict_het(self, golden_values):
14101410
f"h={h} n_obs: py={py_h['n_obs']} vs r={r_h['n_obs']}"
14111411
)
14121412
# `p_value` and `conf_int` parity (post-2026-05-15 df threading).
1413-
# `_compute_heterogeneity_test` now passes `df = n_obs - n_params`
1414-
# to `safe_inference`, matching R's t-distribution with WLS df.
1415-
# Pinned at INFERENCE_RTOL = 1e-4 because Wald-test critical
1416-
# values come from `scipy.stats.t.ppf` and `t.sf` which are
1417-
# implementation-aligned with R's `qt`/`pt` to ~6 sig figs.
1413+
# `_compute_heterogeneity_test` now passes
1414+
# `df = n_obs - rank(design)` to `safe_inference`, matching
1415+
# R's t-distribution with WLS df (full-rank designs have
1416+
# `rank == n_params`). Pinned at INFERENCE_RTOL = 1e-4
1417+
# because Wald-test critical values come from
1418+
# `scipy.stats.t.ppf` and `t.sf` which are implementation-
1419+
# aligned with R's `qt`/`pt` to ~6 sig figs.
14181420
assert py_h["p_value"] == pytest.approx(
14191421
r_h["p_value"], rel=self.INFERENCE_RTOL
14201422
), f"h={h} p_value: py={py_h['p_value']:.6e} vs r={r_h['p_value']:.6e}"

0 commit comments

Comments
 (0)