refactor(spillover): route stage-1 FE through shared _iterative_fe_solve#642
refactor(spillover): route stage-1 FE through shared _iterative_fe_solve#642igerber wants to merge 1 commit into
Conversation
Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
MethodologyFinding: P3 informational — documented solver-budget behavior change
No P0/P1 methodology defects found. The source-material contract is preserved: Butts’ staggered spillover estimator estimates stage-1 FE on untreated-and-unexposed observations, and Gardner’s two-stage framework identifies group/time effects from untreated observations before residualized stage 2. The PR only changes the numerical engine used for that same alternating FE solve. Code QualityFinding: None. The wrapper remains narrow and preserves Spillover-specific validation before delegating to PerformanceFinding: None. The shared helper uses per-sweep MaintainabilityFinding: None. Removing the duplicate FE loop reduces maintenance surface. The TODO row for migrating Tech DebtFinding: P3 informational — tracked deferred item completed
SecurityFinding: None. No secrets, unsafe I/O, network access, or security-sensitive behavior changed. Documentation/TestsFinding: None requiring changes. Documentation was updated in Tests not run: |
4c4306d to
438478a
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
MethodologyFinding: P3 informational — documented SpilloverDiD solver-budget change
Finding: P3 informational — Callaway no-covariate IPW structural parity remains deferred/tracked
Code QualityFinding: None. The PerformanceFinding: None. Routing through MaintainabilityFinding: P3 informational — IPW aggregation fixture regeneration is intentionally deferred
Tech DebtFinding: P3 informational — completed spillover FE-solver TODO removed
SecurityFinding: None. No secrets, unsafe I/O, network calls, or security-sensitive behavior changed. Documentation/TestsFinding: P3 informational — targeted tests not run locally
|
438478a to
1a68d0b
Compare
_iterative_fe_subset becomes a thin Butts-subsample wrapper over diff_diff.utils._iterative_fe_solve (the shared bincount Gauss-Seidel engine ImputationDiD/TwoStageDiD already use), taking the library's FE-solver copy count from 2 to 1. The wrapper keeps the SpilloverDiD front door (empty-Omega_0 / empty positive-weight-Omega_0 ValueError gates + subsample extraction); the shared engine owns the iteration, the zero-weight NaN-FE convention, and warn_if_not_converged (labelled 'SpilloverDiD stage-1 FE (Butts Omega_0 subsample)', replacing the caller-side warning). Per sweep the shared engine computes identical group means and convergence metric, so converged fits are bit-identical; max_iter aligned 100 -> 10,000 per the shared fixest/pyfixest convention with a REGISTRY note (tol=1e-10 unchanged). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1a68d0b to
01f4c72
Compare
|
🔁 AI review rerun (requested by @igerber) Head SHA: Overall Assessment✅ Looks good — no unmitigated P0/P1 findings. Executive Summary
MethodologyFinding: P3 informational — documented SpilloverDiD FE budget/routing change
Code QualityFinding: None. The PerformanceFinding: None. The shared solver removes the duplicate local FE loop. The longer iteration budget can increase runtime only for hard non-convergent cases, and that behavior is documented as intentional. MaintainabilityFinding: P3 informational — shared-helper docstring is slightly stale
Tech DebtFinding: None. The completed TODO row for migrating SecurityFinding: None. No secrets, unsafe I/O, network behavior, or security-sensitive code paths changed. Documentation/TestsFinding: P3 informational — tests not executable in this review environment
|
Summary
spillover._iterative_fe_subsetbecomes a thin Butts-subsample wrapper overdiff_diff.utils._iterative_fe_solve— the shared bincount Gauss-Seidel engine ImputationDiD/TwoStageDiD already route through — taking the library's FE-solver copy count from 2 to 1 (the TODO row's goal).ValueErrorgates and the subsample extraction. The shared engine owns the iteration, the zero-weight/positive-weight NaN-FE convention (identical contract, per the existing cross-references in REGISTRY), and thewarn_if_not_convergednon-convergenceUserWarning— now labelled "SpilloverDiD stage-1 FE (Butts Omega_0 subsample)", replacing the caller-side warning.max_iteraligned from the historical local cap of 100 to the shared 10,000 convention (the fixest/pyfixest budget; the option the TODO row offered "with a REGISTRY note") — fits that previously exhausted 100 sweeps and warned may now converge instead (strictly more accurate FE;tol=1e-10unchanged). New REGISTRY SpilloverDiD Note documents the routing and the budget alignment.Methodology references (required if estimator / math changes)
Validation
tests/test_spillover.py(319 tests incl. golden/parity/survey suites) andtests/test_methodology_two_stage.pypass unchanged, pinning converged-fit bit-identity.Security / privacy
Generated with Claude Code