Skip to content

LWDiD Stata parity arm + acceptance-suite re-anchor + REGISTRY amendments - #773

Merged
igerber merged 2 commits into
mainfrom
lwdid-stata-arm
Aug 16, 2026
Merged

LWDiD Stata parity arm + acceptance-suite re-anchor + REGISTRY amendments#773
igerber merged 2 commits into
mainfrom
lwdid-stata-arm

Conversation

@igerber

@igerber igerber commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Summary

  • Stata parity arm for LWDiD (benchmarks/stata/generate_lwdid_golden.do -> benchmarks/data/lwdid_stata_golden.json): runs the authors' own SSC lwdid package (v2.4.2, version line pinned in meta, fail-closed capture) over the loader-cached Prop 99/Walmart panels and the committed castle subset. Emits full-precision small-N ATT/SE (Prop 99 both rollings + castle tau_omega), Prop 99 randomization-inference p at 100k reps, and the six Walmart event-study configs' per-r WATT points + B=9,999 multiplier-bootstrap SEs. Fail-closed input chain: on-disk cache SHA warm-up, in-.do schema/row-count gates, nonmissing + one-row-per-event-time asserts before emission.
  • Acceptance-suite rewrite (tests/test_methodology_lwdid.py): now written against the agreed post-rename LWDiD API and serves as the acceptance bar for PR feat: add LWDiD estimator (Lee & Wooldridge 2025, 2026) #588's final round (it intentionally fails on the pre-rename contribution head; the round is complete when it passes unmodified). Key re-anchors: the RI golden moves from the paper's printed 0.020 to the authors'-package inclusive-ties convention (~0.051; the printed value is not reproducible with the package — REGISTRY RI note); the Walmart SE xfail scaffolding is retired — RA-config bootstrap SEs gate against the Stata golden at a Monte-Carlo-informed tolerance, while the IPWRA SE columns are provenance-only pending the E.3 influence-function adjudication (~15% systematic divergence measured — REGISTRY IPWRA-variance note). New: full-precision TestStataParity (incl. the Post_avg cell-mass convention pin), retired-surface negative assertions, shared-validation contracts (covariate/cluster unit-constancy on both paths, mixed time-family rejection, row-order invariance), sensitivity contracts, and balanced + unbalanced cross-path estimand-consistency pins.
  • Ungated golden schema test (tests/test_lwdid_stata_golden_schema.py): validates the committed golden's schema/cardinality on main (the methodology suite import-skips until diff_diff.lwdid lands) and hosts the shared expected-set constants.
  • REGISTRY LWDiD maintainer notes: RI convention (as-printed discrepancy), dual overall-ATT conventions (tau_omega vs Stata large-N Post_avg cell-mass), Sec 4.3 all-eventually-treated rejection, inference default, IPWRA variance forms, Conley non-offering, pre-release API-conformance decisions, anchor-surface clarifications; requirements checklist split/annotated to match.
  • Backlog + inventory: DEFERRED.md Sec 4.3 parked row + fixed-B CI-cost decision record; TODO.md cell-mass-overall row; benchmarks/stata/requirements.do gains lwdid; benchmarks READMEs and docs/benchmarks.rst refreshed to the five-arm inventory; CHANGELOG entry.

Methodology references (required if estimator / math changes)

  • Method name(s): LWDiD (Lee & Wooldridge rolling-transformation DiD) — validation infrastructure only; no diff_diff/ source changes in this PR.
  • Paper / source link(s):
  • Any intentional deviations from the source (and why): all recorded as labeled REGISTRY Notes in the ## LWDiD section — RI anchored to the authors'-package inclusive-ties convention (the paper's printed 0.020 is not reproducible with the package, ~4.5 binomial SD away); .att = tau_omega (eq. 7.18) while Stata's large-N Post_avg display uses cell-mass weighting (both author-sanctioned; documented, both pinned); IPWRA bootstrap-SE parity deliberately not gated pending the E.3 influence-function adjudication in the contribution's final round.

