Test-side only; no production, manifest or pin change. Group A identity
checks (test_source_pin and the jets.py pins) are unchanged and stay
failing as recorded.
B test_refined_dfg: receipt/plan fixtures load the frozen manifest JSON
that verify_source returns for a matching tree (frozen_manifest), and
the two manifest-selection assertions call verify_source with only its
working-tree hash comparison neutralised (selected_manifest), so the
malformed/collision/observation-mode/checkout receipt checks run again.
test_source_pin remains the single identity check.
C test_channel_root: int(owner)-1 (uint64-int became float on NumPy 1);
test_shifted_storage: FP32 NaN fill so the arrays stay FP32. Both reach
the intended immutable/representation/FP32/density checks.
D test_block_stepper fake gets _ddf_shifting; test_fine_surface_gpu sets
_boundary_hosts/_level_jets instead of the read-only fine_boundary view;
test_refinement_followup fake_backend sets _layouts/_ddf_shifting/
_level_cfgs instead of the read-only fine_layout view (as reviewed in
32da2d73).
E test_kernel_contracts_reject_before_upload: an inconsistent pair tau is
now first rejected by the hierarchy chain check; the test asserts that
rejection, then bypasses _check_chain to prove the per-level omega/tau
guard still rejects, and asserts no mem_alloc/memcpy_htod in either case.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One local levels(bounds, blocks, objects, jets, **rest) builds the
two-level lists; run_steps and every rejection case use it. All five
before-CUDA rejections, the margin and one-jet checks keep their inputs.
Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dense root + blocked fine level is level_blocks=[None, block]; bodies go
to level_objects[1]. Both before-CUDA rejections (non-dividing and
malformed fine block) keep their inputs. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper and the PeriodicPatchStepper alias are called with
refinements=[bounds] instead of the positional legacy bounds (same
_legacy_levels result). Assertions, including the before-CUDA and
four-cell/omega/layout rejections, unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KW becomes levels() (scalar L1 + scalar L2, per-level blocks, objects,
Jets). All rejection cases are kept per level. Two cases change branch:
L2 bodies/Jets with no nested child (legacy 'child_objects/child_jets
require a nested child') are now an entry for a level that does not
exist ('needs one entry per level'); several L1 patches + scalar child
now meets 'a scalar child requires a scalar parent'. Both still reject
before CUDA. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_refinement_mrt_gpu, test_shifted_jets_gpu and
test_refinement_blocked_base pass refinements/level_* lists. The three
blocked-base rejection cases keep their inputs per level; base-only
blocks now meet the level-list rule (blocked refined levels below) where
the legacy keyword check fired before. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_exchange_window, test_raw_exchange_gpu (one fine(block) helper for
the repeated circle+jet construction), test_refinement_jets,
test_multiple_pinned_remap_gpu and test_pinned_body_remap_gpu pass
refinements/level_* lists. Dense fine levels stay level_blocks=[None,
None|block] as before. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
test_refinement_gpu (incl. PeriodicPatchStepper alias calls),
test_channel_root_gpu, test_fine_surface_gpu, test_shifted_remap_gpu,
test_runtime_child_remap_gpu and test_refinement_three_level_multipatch_gpu
pass refinements/level_* lists; scalar and set children map to the second
refinement entry exactly as _legacy_levels did. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
baba5e0 replaced _advance_child with _advance(index, parent_buffer) driven
from _hop; the two feed-order tests still patched the removed method.
Patch _advance and record only index 2 (L1 hop feeding L2); assertions,
expected order and the stale-feed negative control are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 3f47436073)
Integrate reviewed test changes from 7c1517de819741907fb945ea0ab7864734fa3856 and 340ba4e1dc6386581839c0b28c8fe8a1f4aeb70b unchanged. Document bounded 2D implementation, evidence and open gates; production source and historical manifests are unchanged.
Separate GPU class for a shifted MRT, all-blocked, stationary-body case
without Jets: window totals vs summed per-base reads (substep-scaled
tolerance), bitwise populations vs a raw-only stepper, a single step(N)
stepper with bitwise-equal window rows and populations, step(0)
non-change, and reset after a window. SRT/Jet test stays separately
scoped. Test-only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Scale the window-vs-summed-reads tolerance by the actual absolute fine
substep contributions (last_raw after every fine hop), labelled a
conservative engineering tolerance rather than a proof. Compare
populations by finite FP32 bits plus NaN masks and reject infinities.
Test-only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper(observe_window_exchange=True), which requires
observe_raw_exchange, allocates a second per-link FP64 ledger per body
level. While a window is open, the unchanged BlockAccumulateExchange
kernel also accumulates into it after each fine hop. Small API:
start_exchange_window() zeroes and opens at the current completed step;
read_exchange_window(body_id, level=) is non-destructive and reports
impulse with rates over the integer window duration. initialize/
_initialize_raw and step failure invalidate; remap builds a new instance
with no open window; Jet amplitude updates may stay in-window. Default
disabled: no allocation and no extra launch; last_substep/last_base_step
unchanged. summarize_exchange gains window='window' with duration.
Host contract tests (mocked driver) and a GPU gate against summed
per-base reads with a reordering-bound FP64 tolerance.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove MRT from the FixedPatch2D rejection matrix (TRT and other
rejections retained); convert host MRT tests to stdlib unittest; add GPU
gates for unshifted dense-vs-blocked MRT two-level roots (exact bits) and
a shifted all-blocked three-level MRT smoke checking per-level omega.
No numerical source change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Additive compile-time COLLISION_MODEL == 2 branches in BlockStep,
BlockChannelStep and patch_collide repeat the uniform collide_dispatch
MRT sequence (zero forcing, omega clamp, collide_mrt_no_force). SRT
statements, including the shifted retained-delta/direct-momentum path,
are unchanged under the alternate branch. Guards accept SRT or MRT only;
TRT, LES, non-FP32, non-double-buffer and shifted dense/mixed refinement
stay rejected. Transfers, subcycling, BFL, raw ledgers, channel closures,
shifted-Jet SRT guard and PeriodicBlockStepper are untouched. Existing
MRT operator, shifted representation and fixed kinetic rates are reused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Schedule test drives _pairs[i].explode/coalesce and patches _advance(index,
buffer) for the stale L1->L2 feed mutant; remap rejection test patches
_boundary_hosts entries and hierarchy.pairs instead of the read-only views;
the GPU launch-failure test patches _pairs[0].explode. Assertions unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
prepare_fine_boundary accepts a FixedPatchSet2D: objects are projected once
onto the level-wide fine grid (FixedPatchSet2D.fine_origin = (0, 0), same
coarse cell-edge -> fine cell transform), each circle must lie inside one
patch, coarse transfer cells are checked against the covered union, and body
ids stay object positions, so the existing jet one-body-per-jet, overlap and
(receiver, dir) writer checks run once over the whole level (caller obj_id
cannot bypass them). The stepper no longer rejects fine_objects/jets with
several patches; blocked link tables, BFL and the jet amplitude cache are
reused unchanged. No kernel change. README/docstring scope updated.
Tests: CPU translation/ids/rejections (outside one patch, one jet over two
bodies at zero amplitude); GPU one body via the new path == single-patch path
(both modes), two bodies (+jets, amplitude switch) == tiled single (bitwise).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper(..., child=(x0,y0,x1,y1), child_block=(by,bx)) adds an L2
patch in L1 window cells (requires fine_block/base_block, one L1 patch, no
bodies/jets). nest_patch() builds the L1->L2 FixedPatch2D (2*nu on L1) and
the composed L1 kind (inherited INNER/OUTER kept, child-covered ACTIVE made
OUTER), rejecting from the actual tables: coverage outside ACTIVE, donors or
receivers not uncovered ACTIVE, surviving ACTIVE pulls of covered/OUTER cells
without a child-supplied arrival, and overlap with L1's restriction footprint.
Step order per L1 hop: explode L1(src)->L2, two L2 hops (halo, step), L1 halo,
receiver-local L2->L1 staging into src, L1 step. The second hop thus feeds L2
from the new L1 G; L2 is never refilled from L0; L0 stays once per step (1:2:4).
Existing kernels only; a small _Pair holds the child transfer bindings (explode
from the child module, parent window stride). Two-level API unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchSet2D.fine_layout rejects non-positive, float, bool or wrong-length
block sizes with ValueError before any modulo (was ZeroDivisionError/TypeError).
The face gap-4 GPU test now checks raw owner cores directly by kind/covered
for every patch (ACTIVE finite, OUTER/holes/covered NaN; INNER not asserted),
not only the masked download and reversed-order parity. README documents the
body-free multipatch call, scope and level-wide fine shape.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One rectangle via the multipatch path is bit-identical to the old
single-patch blocked path (both modes, raw masks); S1 two-patch 16x32 equals
the 16x16 one-patch run tiled (bitwise), in both rectangle orders; face
gap-4 pair is order-invariant with exact covered/hole masks. Mass printed
as a diagnostic only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Caller obj_id 99 spanning 2x2 fine blocks: driven rows carry the single
remapped owner 0 across several block ids, accepted; source id unchanged.
Caller ids (99, 7) under one tube are rejected at amplitude 0 and .002
on the 32x24 fixture; source ids unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
surface_link_velocity (the shared host check used by CurvedLinkSoA,
ObjectManager sync, prepare_fine_boundary and FixedPatchStepper) now
rejects a jet whose selected cut links carry more than one body id, at
any amplitude, before uploads. Identity is the scene-wide body id of the
physical cut-link list, so one body spanning storage blocks stays valid.
No body selector; empty-selection semantics unchanged.
Tests: two bodies under one jet rejected (amplitude 2e-3 and 0) on the
Simulation/manager path and on the fine path; separate jets on separate
bodies accepted on both; one fine body crossing 2x2 block seams accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper.set_jet_amplitude validates index/amplitude and builds
the new rows before touching the device; invalid input leaves the
instance usable. A copy/sync error marks it failed (as initialize/step/
download do) and re-raises; host state (_jets, blocked velocity table)
commits only after a successful upload. CurvedLinkSoA.set_jet_amplitude
likewise uploads a new array first and commits jets/surface_velocity
afterwards. Focused mocked-driver tests for dense and blocked copy
failure, invalid input and IndexError.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper(..., jets=()) passes jets (coarse cell-edge frame, as
fine_objects) to prepare_fine_boundary, which runs the shared assignment
checks before CUDA. Dense fine path: assign_surface with jets and the
boundary's true hits. Blocked path: surface_link_velocity with jets/hits;
unit-amplitude shapes cached. set_jet_amplitude (new/ready only) validates
first, then rewrites the dense SoA column or the blocked jet rows and
re-uploads only the velocity buffer after a stream sync. Scheduling,
kernels and launch ABI unchanged.
tests/validation/multigrid/test_refinement_jets.py: mocked-driver CPU
checks and frozen GPU gates G1-G3 (layout identity, jet vs legacy <=1e-6,
amplitude switch).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The blocked actuated path called the helper with an unvalidated fine
config (nq=0), so receiver*nq+dir collapsed distinct writers and the
unique-writer guard fired. Validate after wall-aware sanitization, as the
dense path does before assign_surface; the test's fine_cfg helper too.
Unique-writer guard unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Asserts 21 aperture links, all with nonzero velocity, and 3 halo-writer
plus 2 halo-donor aperture rows in each decomposed layout (actuation
coverage across seams, not only geometric cut-link coverage). Velocity
is given in coarse units; prepare_fine_boundary scales it once. The GPU
gate remains storage equivalence; no zero-mass-change claim.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- curved_links.surface_link_velocity: pure host helper extracted from
CurvedLinkSoA.assign_surface (which now calls it; dense path unchanged).
Rows follow physical cut-link order.
- blocks.cu BlockCurvedBoundary: one nullable trailing surface_velocity
argument (2 floats/link), same convention as CurvedBoundaryKernel; no
exchange output. Both call sites pass it explicitly (PeriodicBlockStepper
passes null; single-level behaviour unchanged).
- FixedPatchStepper blocked mode accepts actuated stationary circles,
validated against the physical fine_cfg; uploads the velocity table only
when any actuation spec exists and fails before BFL if that buffer is
missing (even at zero amplitude). Blocked exchange diagnostics are
unavailable; dense exchange behaviour unchanged. No force aggregation,
no motion, no new numerical formula.
Tests: 1x1 seam (0,0), receivers in 4 blocks, all q<.5 links fallback 0;
dense SoA never built in blocked mode; launch order incl. null vs velocity
pointer; missing-buffer guard at 0 and 0.002; helper == assign_surface;
aperture crosses a seam; GPU: periodic and slot_reservoir, +/-0.002,
8 coarse steps, dense vs 1x1/2x2/4x2 exact values + NaN masks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FixedPatchStepper(fine_block=..., fine_objects=[circle]) now accepts
passive stationary circles; any surface actuation is rejected before CUDA
(dense fine path unchanged). prepare_fine_boundary still decides legality
on the dense fine grid; its SoA is mapped by the new array-based storage
adapter blocks.blocked_link_tables (map_cut_links: unique receiver owner
and local writer, row order kept; blocked flags sized nblocks*L), which
PeriodicBlockStepper._static_circles now also uses (single-level legality
builder unchanged). Per fine hop on the same buffer: halo -> existing
BlockCurvedBoundary -> BlockStep(flags, kind). No CUDA changes.
Tests: fixture 76 links / 68 q<.5 and 8 seam writes + 8 seam donors per
decomposed layout (both modes); adapter flags sizing; mocked launch-order
contract; GPU: periodic and slot_reservoir, 8 coarse steps, dense fine
body vs 1x1/2x2/4x2 fine blocks, exact values + NaN masks on masked
downloads and raw final arrays, ACTIVE fluid finite, solid/OUTER NaN.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- GPU test: after hop 2 some INNER_GHOST populations are NaN (pulled from
OUTER poisoned on hop 1; 236 slots in pinned CPUREF); assert ACTIVE
finite and OUTER NaN, keep the full dense-vs-blocked raw value/NaN-mask
comparison.
- A 1x1 non-periodic fine layout has zero halo pairs: skip the halo table
uploads (CUDA rejects mem_alloc(0)); _fine_halo already skips launch.
CPU guard test with driver doubles.
- Drop the class-level fine_layout default; the followup fake backend now
sets fine_layout = None explicitly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fine_block=(by, bx) partitions the ENTIRE fine_shape (incl. the four-cell
patch ghost band) with a non-periodic one-cell-halo BlockLayout2D; body-
free only (fine_objects rejected in blocked mode; dense fine-body and
actuation path unchanged). Per coarse step on the same stream:
BlockExplode into ghost owner cores -> gather -> BlockStep(kind) ->
gather -> BlockStep(kind) -> unchanged PatchCoarseStep reading remapped
owner-core child slots in the original row/child order. Public arrays
keep the dense fine shape; only the private allocation is blocked.
blocks.cu: explicit BlockExplode; BlockStep gains nullable kind
(OUTER skip pull + NaN, INNER pull only, ACTIVE pull + SRT).
PeriodicBlockStepper passes an explicit null kind (raw launch ABI).
refinement.cu/refinement.py and coarse numerics unchanged.
Tests: CPU rejections and table remap (dense (q,cell) and child order
preserved, owner cores, kinds); GPU gate: periodic and slot_reservoir,
8 coarse steps, dense vs 1x1/2x2/4x2 fine blocks bit-identical in
masked downloads and raw coarse/unpacked fine incl. ghost NaN masks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
At the half-integer center the -0.1/-0.5 circles were already rejected
as unresolved, so the case did not exercise the finite/positive-radius
guard; an integer center makes the squared radius mark one solid cell.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
_static_circles now checks finite center/radius and radius > 0 before
build_flag_mask (a negative radius squared to a one-cell solid), matching
prepare_fine_boundary. objects is converted to a tuple before the
emptiness test so an empty iterable takes the body-free path.
CPU tests: negative/NaN radius and nonfinite center rejected before CUDA;
empty iterator skips circle preparation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
blocks.cu: BlockCurvedBoundary passes the receiver-local core cell and the
block-offset fi to the unchanged apply_bouzidi_link (Uw=Vw=0, obs=nullptr),
so k_s and the q<1/2 donor follow the window image the next pull reads.
BlockStep takes nullable block-cell flags; solid cores store NaN each step.
Adds core/flags.cuh, core/obs.cuh and boundary/curved_boundary.cuh.
block_stepper.py: objects=() accepts stationary passive circles only; host
preparation rejects before CUDA: non-circle/moving/actuated/sensor roles,
overlap, domain-edge contact, and any fluid core (all rows/columns, periodic
neighbors) whose pull from a solid lacks exactly one cut link. Uses
map_cut_links for unique receiver owner/local writer. Order per step:
halo copy -> BFL -> pull/collide, no copy in between. Fluid-only
initialize validation; solids NaN.
Tests: CPU rejections/tables; GPU 32x24, nu .1, 8 steps, circle
(15.5,11.5) R4.3 with halo-write and halo-donor presence asserted,
1x1/2x2/4x2 bit-identical, finite fluid/NaN solid, FP64 BFL+pull/SRT
<= 3e-6 on fluid; drift reported. Body-free gate unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>