fix(strict): carry the eager walk's validated capacities into the traced refresh - #333
Merged
Merged
Conversation
…ced refresh The fused strict_run_v2 lane rebuilt its interaction lists inside the compiled velocity-Verlet scan with the preset traversal capacities (at N=200k: pair queue 65536, 256 neighbours per leaf). Eagerly those caps are irrelevant -- yggdrax's retry ladder grows them until the walk fits -- but under jit the overflow flags are tracers, the ladder has one attempt, and yggdrax returns the truncated result. Neighbour rows of up to 781 were cut to 256 (theta 1.0) or 128 (theta 0.6, the queue overflowed too), 85 % of the near-field entries vanished, and every step after the first carried a wrong force: 5.8 % relative L2 at theta 1.0, ~60 % at theta 0.6. fallback_count stayed 0 and no diagnostic fired. Fix: the strict streamed builder now passes a retry_logger to catch the ladder's success queue and reports the capacities it ran with plus what it observed (longest row, far-pair count); the eager prepare stores that on the engine, and the traced refresh raises its caps to cover it with headroom (neighbours and far pairs to pow2(1.5x observed), queue to pow2(2x ladder)). The scan's capacity_ok carry additionally fails when a refreshed row reaches the traced neighbour cap or the far list its buffer, so a future overflow is an error rather than a wrong force. The queue itself stays unverifiable under tracing -- hence the 2x margin. Regression test recovers the applied force from the trajectory and compares it with an eager prepare+evaluate at the same positions (comparing against x0 is wrong here: close pairs move O(0.1) per step and dominate the L2 norm). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
TobiBu
force-pushed
the
fix/strict-refresh-nearfield-truncation
branch
from
September 6, 2026 08:42
acc71fd to
0e6d1c1
Compare
…arfield-truncation
The capacity hand-off carried three caps into the traced refresh. Two of them belong there; the compact far-pair cap does not, and widening it broke tests/integration/test_fmm.py::test_strict_fused_compact_far_pair_cap_fails, which pins that a too-small cap fails loudly instead of truncating. The far-pair cap is already checked under tracing -- _raw_to_compact_far_pairs raises through a debug callback -- so it never truncated silently, and it is set explicitly by JACCPOT_STATIC_STRICT_FUSED_COMPACT_FAR_PAIR_CAP: raising a cap the caller named would turn a deliberate memory bound into a no-op, the same reasoning _resolve_tracing_traversal_config already applies to explicit capacities. The neighbour cap, the one whose overflow flag is a tracer nobody reads and the one that produced the wrong forces, is still widened. The scan's saturation guard keeps both arms and now says which is which: the neighbour arm is the only defence for a silent failure, the far-pair arm a second, cheap line behind yggdrax's own raise. Verified: the pinned test raises again (CPU), and test_strict_run_v2_refresh_keeps_full_neighbor_lists still passes on an A100 with the override gone -- rows 781, force error 6.5e-4 at step 2. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
TobiBu
pushed a commit
that referenced
this pull request
Sep 10, 2026
JACCPOT_STATIC_STRICT_FUSED_FLAT_WALK and JACCPOT_STATIC_STRICT_FUSED_M2L_CSR default to 1. Rules that make a default safe where the opt-in could simply raise: * A merely-defaulted flat-walk flag falls back to the traced dual walk QUIETLY when the configuration cannot take the flat walk (treecode walk requested, a MAC other than bh/dehnen, a solver-owned pair policy, the non-flat far-pair layout). An explicit "1" against such a configuration still raises: then the caller asked for a walk it cannot have. * A capacity the caller did not NAME in the environment (no ..._COMPACT_FAR_PAIR_CAP / ..._NEIGHBOR_EDGE_PROFILE_FIXED_CAP) grows eagerly from its floor (131072 / 2^21 directed pairs; ceilings 2^26 / 2^28); a named cap is exact and raises on overflow (#333). Cap growth no longer consumes the queue retry budget. Without this the old 2^21 near default raised at leaf 64 / N=200k (needs 2^22) -- a regression the dual walk never had because it sized from eager data. * _strict_fused_capacity_handoff hands the settled far/near widths to the traced refresh AND to later eager prepares as floors, so lax.scan carry shapes match and never shrink. * The CSR M2L gate keeps its sm_80 / interpret predicate. Tests: test_flat_walk_default_dispatch.py (CPU: default routing, =0, the three fallback/raise pairs, named-vs-unnamed caps, floor handoff); seam test for unnamed-cap growth; the wiring tests now pin default-on and the treecode flag winning over a defaulted flat walk. Docs updated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
TobiBu
added a commit
that referenced
this pull request
Sep 10, 2026
JACCPOT_STATIC_STRICT_FUSED_FLAT_WALK and JACCPOT_STATIC_STRICT_FUSED_M2L_CSR default to 1. Rules that make a default safe where the opt-in could simply raise: * A merely-defaulted flat-walk flag falls back to the traced dual walk QUIETLY when the configuration cannot take the flat walk (treecode walk requested, a MAC other than bh/dehnen, a solver-owned pair policy, the non-flat far-pair layout). An explicit "1" against such a configuration still raises: then the caller asked for a walk it cannot have. * A capacity the caller did not NAME in the environment (no ..._COMPACT_FAR_PAIR_CAP / ..._NEIGHBOR_EDGE_PROFILE_FIXED_CAP) grows eagerly from its floor (131072 / 2^21 directed pairs; ceilings 2^26 / 2^28); a named cap is exact and raises on overflow (#333). Cap growth no longer consumes the queue retry budget. Without this the old 2^21 near default raised at leaf 64 / N=200k (needs 2^22) -- a regression the dual walk never had because it sized from eager data. * _strict_fused_capacity_handoff hands the settled far/near widths to the traced refresh AND to later eager prepares as floors, so lax.scan carry shapes match and never shrink. * The CSR M2L gate keeps its sm_80 / interpret predicate. Tests: test_flat_walk_default_dispatch.py (CPU: default routing, =0, the three fallback/raise pairs, named-vs-unnamed caps, floor handoff); seam test for unnamed-cap growth; the wiring tests now pin default-on and the treecode flag winning over a defaulted flat walk. Docs updated. Co-Authored-By: Claude Fable 5.1 <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.
Fixes #332.
The defect
strict_run_v2(fusedlarge_n_gpu/static_radix lane) rebuilt its interaction lists inside the compiled velocity-Verlet scan with the preset traversal capacities. Eagerly those are irrelevant: yggdrax's retry ladder grows them until the walk fits. Underjitthe overflow flags are tracers, the ladder has one attempt, and yggdrax returns the truncated result; jaccpot never read the flags. At N=200k, leaf 256, rows of up to 781 were cut to 256 (theta 1.0) / 128 (theta 0.6), 85 % of the near-field entries vanished, and every step after the first carried a wrong force (5.8 % rel-L2 at theta 1.0, ~60 % at theta 0.6) withfallback_count0 and no diagnostic.The fix
_build_dual_tree_artifacts_split_strict_streamedpasses aretry_loggerthat captures the ladder'ssuccessevent and reports the capacities it ran with plus what it observed (longest row, far-pair count); it also accepts overrides that only ever raisemax_neighbors_per_leaf/ the compact far-pair cap._strict_fused_capacity_handoff(fmm_prepare) stores the eager report on the engine and, on the traced build, widens the config: the per-leaf neighbour cap to pow2(1.5x the observed longest row) and the pair queue to pow2(2x the ladder's answer). Wired at both dual-and-downward call sites (generic and strict-streamed fast)._raw_to_compact_far_pairsraises through a debug callback), so a too-small one fails loudly rather than truncating, and it is named explicitly byJACCPOT_STATIC_STRICT_FUSED_COMPACT_FAR_PAIR_CAP-- widening a cap the caller set would turn a deliberate memory bound into a no-op. An earlier revision of this branch did widen it and broketests/integration/test_fmm.py::test_strict_fused_compact_far_pair_cap_fails, which pins exactly that loud failure.strict_run_v2'scapacity_okscan carry now also fails when a refreshed row reaches the traced neighbour cap or the far list its buffer; the post-scan error names all three caps. The queue remains unverifiable under tracing, hence the 2x margin.Verification
tests/integration/test_strict_run_v2_refresh_capacity.py(GPU, slow): recovers the applied force from the trajectory and compares it with an eager prepare+evaluate at the same positions (against x0 the true field changes by O(1) per step here because of close pairs); asserts full-length refreshed rows.tests/unit/runtime,test_public_api_surface,test_strict_run_fail_fast,test_strict_refresh_faces,test_same_topology_refresh_modes: green.🤖 Generated with Claude Code
Record note (2026-09-07). Commit
ca57749's message quotes "force error 6.5e-4 at step 2" for the regression test. That figure is from the theta=1.0 probe (probe_step_check8.py), not from this test, which runs theta=0.6 and asserts a bound rather than reporting a number. What is independently verified on this tree: the pinned far-pair-cap test raises again on CPU, andtest_strict_run_v2_refresh_keeps_full_neighbor_listspasses on an idle A100 with the far-cap override removed. Please drop that figure from the message if this branch is squashed.