Validation

  • Tests added/updated: tests/test_methodology_lwdid.py (rewritten; skips on main until diff_diff.lwdid lands), tests/test_lwdid_stata_golden_schema.py (new; runs on main, 5 tests). Verified against the PR feat: add LWDiD estimator (Lee & Wooldridge 2025, 2026) #588 head under a local kwarg-compatibility shim: 58 pass / 29 fail with the failures exactly matching the enumerated expected-fail lanes (the contribution's remaining work items). Full-precision parity confirmed: Prop 99 + castle ATT/SE, Walmart RA points to ~1e-9, RA bootstrap SEs within the MC bound, Post_avg convention to 7e-12.
  • Backtest / simulation / notebook evidence (if applicable): generator log clean (grep -E '^r\([0-9]+\);' empty); goldens spot-checked against the recorded smoke measurements.

Security / privacy

  • Confirm no secrets/PII in this PR: Yes

@github-actions

Copy link
Copy Markdown

Overall assessment

⚠️ Needs changes — one unmitigated P1 methodology inconsistency.

Executive summary

  • Affected method: LWDiD, especially covariate-adjusted exact inference.
  • The acceptance test conflates the simple controlled regression with the interaction-augmented RA regression, enforcing incorrect degrees of freedom.
  • RI, schema, and clustering tests contain P2 validation gaps.
  • RI/IPWRA/default-inference deviations and deferred features are properly documented and non-blocking.
  • Static syntax and JSON checks passed; pytest and Stata were unavailable.

Methodology

P1 — Incorrect degrees of freedom for interacted RA

  • Location: tests/test_methodology_lwdid.py:L787-L797; docs/methodology/REGISTRY.md:L2546-L2560
  • Impact: The test expects (N-K-2) df while estimation_method="reg" is defined as the LW 2025 E.1 regression with X and D·(X−X̄). That design has (2K+2) coefficients, hence residual df (N-2K-2). The test would force anti-conservative p-values or reject a correct implementation.
  • Concrete fix: For the Registry’s current E.1 design, derive df from design rank; with one covariate this test should use n - 4. If the simpler LW 2026 regression without interactions is intended instead, document that selection in a labeled Registry Note and test that exact design explicitly.

P3 — Documented deviations

  • Location: docs/methodology/REGISTRY.md:L2555-L2569
  • Impact: Analytical-default inference, AIPW-style IPW/IPWRA influence functions, inclusive RI, omitted Conley support, dual overall estimands, and all-treated rejection differ from source recommendations.
  • Concrete fix: None required here; all are explicitly labeled Registry Notes or tracked deferrals.

Code Quality

No additional findings.

Performance

P3 — Fixed-B tests run in default CI

  • Impact: Six bootstrap fits add CI cost.
  • Concrete fix: None; explicitly accepted in DEFERRED.md:L132.

Maintainability

No findings.

Tech Debt

P3 — Deferred LWDiD surfaces are tracked

  • Impact: Cell-mass overall ATT and all-eventually-treated support remain unavailable.
  • Concrete fix: None for this PR; tracked in TODO.md:L24 and DEFERRED.md:L75.

Security

No findings or accidental secrets observed.

Documentation/Tests

P2 — RI test does not pin the plus-one formula

  • Location: tests/test_methodology_lwdid.py:L433-L455
  • Impact: The ±0.021 Monte Carlo tolerance cannot distinguish ((c+1)/(B+1)) from the paper’s (c/B), despite claiming to enforce that convention.
  • Concrete fix: Add a deterministic small-repetition test with a known extreme count and exact expected p-value.

P2 — Small-N golden schema permits malformed values

  • Location: tests/test_lwdid_stata_golden_schema.py:L67-L106
  • Impact: Prop99 accepts booleans/NaN/Inf, while Castle accepts any non-null value, so the ungated schema check can pass malformed anchors.
  • Concrete fix: Require _is_finite_number() for every Prop99 and Castle ATT, SE, and RI p-value.

P2 — Cluster oracle lacks cluster-correlated variation

  • Location: tests/test_methodology_lwdid.py:L1470-L1496
  • Impact: shock is drawn per unit and removed by demeaning; merely checking that two SEs differ does not verify clustering by cl.
  • Concrete fix: Draw a cluster-level post-period shock and compare the SE against an explicit CR1 calculation.

Path to Approval

  1. Align the covariate exact-inference test with the actual regression design: use design-rank df—n - 4 for the current one-covariate E.1 test—or explicitly document and test a non-interacted exact-inference path.

