Commit 25c364f
utils: enforce all-or-nothing NaN inference contract on degenerate bootstrap
CI review (R6) caught a new P0 in my R5 wild_bootstrap_se() fix:
the degenerate-bootstrap branches violated the all-or-nothing NaN
contract from feedback_bootstrap_nan_on_invalid_contract:
- n_valid == 0 returned p_value = 1.0 with se = NaN (split inference)
- valid_coefs.size == 1 returned a finite percentile CI from a single
draw alongside se = NaN
- t_stat_original was always finite (analytical), surfacing alongside
NaN bootstrap se when bootstrap was degenerate
Fix: when n_valid < 2 OR valid_coefs.size < 2, NaN-out the entire
inference quadruple (se, p_value, ci_lower, ci_upper) AND the
surfaced t_stat_original. The analytical t-stat from step 1 is still
computed for diagnostic use inside the helper but not propagated
to the user-facing result on a degenerate bootstrap — this prevents
the estimator wrapper from emitting an analytical t-stat alongside
NaN bootstrap fields, which would mix inference families on the
same coefficient.
New regression tests in tests/test_wild_bootstrap.py::
TestWildBootstrapDegenerateAllNaN:
- test_degenerate_n_valid_zero_returns_all_nan: monkeypatches
solve_ols so every bootstrap draw has singular vcov; asserts
ALL five user-surface fields are NaN.
- test_degenerate_single_valid_draw_returns_all_nan: forces exactly
one valid draw (n_valid == 1); asserts ALL five fields NaN — no
percentile CI from a single-point sample.
Both branches were previously not exercised by the analytical-design
tests, which is why the R5 fix passed but the R6 reviewer caught the
contract violation via code inspection.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 7f5df65 commit 25c364f
2 files changed
Lines changed: 281 additions & 234 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
624 | 624 | | |
625 | 625 | | |
626 | 626 | | |
627 | | - | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
628 | 637 | | |
629 | 638 | | |
630 | | - | |
631 | | - | |
632 | | - | |
633 | | - | |
634 | | - | |
635 | | - | |
636 | | - | |
637 | | - | |
638 | | - | |
639 | | - | |
640 | | - | |
641 | 639 | | |
642 | | - | |
643 | | - | |
644 | | - | |
645 | | - | |
646 | 640 | | |
647 | | - | |
648 | 641 | | |
649 | 642 | | |
650 | | - | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
651 | 649 | | |
652 | 650 | | |
| 651 | + | |
653 | 652 | | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
654 | 661 | | |
655 | 662 | | |
| 663 | + | |
656 | 664 | | |
657 | 665 | | |
658 | 666 | | |
659 | 667 | | |
660 | | - | |
| 668 | + | |
661 | 669 | | |
662 | 670 | | |
663 | 671 | | |
| |||
0 commit comments