Skip to content

test(dml): replicate Chang (2020) §4.2.2 RCS simulation DGP (DML PR-B2) - #805

Merged
igerber merged 1 commit into
mainfrom
dml-s42-fixtures
Aug 30, 2026
Merged

test(dml): replicate Chang (2020) §4.2.2 RCS simulation DGP (DML PR-B2)#805
igerber merged 1 commit into
mainfrom
dml-s42-fixtures

Conversation

@igerber

@igerber igerber commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • Replicates Chang (2020) §4.2.2's own repeated-cross-section simulation DGP (arXiv v3 p. 19, kernel-estimation design) as maintainer validation fixtures for DMLDiD(panel=False), retiring the long-standing "paper's own §4 RCS DGPs are NOT replicated" caveat. Scope was settled by five dual plan-review rounds that executed the candidate designs.
  • New fixtures in tests/test_methodology_dml_did.py ("Chang Sec. 4.2.2" section): an exact-draw-order frame generator; a DGP-shape pin (distributions, all three innovation scales 0.1/0.2/0.3, stationary-sampling checks, the design's built-in confounded unadjusted contrast → θ₀+1 = 4 — its covariate-adjustment point — and both correct-specification facts: true propensity sigmoid(X − ½) by Bayes, true ℓ₂₀ = 0.25·X); seed-pinned recovery at both paper Ns with a 4·se gate, seed-pin absolute bounds, and a discriminating comparison requiring the adjusted estimate to beat the unadjusted contrast; and a slow MC coverage class. Fits run under a strict warning gate (tolerates only the documented A2.3 and propensity-trimming UserWarnings).
  • §4.2.1 (ML-estimation design): parameterization extracted into the paper review, but documented as NOT replicable with the bundled unpenalized learners — review-verified order-of-magnitude noise at (N=500, p=100) (SE ~4-10, EPV ~1.4-1.6 vs the solve_logit threshold, fitted out-of-fold clipping ~5-29% across seeds; true-propensity tail mass only ~0.06%) and a fail-closed linear-outcome rank deficiency at (N=200, p=100) even under an oracle propensity. The TODO row is narrowed accordingly (penalized propensity learner + p-robust outcome learner).
  • Paper review updated: full §4.2 parameterizations, the N(0, 0.1) variance-reading adoption, a ninth suspected-typo entry (§4.2.1's printed-but-unused β₀, with the trend-cancellation note showing both readings leave its parallel trends intact), and a Gaps entry for the paper's own regularity-condition quirks (Gaussian kernel vs Assumption 3.3 compact support; unbounded-index propensities vs a.s. strict overlap 3.2(a) in both §4.2 designs).
  • REGISTRY: Case 2 checklist bullet updated + a standalone - **Note:** recording the replication scope (native learners stand in for the paper's kernel first stages; the fixture is correctly specified on both nuisances, so it adds paper-DGP faithfulness rather than plug-in-bias reproduction; the overlap quirk; the §4.2.1 evidence). test_methodology_dr_scores.py banner comment synced; CHANGELOG ### Added entry.

Methodology references (required if estimator / math changes)

  • Method name(s): No estimator/math changes (validation fixtures + methodology docs only). DMLDiD — Chang (2020) Case 2.
  • Paper / source link(s): Chang, N.-C. (2020). Double/debiased machine learning for difference-in-differences models. The Econometrics Journal 23(2), https://doi.org/10.1093/ectj/utaa001 (fixtures parameterized from arXiv:1812.10846v3 §4.2, pp. 18-20).
  • Any intentional deviations from the source (and why): the fixtures estimate with the library's native learners instead of the paper's Gaussian-kernel first stages (no kernel first stage is bundled) — recorded as a standalone REGISTRY - **Note:**; "N(0, 0.1)" is adopted as variance 0.1 with the printed-notation ambiguity recorded in the paper review.

Validation

  • Tests added/updated: tests/test_methodology_dml_did.py (+3 classes: shape pin, seed-pinned recovery, slow MC coverage; incumbent RCS banner updated), tests/test_methodology_dr_scores.py (comment sync). Default lane + both suites green on the Rust and pure-Python backends; the new MC class green on both (200 reps Rust / reduced 22-rep band pure-Python).
  • Backtest / simulation / notebook evidence (if applicable): the seed-pinned recovery values reproduce the plan-review's independently executed measurements exactly (att 2.7581 / 2.9054 / 2.5580; unadjusted contrast 4.008 / 3.978 / 3.617); the DGP-shape pin verifies the generator against the paper's distributions at n=200k.

Security / privacy

  • Confirm no secrets/PII in this PR: Yes

@github-actions

Copy link
Copy Markdown

Overall assessment

Looks good — no unmitigated P0/P1 findings.

Executive summary

  • No estimator, weighting, variance, identification, or default behavior changed.
  • The §4.2.2 DGP, propensity, outcome nuisance, and confounded contrast match Chang’s Case 2 formulation.
  • Kernel-to-native-learner substitution and strict-overlap limitations are explicitly documented.
  • Static parsing passed; runtime tests could not be executed because this environment lacks pytest and NumPy.

Methodology

  • Severity: P3 — documented deviation. The paper uses Gaussian-kernel first stages, while the fixtures use correctly specified native learners. The unbounded covariate also violates literal strict overlap. Both are recorded in the REGISTRY Note at docs/methodology/REGISTRY.md:L3132.
    • Impact: The tests replicate the paper’s DGP and validate estimator recovery, but do not reproduce its kernel plug-in behavior.
    • Concrete fix: None required; retain the existing Note.

The generator and assertions correctly establish g₀(X)=sigmoid(X−½), ℓ₂₀(X)=0.25X, and the unadjusted contrast θ₀+1=4 at tests/test_methodology_dml_did.py:L730-L750 and tests/test_methodology_dml_did.py:L792-L838.

Code Quality

No findings. The warning gate rejects unexpected learner, degeneracy, and inference warnings.

Performance

No findings. The expensive Monte Carlo coverage test is marked slow and uses backend-aware replication scaling at tests/test_methodology_dml_did.py:L872-L889.

Maintainability

No findings. The fixture helpers isolate generation, fitting, and the comparison contrast cleanly.

Tech Debt

  • Severity: P3 — tracked. §4.2.1 replication remains deferred in TODO.md:L82.
    • Impact: Validation covers §4.2.2 but not the high-dimensional ML design.
    • Concrete fix: No action required for this PR; the TODO identifies the required penalized propensity and robust outcome learners.

Security

No findings; no secrets, external inputs, or security-sensitive behavior were introduced.

Documentation/Tests

No findings. Documentation consistently states the variance interpretation, learner substitution, overlap caveat, and replication scope. Recovery checks fail closed if SEs or confidence intervals become NaN. Python AST parsing passed for both changed test modules; full execution was unavailable because test dependencies are absent.

@igerber igerber added the ready-for-ci Triggers CI test workflows label Aug 29, 2026
Replaces the "paper's own §4 RCS DGPs are NOT replicated" caveat with the
real thing, scoped by five dual-review rounds that executed the candidate
designs:

- §4.2.2 (kernel-estimation design, arXiv v3 p. 19) replicated verbatim in
  tests/test_methodology_dml_did.py: an exact-draw-order frame generator; a
  DGP-shape pin covering the distributions, all three innovation scales
  (0.1/0.2/0.3), stationary-sampling checks (T independent of (D, X)), the
  design's built-in confounded unadjusted contrast (-> theta0 + 1 = 4, its
  covariate-adjustment point), and both correct-specification facts (true
  propensity sigmoid(X - 1/2) by Bayes; true l20 = 0.25 X); seed-pinned
  recovery at both paper Ns (sieve + linear at N=500, linear at N=200, each
  with a 4*se gate, a seed-pin absolute bound, and a discriminating
  comparison requiring the adjusted estimate to beat the unadjusted
  contrast); and a slow MC coverage class (the file's third), seeds offset
  from the incumbent streams. Fits run under a strict warning gate that
  tolerates exactly the documented panel=False Assumption 2.3 UserWarning
  and the occasional propensity-trimming UserWarning (rare fitted-tail
  excursions on the unbounded-X design) and fails on anything else.
  "N(0, 0.1)" adopted as VARIANCE 0.1 with the ambiguity recorded.
- §4.2.1 (ML-estimation design) extracted into the paper review but
  documented as NOT replicable with the bundled unpenalized learners:
  order-of-magnitude noise at (N=500, p=100) (SE ~4-10, EPV ~1.4-1.6 vs the
  solve_logit threshold 10, fitted out-of-fold clipping ~5-29% of rows -
  estimated propensities; true-propensity tail mass is only ~0.06%), and a
  fail-closed linear-outcome rank deficiency at (N=200, p=100) even under an
  oracle propensity (ridge/sieve fit there). TODO row narrowed accordingly
  (penalized propensity learner + p-robust outcome learner); the review
  gains the full §4.2 parameterizations, a ninth suspected-typo entry (the
  printed-but-unused beta_0, with the trend-cancellation note), and a Gaps
  entry for the paper's own regularity-condition quirks (Gaussian kernel vs
  Assumption 3.3; unbounded-index propensities vs a.s. strict overlap
  3.2(a) in BOTH §4.2 designs).
- REGISTRY: Case 2 checklist bullet updated + a standalone replication-scope
  Note (native learners stand in for kernel first stages; overlap quirk;
  §4.2.1 evidence). dr_scores test comment updated (parameterization now
  extracted; §4.2.2 replicated). CHANGELOG Added entry.

Verified: default lane + both existing suites green on Rust and pure-Python
backends; the new MC coverage class green on both (200 reps Rust / 22-rep
reduced band pure-Python); the seed-pinned recovery values reproduce the
review measurements exactly (att 2.7581/2.9054/2.5580, unadjusted contrast
4.008/3.978/3.617).
@github-actions

Copy link
Copy Markdown

🔁 AI review rerun (requested by @igerber)

Head SHA: 956389810cb6c3e661364b7017477d3bfe336c2a


Overall assessment

Looks good — no unmitigated P0/P1 findings.

Executive summary

  • No estimator, variance, weighting, assumptions, or defaults changed.
  • The §4.2.2 DGP and nuisance identities match the documented Chang design.
  • Learner substitution and strict-overlap limitations are explicitly documented.
  • §4.2.1 remains properly tracked in TODO.md.
  • Static parsing passed; runtime tests were unavailable because NumPy and pytest are not installed.

Methodology

  • Severity: P3 — informational
    • Impact: Fixtures validate the paper’s DGP using native learners, not its Gaussian-kernel first stages; the unbounded covariate also violates literal strict overlap.
    • Concrete fix: None required. Both limitations are documented at docs/methodology/REGISTRY.md:L3132.

The generator, propensity, outcome nuisance, and confounded contrast are correctly encoded at tests/test_methodology_dml_did.py:L700-L750 and asserted at tests/test_methodology_dml_did.py:L792-L838.

Code Quality

No findings. Unexpected learner, degeneracy, and inference warnings fail the fixtures at tests/test_methodology_dml_did.py:L753-L774.

Performance

No findings. The 200-replication coverage check is marked slow and backend-scaled.

Maintainability

No findings. DGP generation, warning validation, and unadjusted comparison are isolated helpers.

Tech Debt

  • Severity: P3 — tracked
    • Impact: The high-dimensional §4.2.1 design is not yet replicated.
    • Concrete fix: None required for this PR; required learner work is tracked at TODO.md:L81.

Security

No findings. No secrets, external inputs, or security-sensitive behavior were introduced.

Documentation/Tests

No findings. Documentation consistently describes the variance interpretation, learner substitution, overlap caveat, and replication scope. Both changed Python files pass AST parsing; runtime execution was unavailable due missing dependencies.

@igerber
igerber merged commit 7de6e27 into main Aug 30, 2026
29 checks passed
@igerber
igerber deleted the dml-s42-fixtures branch August 30, 2026 00:26
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