Repository navigation
release: 4.0.0 - close the 4.0 cut window (item 10) - #886
Conversation
Bump __version__ / pyproject / rust/Cargo.toml / llms-full.txt / CITATION.cff
(version + date-released 2026-11-01) to 4.0.0, which closes the ledger's cut
window (cut_window 4.0 / cut_base 3.13.0 stay as the historical record; the
due gate is green at 4.0.0 with 94 removed / 43 done / 2 permanent shimmed
rows M-031, M-082). CHANGELOG.md gains the compiled `## [4.0.0] - 2026-11-01`
section from the 26 changelog.d fragments and the v3.13.0...v4.0.0 compare
link; the compiler's CATEGORIES order now leads with Breaking Changes /
Behavioral Changes (README mirror + order test extended), the pr1-conformance
fragment's LWDiD pvalue/ci bullet moved from `### Deprecated` to `### Breaking
Changes` (the properties are removed, not deprecated), and the cut-framing
fragment no longer claims a maint/3.13 branch was cut (none was - maintainer
decision 2026-10-18).
Prose flipped to present/past tense: docs/user_guide.rst ("upcoming 4.0"),
docs/migration-4.0.md (intro note - incl. the unwarned field breaks and the
numbers-move caveat for the df_convention / auto-cluster flips; the renames
intro; the 3.9 alias-diet sentence), ROADMAP.md (the shipped 4.0 program entry
replaced by the 4.1 event_study() front door), DEFERRED.md (Version-gated intro;
the migration-guide snippet-execution waiver's premise restated for both
directions of the mixed fences), .claude/memory.md (Results Objects block is the
4.0 contract), METHODOLOGY_REVIEW.md (three "will be removed" sentences about
params removed at 4.0), docs/troubleshooting.rst and REGISTRY.md (the static
TWFE time= alias raises since 4.0, M-083), diagnostic_report.py (comment: reading
a removed overall_* name raises AttributeError), tutorial 10_trop markdown (the
twostep/joint aliases are gone), tutorial 18 (stored warning path prefix
stripped), .claude/commands/bump-version.md (__init__ line number).
Spec docs/v4-design.md: status CLOSED at 4.0.0; forward-reference disclaimer,
companion-artifacts pointer and dated-addenda list amended; section 2 cut-window
paragraph marked spent (no maint/3.13 branch); phase-5 row and section 9 items 0
and 10 marked shipped; the 4.0-cut checklist records the deprecation grep re-run
(0 warning-emitting sites, 0 shim helper call sites, 0 `.. deprecated::`
directives, no module __getattr__; four stale prose sentences fixed here);
section 11 notes the window closed. Ledger header comments note the closure.
Tutorials re-executed on the Rust backend with the worktree kernel: 02 and 09
(the item-7a p-value/CI moves and the item-7b `Std. errors: ... G=` lines; point
estimates and SEs unchanged), 27 (the M-030 `post=` spelling in the practitioner
text; warning path prefixes normalized), 25 (its committed confidence-set /
in-time-placebo outputs were a stale capture: a probe at its own last commit,
3f79ff1 / #842, already prints the refreshed numbers on the Python backend, so
no 4.0 commit moved them). 01/04/05/07/11/13 have never carried outputs and are
nbmake-validated; 16_wooldridge_etwfe was refreshed at 8b; 32's Python-backend
bootstrap outputs are left as captured (backend-only difference). TODO.md's
tutorial re-execution row is closed.
Overall assessment: ✅ Looks goodNo actionable findings introduced by this diff. Executive summary
MethodologyNo findings. The refreshed inference follows the documented Code QualityNo findings. The compiler category order and README mirror agree. The extended test explicitly checks that breaking categories lead. PerformanceNo findings. No estimator execution or computational workload changed. MaintainabilityNo findings. Release metadata, migration guidance, and lifecycle documentation are consistent. Tech DebtNo findings. The migration-guide execution limitation remains explicitly tracked in SecurityNo findings in the changed content. Documentation/TestsNo findings. Fragment removal follows the documented release-compilation convention; Validation passed for changelog checking, idempotent release verification, version consistency, notebook JSON parsing, Python 3.9 syntax compatibility, and diff whitespace. Full pytest and notebook execution remain unverified in this environment. |
Summary
__version__,pyproject.toml,rust/Cargo.toml,diff_diff/guides/llms-full.txtandCITATION.cff(version+date-released: 2026-11-01) move to 4.0.0, which closes the ledger's cut window (cut_window: "4.0"/cut_base: "3.13.0"stay as the historical record per spec section 11). The due gate is green at 4.0.0: 94removed/ 43done/ 2 permanentshimmedrows (M-031, M-082 - thetimename survives as the calendar column,removed_in: null). No ledger row changes.CHANGELOG.mdgains## [4.0.0] - 2026-11-01from the 26changelog.d/fragments plus thev3.13.0...v4.0.0compare link;changelog.d/holds onlyREADME.md. Three pre-compile fixes: the compiler'sCATEGORIESorder now leads withBreaking Changes/Behavioral Changes(a major release reads breakage first;changelog.d/README.mdmirror updated andtest_category_order_and_contiguous_joinextended to pin the new placement - the old test passed under both orders), the pr1-conformance fragment'sLWDiDResults.pvalue/.cibullet moved from### Deprecatedto### Breaking Changes(the properties are removed at 4.0, not deprecated), and the cut-framing fragment's "Amaint/3.13branch is cut" sentence corrected (none was - maintainer decision 2026-10-18). Two compiled-section wording touch-ups (maintainer decision,stayed 3.13.0).docs/user_guide.rst("upcoming 4.0" x2);docs/migration-4.0.md(title kept; the intro note now states the release, the surfaces that break without a warned release, and that thedf_convention/ SpilloverDiD auto-cluster flips move the NUMBERS of warning-free code with §6 as the recipe; the renames intro; the 3.9 alias-diet sentence);ROADMAP.md(the shipped 4.0 program entry replaced by the 4.1event_study()comparison front door);DEFERRED.md(Version-gated intro; the migration-guide snippet-execution waiver's premise restated - the fences are mixed in both directions, so the waiver stands); the trackedmemory.mdnotes file (Results Objects block is the 4.0 contract);METHODOLOGY_REVIEW.md(three "will be removed" sentences about params already removed);docs/troubleshooting.rst+docs/methodology/REGISTRY.md(static TWFEtime=raises since 4.0, M-083);diff_diff/diagnostic_report.pycomment (reading a removedoverall_*name raisesAttributeError); tutorial 10 markdown (thetwostep/jointaliases are gone); tutorial 18 (stored warning path prefix stripped); thebump-versioncommand doc line number.docs/v4-design.md(dated amendments, history kept): statusCLOSED at 4.0.0; forward-reference disclaimer (phases 1-5 shipped; the phase-6 front door is the one described-but-unbuilt surface); companion-artifacts pointer follows the ROADMAP rename; dated-addenda list; section 2 cut-window paragraph marked spent with the maint/3.13 decision; phase-5 row and section 9 items 0 / 10 marked shipped (item 10 carries the corrected tutorial facts); the 4.0-cut checklist records the deprecation grep re-run: 0 warning-emittingFutureWarning/DeprecationWarningsites indiff_diff/, 0 warning-emitting_deprecation.pyhelper call sites, 0 Sphinx.. deprecated::directives, no module__getattr__, four stale prose sentences fixed in this PR; section 11 notes the closure. Ledger header comments note the closure (keys unchanged).02_staggered_didand09_real_world_examplescarried committed outputs; both re-executed - movers are exactly the item-7a p-value/CI shifts and the item-7bStd. errors: CR1 cluster-robust at ..., G=lines (02 cells 38/39/41/42: e.g. SunAbraham ATT CI[3.2961, 3.6566]->[3.2942, 3.6585], lead -5 p 0.0537 -> 0.0562; 09 cell 27: Castle Doctrine SunAbraham p 0.0250 -> 0.0290, CI[0.0597, 0.8853]->[0.0504, 0.8946]); point estimates and SEs unchanged; no markdown restates a moved number.01/04/05/07/11/13have never carried outputs (none at v3.13.0 either;nbsphinx_execute = "never") and stay output-free, nbmake-validated.16_wooldridge_etwfewas refreshed at 8b. Movers outside the list:27_cic_distributional_effects(cell 29 practitioner texttime='post'->post='post', the M-030 rename; warning-cell line numbers/prefix normalized) re-executed;25_synthetic_control_policyre-executed (cell 17 constant-effect 90% confidence set[3.47, 20.45]->[3.39, 31.50], cell 20 in-time placebo at 350.547->0.777) - a probe running the notebook's setup + those two cells against a scratch checkout of its own last commit (3f79ff1c, fix(synthetic_control): solve the donor weights exactly by non-negative least squares #842, Python backend) already prints the refreshed numbers, so the committed outputs were a stale capture, not a 4.0 code move;32_dml_did's Python-backend bootstrap outputs are left as captured (a Rust-vs-Python backend difference only, not a 4.0 mover; its drift test guards it).TODO.md's tutorial re-execution row is closed.Methodology references (required if estimator / math changes)
diff_diff/diagnostic_report.py).Validation
tests/test_changelog_fragments.py::test_category_order_and_contiguous_joinextended (Breaking Changes < Behavioral Changes < Added < Fixed < Internal). Green locally at__version__ = 4.0.0:test_v4_matrix,test_naming_guard,test_changelog_fragments,test_tracking_files,test_docs_ia,test_guides,test_doc_deps_integrity,test_v4_diagnostic_family_docs,test_practitioner(930 passed, 29 skipped);tests/test_t25_synthetic_control_policy_drift.py+tests/test_t27_cic_distributional_effects_drift.py;changelog_compile.py checkOK; black / ruff on the edited Python;mypy --python-version 3.12 diff_diffclean (111 files); Python 3.9 byte-compile of the edited test and script. Sphinx-Wbuild green with no autosummary drift.pytest --nbmake --nbmake-kernel=diff-diff-v-fourgreen on 01, 02, 04, 05, 07, 09, 11, 13, 25, 27 (the worktree kernel is required - the user-levelpython3kernel points at a sibling checkout). Cell-level output diffs of 02 / 09 / 25 / 27 are listed in the Summary; every other cell is byte-identical apart from re-rendered figure bytes andipykernel_NNNNtemp-path churn.Security / privacy
Changelog
CHANGELOG.md[4.0.0].Post-merge release runbook
git fetch origin && git tag v4.0.0 <merge sha> && git push origin v4.0.0.gh workflow run release-build-check.yml --ref v4.0.0, then confirm green AND that it built the tag:gh run list --workflow release-build-check.yml --event workflow_dispatch -L 1 --json headSha,status,conclusion. If it fails, delete the tag (git push origin :refs/tags/v4.0.0) before fixing - no Release exists yet.gh release create v4.0.0 --title "diff-diff 4.0.0" --notes-file <the [4.0.0] section of CHANGELOG.md>- publishing the Release triggerspublish.yml(wheels + sdist -> PyPI via trusted publishing; Zenodo mints the versioned DOI). RTD buildsstablefrom the tag.CHANGELOG.md## [4.0.0] - DATEandCITATION.cffdate-releasedtogether (the compiler's exit-4 re-run path reads the header date).