test: posterior shape-recovery merge gate for MC integrators (expensive_before_merging) - #31
Merged
Merged
Conversation
…ators Integrals are easy; posterior shape recovery is the strong requirement for production merges. Self-contained suite (runs against any branch, incl. rift_O4c): seeded random Gaussian mixtures across dimensions per RIFT-FinerNet multigauss_direct (Wagner et al), truth by exact rejection fair-draws, weighted-cloud read-back through the production _rvs API. Metrics: per-dim JS vs matched-n_ESS self-calibrating floor, mean pulls, width ratios, correlation recovery, lnZ bias. AV+GMM strict, NF+portfolio warn-only. Includes base-vs-candidate comparison tool for PR gating. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… gating) First standard-preset baseline showed all samplers legitimately starve on d=8 mixtures at production budgets (FinerNet high-D degradation), so absolute pass/fail is uninformative there. STARVED rows now gate only via base-vs-candidate comparison (healthy->starved = regression). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pointers in AGENTS.md, RIFT/integrators/TESTING.md (new, colocated with the code being edited), test/README.md, and test/integrators/README_benchmark.md so future agents/developers touching the integrators find the expensive_before_merging gate and its differential base-vs-candidate recipe. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Owner
Author
|
Auto-review completed the required posterior shape-recovery merge gate. I ran the standard CPU-only 96-run matrix on both the refreshed |
This was referenced Jul 22, 2026
oshaughnessy-junior
added a commit
that referenced
this pull request
Jul 23, 2026
…n_eff in the shape gate) The shape-recovery merge gate (PR #31) flagged a portfolio regression on my branch: ~13 of 20 portfolio rows lost n_eff vs base, several by 2-4x. It did not block (portfolio is warn-only, strict=AV,GMM) but PR #28 changes the portfolio DEFAULT path, so it needed attribution. Isolated on the gate's own targets, same checkout, one knob at a time: * never-freeze (my headline default): ratio 1.00 on every row -- NO effect on these targets. (It matters on the S250114ax freeze-out, not here.) My leading hypothesis was wrong. * plateau-aware _climbing revive: SOLE cause. plateau ON -> OFF reproduces gate base EXACTLY: d4_n1_s101 25.9 -> 53.5 (base 53.5) d4_n3_s202 29.1 -> 83.8 (base 83.8) d6_n1_s202 64.0 -> 102.1 (base 102.1) d6_n3_s202 7.2 -> 31.4 (base 31.4) d8_n1_s101 37.3 -> 61.9 (base 61.9) Mechanism: forcing updates of members the freeze schedule would have parked makes their proposals WORSE, not better -- the opposite of the intuition that motivated it. Fix: portfolio_plateau_revive now defaults False (base-equivalent default path); the behaviour stays available as an opt-in knob with the measurements recorded inline so nobody re-enables it blind. Method note: the first isolation attempt was INVALID -- it put the suite's test dir on sys.path but not the branch on PYTHONPATH, so it imported the INSTALLED RIFT (where the knob does not exist) and reported "no effect" with n_eff nowhere near the gate's. A valid isolation must reproduce the gate's absolute numbers; these do, row for row. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
oshaughnessy-junior
added a commit
that referenced
this pull request
Jul 23, 2026
…ment Gate (PR #31 requirement), base rift_O4d @4bac7444 vs this branch, both incl. #33, run on an idle node: COMPARE_EXIT=0, 0 blocking regressions, base and PR identical in aggregate (strict 8/8, warn-only 5/5, starved 45/45), 22 of 23 portfolio rows bitwise identical to base. The one remaining difference is mix_d2_n3_s303 (n_eff 736->517, bias -0.0060->-0.0064): the row where never-freeze actually engages. Both PASS comfortably, but it quantifies the trade -- never-freeze buys starvation-immunity and costs ~30% n_eff where freezing would have been harmless. Also hardens probe_portfolio_optin_flags.py to export CUDA_VISIBLE_DEVICES/OMP_NUM_THREADS and put the checkout on sys.path itself. Library-mode use of the suite does NOT inherit what run_shape_recovery.sh exports; without it you import the INSTALLED RIFT and get confident, meaningless numbers (this bit me once -- caught only because the absolute n_eff did not match the gate's). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Posterior shape-recovery merge gate for the MC integrators
Adds
test/expensive_before_merging/integrators/— the strong, slow validation suite run before confirming a merge into a production line (not per-commit CI). Motivation: the fast CI gate checks only the integral on one 3-D Gaussian; integrals are easy, while the recovered posterior shape (the weighted cloud CIP/fairdraws consume) can be confidently wrong with a perfect evidence. This suite already caught, in its first deployment: a GMM run with evidence correct to +0.009 nats but marginal JS = 0.29 and widths 2.8–3.8× too broad; the portfolio aggregation bias fixed by #26 (−2.7..−3.1 nats → ≤ +0.12, quantified); and the rift_O4c→rift_O4d GMM efficiency collapse (n_eff 3047→1 at d=6, bisected to an import-time cupy binding with silently swallowed refit failures).Contents
shape_recovery.py— self-contained harness (runs against ANY checkout via PYTHONPATH, incl. rift_O4c): seeded random Gaussian-mixture targets (d ∈ {2,4,6,8} × ncomp ∈ {1,3} × 3 seeds, Wishart covariances, FinerNet multigauss recipe), truth = 10⁶ exact rejection fair-draws, samplers exercised through the productionadd_parameter/integrate[_log]/_rvsAPI. Metrics: per-dim JS vs a self-calibrating matched-n_ESS floor, mean pulls, width ratios, correlation recovery, lnZ bias. Verdicts: PASS / FAIL / STARVED (starved = n_eff below testability; non-blocking absolutely, gates differentially).compare_shape_results.py— differential PR gate: PASS→FAIL/STARVED or metric-worsening on a strict sampler (default AV,GMM) blocks; fail-on-both is reported as pre-existing.run_shape_recovery.sh, pytest wrapper (RIFT_RUN_EXPENSIVE=1), READMEs with the merge workflow.AGENTS.mdsection,RIFT/integrators/TESTING.mdcolocated with the integrator sources, pointers intest/README.mdandtest/integrators/README_benchmark.md.Validation
Standard preset (~10 min/branch, CPU-only, ldas-pcdev11): rift_O4d base, PRs #26/#27/#28, rift_O4c back-check. Results, comparison tables, and the GMM-regression bisect provenance are archived in the RIFT_roboto_paper repo under
analyses/integrator_shape_gate/; methodology documented in the paper appendixap:shape_gate. First-deployment evidence on #26: #26 (comment)Notes
CUDA_VISIBLE_DEVICES=""): deterministic, and deliberately exercises the cupy-installed-but-no-GPU worker configuration that produced the silent GMM failure. The suite works around the GMM stack's module-level cupy selection via_force_cpu_modules(); the underlying no-device-probe bug is being fixed separately.SHAPE_JOBS=10-12,OMP_NUM_THREADS=1).🤖 Generated with Claude Code