@github-actions

Copy link
Copy Markdown

🔁 AI review rerun (requested by @igerber)

Head SHA: d4d29d59d77ce6f743cbd95da656a6cc439bdeb5


Overall assessment

Looks good — the prior P1 is resolved; remaining findings are P2/P3 only.

Executive summary

  • LWDiD exact inference now uses design-coherent residual degrees of freedom.
  • Prior RI-formula and golden-finiteness gaps are resolved.
  • The cluster oracle remains incomplete at P2.
  • All methodology deviations are explicitly documented and non-blocking.
  • Static syntax, JSON schema, cardinality, finiteness, and RI-denominator checks passed.

Methodology

P3 — Documented LWDiD deviations

  • Location: docs/methodology/REGISTRY.md:L2555-L2570
  • Impact: Analytical-default inference, inclusive RI, AIPW-style IPWRA variance, dual overall estimands, omitted Conley support, and all-treated rejection differ from source recommendations.
  • Concrete fix: None required; each is covered by a labeled Registry Note or tracked deferral.

The previous exact-inference P1 is resolved at tests/test_methodology_lwdid.py:L805-L841: the test identifies the fitted regression design and applies its residual df.

Code Quality

No findings.

Performance

P3 — Fixed bootstrap workloads

  • Impact: Six fixed-B Walmart fits increase default CI cost.
  • Concrete fix: None; explicitly accepted in DEFERRED.md:L132.

Maintainability

No findings.

Tech Debt

P3 — Deferred surfaces are tracked

  • Impact: Cell-mass overall ATT and all-eventually-treated support remain unavailable.
  • Concrete fix: None for this PR; tracked in TODO.md:L24 and DEFERRED.md:L75.

Security

No findings or accidental secrets observed.

Documentation/Tests

P2 — Cluster oracle still does not validate CR1 numerically

  • Location: tests/test_methodology_lwdid.py:L1514-L1551
  • Impact: The new cluster-level shock catches ignored clustering, but any incorrect adjustment producing an SE 15% larger than HC1 still passes.
  • Concrete fix: Independently collapse outcomes, compute the CR1 sandwich with (G/(G−1))((N−1)/(N−K)), and assert equality with r_cl.se.

P2 — README overstates Walmart generator smoke gates

  • Location: benchmarks/stata/README.md:L317-L318, L357-L363; benchmarks/stata/generate_lwdid_golden.do:L177-L217
  • Impact: Documentation claims measured-value gates per block, but the Walmart block has only schema/nonmissing checks.
  • Concrete fix: Add independent Walmart point assertions or state that measured-value smoke gates cover only the small-N blocks.

P2 — Benchmark inventory omits LWDiD

  • Location: docs/benchmarks.rst:L25-L57
  • Impact: The canonical comparison table does not list the newly added LWDiD/Stata arm.
  • Concrete fix: Add an LWDiD → Stata lwdid row.

@github-actions

Copy link
Copy Markdown

🔁 AI review rerun (requested by @igerber)

Head SHA: c3889511a1bddd2971f250de6b122065e04d6a3d


Overall assessment

Looks good — all previous findings are resolved; no unmitigated P0/P1 issues remain.

Executive summary

  • The exact CR1 cluster oracle now validates the numerical sandwich directly.
  • README smoke-gate scope and benchmark inventory documentation are corrected.
  • LWDiD deviations are explicitly labeled in the Methodology Registry.
  • Golden JSON cardinality, finiteness, RI denominator, and Python syntax checks passed.
  • Full pytest execution was unavailable because pytest is not installed in the review environment.

Methodology

P3 — Documented LWDiD deviations

  • Location: docs/methodology/REGISTRY.md:L2555-L2570
  • Impact: Analytical-default inference, inclusive RI, alternative IPWRA influence functions, dual overall estimands, omitted Conley support, and all-treated rejection differ from the papers or reference implementation.
  • Concrete fix: None required. Each deviation is explicitly labeled in the Registry, so it is informational under the review policy.

The prior exact-inference issue remains resolved by the design-coherence test at tests/test_methodology_lwdid.py:L805-L841.

Code Quality

No findings.

Performance

