feat(rdd): RDPlot - optimal data-driven RD plots (CCT 2015, rdplot parity)#695
Conversation
Overall Assessment✅ Looks good — no unmitigated P0/P1 findings identified. Executive Summary
MethodologyNo unmitigated findings. P3 informational: Documented RDPlot deviations/quirks reviewed. Code QualityNo findings. The core numerical paths are localized in PerformanceNo blocking findings. P3 informational: Very large manual MaintainabilityNo findings. The new public API is exported in Tech DebtNo untracked blocking debt found. Documented scope seams, including no sampling weights, no SecurityNo findings. I found no secrets or unsafe execution paths in the added RDPlot implementation, tests, benchmark generator, or golden data. Documentation/TestsNo blocking findings. Coverage is broad: golden R parity in Verification not run: |
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings identified. Executive Summary
MethodologyNo unmitigated findings. Severity: P3 informational Code QualityNo findings. Constructor validation and parameter propagation are covered in PerformanceSeverity: P3 informational MaintainabilityNo findings. The implementation is localized in Tech DebtNo untracked blocking debt found. Documented scope seams include no sampling weights, no SecurityNo findings. I found no secrets, unsafe execution paths, or new security-sensitive behavior in the changed implementation, docs, tests, benchmark generator, or golden data. Documentation/TestsNo blocking findings. Coverage is broad: R golden parity in Verification not run: |
…rity) PR-B of the rdplot arc (paper review merged in #694). New RDPlot class + RDPlotResult in diff_diff/rdplot.py, parity-targeting rdplot() in CRAN rdrobust 4.0.0: all 8 binselect bin-count selectors (ES/QS x IMSE-optimal/mimicking-variance x spacings/polynomial-regression), manual nbins/scale/h/support/ci, masspoints detection with the spacings-to-pr adjust remap, per-bin means/SEs/CIs (vars_bins, R column names), 500-point-per-side global-fit curves (vars_poly), implied scale + Supplement S.1 WIMSE weights in summary(), covariate-adjusted plots reusing the #691 partialled-gamma machinery, and an optional lazy matplotlib RDPlotResult.plot() (matplotlib not a dependency). Golden parity on 24 configs (benchmarks/R/generate_rdplot_golden.R -> rdplot_golden.json) incl. the vendored Senate data; supplement Figures SA-1/SA-2 selector outputs asserted as JSON-independent paper anchors. R quirks replicated and REGISTRY-documented (left-edge slot reflection under empty bins, qs+nbins label, Inf J_IMSE on zero-variance sides, negative-sigma2 floor, k=4->3->2 raises-only fallback ladder, QS type-7 cutpoints). Documented deviations/defensive guards: fractional/pair scale takes CCT 2015 Eq 2's ceiling (R crashes there), missing-row and discrete-outcome warnings, zero-effective-h / single-support-point / tiny-side clear errors, covariate-name validation shared with the estimator. Docs sweep: REGISTRY RDPlot section, api rst, references, llms.txt/llms-full.txt, README one-liner, doc-deps entry, CHANGELOG. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VwhFMnFQGBumYfwbeQaUjm
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall AssessmentExecutive Summary
MethodologySeverity: P1 [Newly identified] Severity: P3 informational Code QualityNo additional findings. Constructor validation and parameter propagation appear complete through PerformanceSeverity: P3 informational MaintainabilityNo findings. The implementation is localized in Tech DebtNo untracked blocking debt found. The documented RDPlot scope seams are registry-tracked. SecurityNo findings. I did not find secret-like tokens in the changed RDPlot implementation, tests, benchmark generator, docs, or golden fixture. Documentation/TestsSeverity: P3 informational Path to Approval
|
…sides np.var of a constant 0.7 vector is ~1.3e-32 (single-pass mean roundoff) while R's two-pass var() is exactly 0, so the var==0 rescue was skipped for constant non-representable-float outcomes and the resulting Inf J_MV crashed bin construction on a zero jump. Route the side variances through the port's _var0 exact-constancy helper (the R semantics already ported for the fuzzy identification stop), reproducing R's J=1 rescue, its Inf J_IMSE / NaN J_MV echoes, and the variability warning. Regression test with a constant-0.7 side added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VwhFMnFQGBumYfwbeQaUjm
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — the prior P1 finding is resolved, and I found no unmitigated P0/P1 issues. Executive Summary
MethodologySeverity: P3 informational Severity: P3 informational Code QualityNo findings. Constructor validation, PerformanceSeverity: P3 informational MaintainabilityNo findings. The implementation is localized in Tech DebtNo untracked blocking tech debt found. The documented RDPlot scope seams are registry-tracked. SecurityNo findings. I scanned the changed files for common secret/token patterns and found no relevant matches. Documentation/TestsSeverity: P3 informational |
Summary
RDPlotclass +RDPlotResult(diff_diff/rdplot.py), the CCT 2015 exploratory RD-plot diagnostic with end-to-end parity againstrdplot()in CRAN rdrobust 4.0.0 (same sha-pinned tarball as the estimator port).binselectbin-count selectors ({evenly, quantile spaced} x {IMSE-optimal, mimicking variance} x {spacings, polynomial-regression variance estimators}), manualnbins/scale/h/support/ci, masspoints detection with the spacings-to-pradjust remap, per-bin means/SEs/CIs (vars_binswith R's column names), 500-point-per-side global-fit curves, and implied-scale + Supplement-S.1 WIMSE weights insummary()(matching R'ssummary.rdplot).fit(..., covariates=...), R'scovs=withcovs_eval="mean") reuse the feat(rdd): covariate-adjusted RD - covariates= on fit() with rdrobust 4.0.0 parity (CCFT 2019) #691 partialled-gamma machinery including the collinearity pipeline, degenerate-adjustment guards, and the shared covariate-name validation contract.RDPlotResult.plot(ax=...)(matplotlib is NOT a dependency; the numbers are the parity surface).benchmarks/R/generate_rdplot_golden.R->benchmarks/data/rdplot_golden.json) incl. the vendored Senate data; the paper supplement's own Figure SA-1/SA-2 selector outputs (esmv 15/35, es 8/9, qs 21/16, qsmv 28/49) are asserted as JSON-independent anchors.RDPlotsection (lifted from the merged docs: add rdplot paper review (CCT 2015 JASA) #694 review per its CI note), api rst, references.rst, llms.txt + llms-full.txt, README Diagnostics one-liner, doc-deps.yaml entry, CHANGELOG[Unreleased].Methodology references (required if estimator / math changes)
RDPlot(RD plot bin-count selection diagnostic; NOT a treatment-effect estimator - no inference surface beyond per-bin display CIs)rdplot.R.scaleproducts take CCT 2015 Eq 2's ceiling (R 4.0.0 crashes there by accident: vector-indexing row mismatch / vectorized-if error on R >= 4.2); missing-row and discrete-outcome (spacings-selector) warnings where R is silent; clear errors for zero-effective-h, single-support-point, and near-empty sides where R degenerates opaquely; R's unconditional covsmessage()moved to the docstring. R quirks REPLICATED and documented: left-side bin-edge slot reflection under empty bins,qs+nbins"manually evenly spaced" label,InfJ_IMSEon zero-variance sides, negative-variance floor, QS type-7 cutpoints (R itself deviates from the paper's inf-form inverse there).Validation
tests/test_rdplot.py(59 tests: 24-config golden parity at rtol=1e-9, paper anchors, R-quirk locks, deviation locks, API contracts incl. transactional set_params and the matplotlib ImportError path; golden suite skips if the JSON is absent)Security / privacy
🤖 Generated with Claude Code
https://claude.ai/code/session_01VwhFMnFQGBumYfwbeQaUjm