Skip to content

release: 4.0.0 - close the 4.0 cut window (item 10) - #886

Merged
igerber merged 1 commit into
mainfrom
feat/v4-pr10-release-4-0-0
Nov 2, 2026
Merged

igerber merged 1 commit into
mainfrom
feat/v4-pr10-release-4-0-0

Conversation

@igerber

@igerber igerber commented Nov 1, 2026

Copy link
Copy Markdown
Owner

Summary

  • Item 10 of the 4.0 cut - the 4.0.0 release. __version__, pyproject.toml, rust/Cargo.toml, diff_diff/guides/llms-full.txt and CITATION.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: 94 removed / 43 done / 2 permanent shimmed rows (M-031, M-082 - the time name survives as the calendar column, removed_in: null). No ledger row changes.
  • Changelog compiled. CHANGELOG.md gains ## [4.0.0] - 2026-11-01 from the 26 changelog.d/ fragments plus the v3.13.0...v4.0.0 compare link; changelog.d/ holds only README.md. Three pre-compile fixes: the compiler's CATEGORIES order now leads with Breaking Changes / Behavioral Changes (a major release reads breakage first; changelog.d/README.md mirror updated and test_category_order_and_contiguous_join extended to pin the new placement - the old test passed under both orders), the pr1-conformance fragment's LWDiDResults.pvalue/.ci bullet moved from ### Deprecated to ### Breaking Changes (the properties are removed at 4.0, not deprecated), and the cut-framing fragment's "A maint/3.13 branch is cut" sentence corrected (none was - maintainer decision 2026-10-18). Two compiled-section wording touch-ups (maintainer decision, stayed 3.13.0).
  • Prose flipped to present/past tense. 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 the df_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.1 event_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 tracked memory.md notes 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 TWFE time= raises since 4.0, M-083); diff_diff/diagnostic_report.py comment (reading a removed overall_* name raises AttributeError); tutorial 10 markdown (the twostep/joint aliases are gone); tutorial 18 (stored warning path prefix stripped); the bump-version command doc line number.
  • Spec docs/v4-design.md (dated amendments, history kept): status CLOSED 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-emitting FutureWarning/DeprecationWarning sites in diff_diff/, 0 warning-emitting _deprecation.py helper 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).
  • Tutorials (Rust backend, worktree kernel). Of the eight the TODO row listed, only 02_staggered_did and 09_real_world_examples carried committed outputs; both re-executed - movers are exactly the item-7a p-value/CI shifts and the item-7b Std. 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/13 have never carried outputs (none at v3.13.0 either; nbsphinx_execute = "never") and stay output-free, nbmake-validated. 16_wooldridge_etwfe was refreshed at 8b. Movers outside the list: 27_cic_distributional_effects (cell 29 practitioner text time='post' -> post='post', the M-030 rename; warning-cell line numbers/prefix normalized) re-executed; 25_synthetic_control_policy re-executed (cell 17 constant-effect 90% confidence set [3.47, 20.45] -> [3.39, 31.50], cell 20 in-time placebo at 35 0.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)

  • Method name(s): N/A - no estimator or math changes (one comment edit in diff_diff/diagnostic_report.py).
  • Paper / source link(s): N/A
  • Any intentional deviations from the source (and why): None

Validation

  • Tests added/updated: tests/test_changelog_fragments.py::test_category_order_and_contiguous_join extended (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 check OK; black / ruff on the edited Python; mypy --python-version 3.12 diff_diff clean (111 files); Python 3.9 byte-compile of the edited test and script. Sphinx -W build green with no autosummary drift.
  • Backtest / simulation / notebook evidence (if applicable): pytest --nbmake --nbmake-kernel=diff-diff-v-four green on 01, 02, 04, 05, 07, 09, 11, 13, 25, 27 (the worktree kernel is required - the user-level python3 kernel 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 and ipykernel_NNNN temp-path churn.

Security / privacy

  • Confirm no secrets/PII in this PR: Yes

Changelog

  • changelog.d/ fragment added (or N/A - no user-visible change): N/A - this PR compiles the fragments into CHANGELOG.md [4.0.0].

Post-merge release runbook

  1. Tag the merge commit so the rehearsal is pinned to the release SHA: git fetch origin && git tag v4.0.0 <merge sha> && git push origin v4.0.0.
  2. Full-matrix build rehearsal (build-only; PR runs build the manylinux leg only): 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.
  3. 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 triggers publish.yml (wheels + sdist -> PyPI via trusted publishing; Zenodo mints the versioned DOI). RTD builds stable from the tag.
  4. If the tag lands on a day other than 2026-11-01, say so: a one-line follow-up aligns CHANGELOG.md ## [4.0.0] - DATE and CITATION.cff date-released together (the compiler's exit-4 re-run path reads the header date).

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.
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown

Overall assessment: ✅ Looks good

No actionable findings introduced by this diff.

Executive summary

  • No estimator equations, weighting, variance calculations, or identification checks changed.
  • All five version declarations agree on 4.0.0; ledger counts match the release description.
  • The release section incorporates all 26 fragments, and historical changelog content remains unchanged.
  • Independent Student-t checks agree with the refreshed TWFE and Sun–Abraham outputs.
  • Full tests and notebook execution could not be repeated because NumPy and pytest are unavailable.

Methodology

No findings. The refreshed inference follows the documented G−1 convention in docs/methodology/REGISTRY.md:L633-L667. This PR introduces no new methodological deviation or inference code path.

Code Quality

No findings. The compiler category order and README mirror agree. The extended test explicitly checks that breaking categories lead.

Performance

No findings. No estimator execution or computational workload changed.

Maintainability

No findings. Release metadata, migration guidance, and lifecycle documentation are consistent.

Tech Debt

No findings. The migration-guide execution limitation remains explicitly tracked in DEFERRED.md.

Security

No findings in the changed content.

Documentation/Tests

No findings. Fragment removal follows the documented release-compilation convention; [Unreleased] remains pointer-only.

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.

@igerber igerber added the ready-for-ci Triggers CI test workflows label Nov 2, 2026
@igerber
igerber merged commit c5280ae into main Nov 2, 2026
53 of 54 checks passed
@igerber
igerber deleted the feat/v4-pr10-release-4-0-0 branch November 2, 2026 10:20
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