P3 — Fixed bootstrap workload is accepted

  • Location: DEFERRED.md:L132
  • Impact: Fixed-B Walmart comparisons add several bootstrap fits to default CI.
  • Concrete fix: None required; the cost and rationale are explicitly accepted.

Maintainability

No findings.

Tech Debt

P3 — Deferred LWDiD surfaces are tracked

  • Location: TODO.md:L24, DEFERRED.md:L75
  • Impact: Cell-mass overall ATT and all-eventually-treated support remain unavailable.
  • Concrete fix: None required for this PR; both are tracked.

Security

No findings or accidental secrets observed.

Documentation/Tests

No findings. All prior P2 items are resolved:

  • Exact CR1 equality is now asserted at tests/test_methodology_lwdid.py:L1514-L1572.
  • Walmart smoke-gate scope is accurate at benchmarks/stata/README.md:L317-L321.
  • LWDiD appears in the benchmark inventory at docs/benchmarks.rst:L58-L60.

@igerber igerber added the ready-for-ci Triggers CI test workflows label Aug 16, 2026
…ents

Maintainer-side infrastructure ahead of PR #588's final round:

- benchmarks/stata/generate_lwdid_golden.do + benchmarks/data/lwdid_stata_golden.json:
  authors' lwdid (SSC v2.4.2, version line pinned in meta) full-precision
  goldens - prop99 small-N ATT/SE + randomization inference at 100k reps,
  castle tau_omega both rollings, six Walmart event-study configs (per-r WATT
  points + B=9,999 multiplier-bootstrap SEs). Fail-closed guards: SSC version
  capture, cache SHA warm-up, in-.do schema/row-count/value gates, nonmissing
  + one-row-per-event-time asserts before emission.
- tests/test_methodology_lwdid.py: rewritten against the agreed post-rename
  LWDiD API as the acceptance bar for the contribution's final round. RI
  golden re-anchored from the paper's printed 0.020 to the authors'-package
  inclusive-ties convention (~0.051; not reproducible with the package), with
  a deterministic (c+1)/(B+1) formula pin; Walmart SE xfail scaffolding
  retired - RA-config bootstrap SEs gate against the Stata golden at a
  Monte-Carlo-informed tolerance, IPWRA SE columns are provenance-only
  pending the E.3 influence-function adjudication (~15% systematic divergence
  measured); full-precision TestStataParity (prop99, castle, Walmart points,
  Post_avg cell-mass convention pin); design-coherent covariate exact
  inference (the fitted design's residual df - the contribution head fits the
  interacted E.1 design while reporting the plain design's T_{N-K-2});
  cluster oracle with cluster-level post-period shocks and an exact CR1
  sandwich pin; retired-surface, shared-validation (covariate/cluster
  constancy on both paths, mixed time-family rejection, row-order
  invariance), sensitivity-contract, and balanced + unbalanced cross-path
  estimand pins.
- tests/test_lwdid_stata_golden_schema.py: ungated schema/cardinality/
  finiteness check so main's CI validates the committed golden (the
  methodology suite import-skips until diff_diff.lwdid lands); hosts the
  shared expected-set constants.
- docs/methodology/REGISTRY.md LWDiD notes: RI convention (as-printed
  discrepancy), dual overall-ATT conventions (tau_omega vs Post_avg
  cell-mass), Sec 4.3 rejection, inference default, IPWRA variance forms,
  controlled-design exact-inference coherence, Conley non-offering,
  API-conformance decisions, anchor-surface clarifications; checklist boxes
  split/annotated accordingly.
- Backlog: DEFERRED.md Sec 4.3 parked row + fixed-B CI-cost decision record;
  TODO.md cell-mass overall row. benchmarks/stata/requirements.do gains
  lwdid; CHANGELOG entry; benchmarks READMEs + docs/benchmarks.rst inventory
  refresh (five arms incl. the LWDiD row, qualified as the precommitted
  validation arm).
@github-actions

Copy link
Copy Markdown

🔁 AI review rerun (requested by @igerber)

Head SHA: bb6e444ebc4928691176199f6a81bae5cb082254


Overall assessment

Looks good — no unmitigated P0/P1 findings.

