Skip to content

docs(v4): 4.0-cut framing - cut-window gate, ledger/spec refresh, M-080 re-scope - #854

Merged
igerber merged 1 commit into
mainfrom
docs/v4-cut-framing
Oct 18, 2026
Merged

igerber merged 1 commit into
mainfrom
docs/v4-cut-framing

Conversation

@igerber

@igerber igerber commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • First PR of the 4.0 cut (at v3.13.0). Re-syncs docs/v4-design.md and the deprecation ledger with the library as shipped since 3.9 and makes the enforcement gate admit an incremental removal program. No estimator behaviour changes; the two diff_diff/ edits are docstrings.
  • Cut window. The ledger header declares cut_window: "4.0" / cut_base: "3.13.0". tests/test_v4_matrix.py parses the header (half-declared or malformed headers fail a dedicated test), relaxes ONLY the early-removal guard for rows scheduled at 4.0, refuses any other version bump while early-terminal rows exist (minor and patch cases pinned), and keeps due enforcement unchanged (the "window does not hide overdue" case). __version__ stays 3.13.0 until the release PR; 3.13.x patches come from a maint/3.13 branch cut at v3.13.0 before this merges (spec section 2).
  • M-008 (DIFF_DIFF_SOLVE_OLS_FASTPATH default) flipped to done, decided_default: off: evaluated, kept off (no soak telemetry ever existed). Naming-guard fixture becomes the terminal-exempt fixture.
  • M-080 re-scoped to the measured roster: static TwoWayFixedEffects already auto-clusters at unit, so the row's premise was stale. SpilloverDiD is the one estimator whose default SE moves at 4.0; cluster=False becomes the explicit off-switch where clustering is a choice (accepted no-op on by-construction estimators and ImputationDiD/TwoStageDiD, rejected by StackedDiD); by-construction estimators keep no auto-cluster metadata by decision. New "Default clustering roster" section in docs/methodology/variance-conventions.md; REGISTRY **Note:** lines on SpilloverDiD, StackedDiD, ImputationDiD, TwoStageDiD, DMLDiD (edited in place), DurationDiD.
  • New row M-150: WooldridgeDiDResults.to_dataframe(level="event") gets its own locator (twin of M-136; it previously rode M-086's notes). M-091 roster records the four later-born Diagnostic containers; M-050 code_refs record that diff_diff/_deprecation.py survives 4.0 as 5.0-window infrastructure; M-045/M-115 name the legacy-CR1 remap branches their removal deletes. The id snapshot and ROW_COUNT_FLOOR now include M-148/M-149 (shipped by [Bug]: SyntheticControl's Frank-Wolfe stops on its budget at the default inner_max_iter; in_space_placebo() then fails closed or drops placebos on 33-40 of 40 panels #838 without extending them) and M-150: 132 rows.
  • Spec: roster 27 -> 24 (LWDiD/DMLDiD/DurationDiD added to section 3.1), TWFE-weights and DurationDiD pretest containers added to the diagnostic family, section 9 gains the ten-PR "4.0 cut sequence", section 11 gains the cut-window rule, section 7 records the M-080 re-scope and M-008 decision.
  • Migration guide: M-150 appendix row (111 rows), M-080 appendix row / orientation row / inference bullet rewritten to the measured roster, new "Estimators added after 3.9" paragraph, M-008 pending-decision paragraph resolved.

Methodology references (required if estimator / math changes)

  • Method name(s): N/A - no methodology changes (docstring edits only in diff_diff/; docs/methodology/ edits record clustering-policy decisions, no equations change)
  • Paper / source link(s): N/A
  • Any intentional deviations from the source (and why): None. The cluster=False semantics per estimator are recorded as REGISTRY **Note:** decisions (SpilloverDiD, StackedDiD, ImputationDiD, TwoStageDiD, DMLDiD, DurationDiD).

Validation

  • Tests added/updated: tests/test_v4_matrix.py (header parser, test_cut_window_semantics x9, test_parse_header_cases x6, header well-formedness and cut-window declaration tests, snapshot 132), tests/test_naming_guard.py (M-008 terminal-exempt fixture). Verified: collect_due_problems at 3.13.0 / 3.14.0 / 4.0.0 reports 0 / 1 / 118 problems (109 distinct ids) with the window declared.
  • Backtest / simulation / notebook evidence (if applicable): N/A. The M-080 roster was measured by execution at v3.13.0 (50 units x 8 periods; default vs cluster="unit" SEs per estimator) and is tabulated in docs/methodology/variance-conventions.md.

Security / privacy

  • Confirm no secrets/PII in this PR: Yes

Changelog

  • changelog.d/ fragment added (or N/A - no user-visible change): Yes - changelog.d/20261018-v4-cut-framing.md

…80 re-scope

First PR of the 4.0 cut (at v3.13.0). Re-syncs docs/v4-design.md and the
deprecation ledger with the library as shipped since 3.9, and makes the
enforcement gate admit an incremental removal program.

- Ledger header declares the cut window (cut_window "4.0", cut_base
  "3.13.0"); tests/test_v4_matrix.py parses it, relaxes only the
  early-removal guard for 4.0-scheduled rows, refuses any other version bump
  while early-terminal rows exist, and keeps due enforcement unchanged
  (new parametrized cut-window and header-parser tests).
- M-008 (DIFF_DIFF_SOLVE_OLS_FASTPATH default) decided: evaluated, kept off.
- M-080 (auto-cluster policy) re-scoped to the measured roster: static TWFE
  already auto-clusters; SpilloverDiD is the one default that moves;
  cluster=False becomes the explicit off-switch where clustering is a choice
  (no-op on by-construction estimators, rejected by StackedDiD);
  by-construction estimators keep no auto-cluster metadata
  (variance-conventions roster + REGISTRY Notes on SpilloverDiD/StackedDiD/
  ImputationDiD/TwoStageDiD/DMLDiD/DurationDiD).
- New row M-150 (WooldridgeDiDResults.to_dataframe level "event", twin of
  M-136); M-091/M-050/M-045/M-115 code_refs and notes amended; id snapshot
  and ROW_COUNT_FLOOR repaired to include M-148/M-149 (132 rows).
- Spec: roster 27 -> 24 (LWDiD/DMLDiD/DurationDiD), diagnostic-family
  additions, section 9 "4.0 cut sequence" (storage flip before the DDD
  container unification), section 11 cut-window rule.
- Migration guide: M-150 appendix row, M-080 row/orientation/inference
  bullet rewritten, "Estimators added after 3.9" paragraph, M-008 decided.
- Naming-guard M-008 fixture becomes the terminal-exempt fixture.
@github-actions

Copy link
Copy Markdown

Overall assessment: ✅ Looks good

No unmitigated P0/P1 findings.

Executive summary

  • Runtime changes are limited to docstrings; estimator calculations and inference remain unchanged.
  • The cut window preserves due enforcement and rejects intermediate patch/minor bumps.
  • Clustering exceptions are explicitly documented in Registry Notes.
  • Direct execution passed 21 parser/gate cases, ledger validation, migration parity, and phase-table checks.
  • Changelog validation passed. Full pytest execution was unavailable because pytest is not installed.

Methodology

  • P3 — Informational: documented clustering policies. The affected documentation covers SpilloverDiD, ImputationDiD, TwoStageDiD, StackedDiD, DMLDiD, and DurationDiD. Cross-checking the Registry, implementation defaults, and repository paper reviews found no undocumented methodology mismatch. In particular, the planned SpilloverDiD default follows Butts’s unit-clustering recommendation.
    • Location: docs/methodology/variance-conventions.md:L182-L227; docs/methodology/REGISTRY.md:L6864-L6869.
    • Impact: The no-op/rejection exceptions and metadata decisions are documented policies; this PR changes no statistical output.
    • Concrete fix: None required.

Code Quality

No findings. The parser reports malformed headers, and the gate retains enforcement outside the declared cut window.

Performance

No findings. No estimator execution paths change.

Maintainability

No findings. The M-150 locator, immutable ID snapshot, migration appendix, and phase-table references agree.

Tech Debt

  • P3 — Informational: fast-path reevaluation remains tracked.
    • Location: TODO.md:L83.
    • Impact: M-008 records a completed “kept off” decision while preserving the evidence requirements for a future default change.
    • Concrete fix: None required; tracked in TODO.md.

Security

No findings in the changed code or documentation.

Documentation/Tests

No findings requiring changes. The changelog fragment follows the repository convention.

Validation confirmed 132 schema-valid ledger rows, exact coverage of 111 migration appendix rows, reference existence, and the reported release-gate counts. All changed Python files compiled successfully in memory. Full pytest integration remains unverified in this environment.

@igerber igerber added the ready-for-ci Triggers CI test workflows label Oct 18, 2026
@igerber
igerber merged commit 4037712 into main Oct 18, 2026
39 of 40 checks passed
@igerber
igerber deleted the docs/v4-cut-framing branch October 18, 2026 14:54
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