Skip to content

Commit 3b7408a

Browse files
igerberclaude
andcommitted
Address PR #356 CI review round 11 (1 P1 guide + 1 P2 test)
HeterogeneousAdoptionDiD staggered support is `partial` (per §3 matrix), but the restriction was never unpacked. Per REGISTRY.md L2281 and had.py:1100-1288, Appendix B.2 limits staggered HAD to the **last treatment cohort plus never-treated units**. With `first_treat_col` supplied, `fit(aggregate="event_study")` auto-filters to F_last and emits a UserWarning naming kept/dropped counts; earlier-cohort units are dropped. Without `first_treat_col` on a multi-cohort panel, fit() raises a front-door ValueError pointing at ChaisemartinDHaultfoeuille for full staggered support. Guide updates: - New §3 footnote on the HAD `partial` cell spelling out the last- cohort-only restriction, the `first_treat_col` requirement for the auto-filter, and the ChaisemartinDHaultfoeuille fallback. - §4.9 HAD bullet appended with a "Staggered-timing scope is last- cohort-only" paragraph carrying the same contract plus the "last-cohort-only WAS" estimand clarification. Tests: - Semantic guide test asserts "last-cohort-only" (or "last cohort") wording, "first_treat_col" token, and ChaisemartinDHaultfoeuille as the fallback are all present so future guide edits cannot silently drop the Appendix B.2 disclosure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 44a552f commit 3b7408a

2 files changed

Lines changed: 41 additions & 0 deletions

File tree

diff_diff/guides/llms-autonomous.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,15 @@ supported / out of scope; `warn` supported but with documented caveats;
259259
- `HeterogeneousAdoptionDiD` continuous: supports partial-adoption
260260
intensity as a continuous first-stage variable; not a pure
261261
dose-response estimator - use `ContinuousDiD` for that.
262+
- `HeterogeneousAdoptionDiD` staggered support is `partial`, not
263+
general. Paper Appendix B.2 restricts staggered use to the
264+
**last treatment cohort plus never-treated units**. With
265+
`aggregate="event_study"` and a `first_treat_col` kwarg,
266+
`fit()` auto-filters to `F_last = max(cohorts)` and emits a
267+
`UserWarning` naming kept/dropped counts; earlier-cohort units
268+
are dropped. Without `first_treat_col`, a multi-cohort panel
269+
raises `ValueError`. For full staggered support that retains
270+
every cohort, use `ChaisemartinDHaultfoeuille` instead.
262271

263272
**Balanced-panel eligibility.** The following estimators hard-reject
264273
unbalanced panels (each raises `ValueError` at `fit()` when a unit is
@@ -459,6 +468,19 @@ intensity of exposure differs):
459468
pre-test battery does not and cannot validate it. Not ATT-shaped; do
460469
not relabel the headline as ATT in report text.
461470

471+
**Staggered-timing scope is last-cohort-only (Appendix B.2).**
472+
HAD's staggered support is the `partial` cell in §3: on a
473+
multi-cohort panel passed to `aggregate="event_study"`, `fit()`
474+
auto-filters to the last treatment cohort (`F_last =
475+
max(cohorts)`) plus never-treated units and emits a
476+
`UserWarning` naming kept/dropped counts; earlier treated
477+
cohorts are dropped. The `first_treat_col` kwarg is
478+
**required** for the auto-filter to activate; without it a
479+
multi-cohort panel raises `ValueError` pointing the caller at
480+
`ChaisemartinDHaultfoeuille` for full staggered support. The
481+
resulting estimand is a **last-cohort-only WAS**, not a
482+
multi-cohort average — report it as such.
483+
462484
### §4.10 Repeated cross-sections (no panel structure)
463485

464486
`profile_panel` assumes long-format panel data. When the same units are

tests/test_profile_panel.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,25 @@ def test_guide_api_strings_resolve_against_public_api():
656656
"at fit time)"
657657
)
658658

659+
# HeterogeneousAdoptionDiD staggered support is `partial` and
660+
# specifically last-cohort-only (Appendix B.2): with first_treat_col
661+
# supplied, fit() auto-filters to F_last + never-treated; without
662+
# first_treat_col, a multi-cohort panel raises. Guide must surface
663+
# this explicitly so agents don't route a general staggered panel
664+
# to HAD expecting a multi-cohort estimand.
665+
assert "last-cohort-only" in text or "last cohort" in text.lower(), (
666+
"Guide must name the last-cohort-only restriction on HAD "
667+
"staggered support (Appendix B.2)"
668+
)
669+
assert "first_treat_col" in text, (
670+
"Guide must mention that first_treat_col is required to activate "
671+
"HAD's staggered last-cohort auto-filter"
672+
)
673+
assert "ChaisemartinDHaultfoeuille" in text, (
674+
"Guide must point at ChaisemartinDHaultfoeuille as the fallback "
675+
"for full staggered support"
676+
)
677+
659678

660679
def test_min_pre_post_use_per_unit_observed_support():
661680
"""On an unbalanced panel where one treated unit is missing its

0 commit comments

Comments
 (0)