Executive summary

  • Prior exact-inference and CR1-oracle findings remain resolved.
  • LWDiD methodology deviations are explicitly documented in the Registry.
  • Golden JSON syntax, cardinality, finiteness, and provenance constants validated.
  • Full pytest/Stata execution was unavailable because dependencies and Stata are absent.

Methodology

P3 — Documented LWDiD deviations

  • Location: docs/methodology/REGISTRY.md:L2556-L2571
  • Impact: Analytical-default inference, alternative IPWRA influence functions, inclusive RI, dual overall estimands, omitted Conley support, and all-treated rejection differ from source procedures.
  • Concrete fix: None required; each deviation is explicitly labeled and therefore informational.

Exact controlled-inference coherence is pinned at tests/test_methodology_lwdid.py:L805-L841, while CR1 equality is directly checked at tests/test_methodology_lwdid.py:L1514-L1572.

Code Quality

No findings.

Performance

P3 — Fixed bootstrap workload accepted

  • Location: DEFERRED.md:L135
  • Impact: Fixed-B Walmart parity tests add several bootstrap fits to default CI.
  • Concrete fix: None required; the cost is an explicit recorded decision.

Maintainability

No findings.

Tech Debt

P3 — Deferred LWDiD surfaces tracked

  • Location: TODO.md:L24, DEFERRED.md:L78
  • Impact: Cell-mass overall ATT and all-eventually-treated estimation remain unavailable.
  • Concrete fix: None required for this PR; both are tracked.

Security

No findings or accidental secrets observed. Dataset inputs carry SHA-256 provenance pins.

Documentation/Tests

No findings. Benchmark inventory and Walmart smoke-gate scope are accurate at docs/benchmarks.rst:L52-L60 and benchmarks/stata/README.md:L317-L321. The ungated schema checks cover structure and finiteness at tests/test_lwdid_stata_golden_schema.py:L73-L118.

period_effects mention

The new REGISTRY LWDiD API-conformance/aggregation Notes name PR #588's
pre-release period_effects surface being retired before it ships - a
documentation of the retirement, not a read of
MultiPeriodDiDResults.period_effects (M-016). CONSUMER_ALLOWLIST entry with
that rationale; both failing CI legs fail on exactly this one test.
@github-actions

Copy link
Copy Markdown

🔁 AI review rerun (requested by @igerber)

Head SHA: 8b9fb3c9fbe0e03bea91b49bb8b9db48985cd3c7


Overall assessment

Looks good — no unmitigated P0/P1 findings.

Executive summary

  • Prior exact-inference and clustered-CR1 findings remain resolved.
  • LWDiD methodology deviations are explicitly documented in the Registry.
  • Golden JSON syntax, cardinality, finiteness, and provenance checks passed.
  • Full pytest and Stata execution were unavailable in this environment.

Methodology

P3 — Documented LWDiD deviations

  • Location: docs/methodology/REGISTRY.md:L2556-L2571
  • Impact: Analytical inference default, alternative IPWRA influence functions, inclusive RI, dual overall estimands, omitted Conley support, and all-treated rejection differ from source procedures.
  • Concrete fix: None required; each deviation is explicitly labeled.

Controlled exact inference is gated at tests/test_methodology_lwdid.py:L805-L841; clustered CR1 equality at tests/test_methodology_lwdid.py:L1514-L1572.

Code Quality

No findings.

Performance

P3 — Fixed bootstrap workload accepted

  • Location: DEFERRED.md:L135
  • Impact: Fixed-B Walmart parity tests add bootstrap work to default CI.
  • Concrete fix: None required; this is an explicit recorded decision.

Maintainability

No findings.

Tech Debt

P3 — Deferred LWDiD surfaces tracked

  • Location: TODO.md:L24, DEFERRED.md:L78
  • Impact: Cell-mass overall ATT and all-eventually-treated estimation remain unavailable.
  • Concrete fix: None required for this PR; both are tracked.

Security

No findings or accidental secrets observed.

Documentation/Tests

No findings. The ungated schema checks cover structure, cardinality, and finite values at tests/test_lwdid_stata_golden_schema.py:L73-L118.

@igerber
igerber merged commit ba5a846 into main Aug 16, 2026
29 checks passed
@igerber
igerber deleted the lwdid-stata-arm branch August 16, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-ci Triggers CI test workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant