From ee7074a53d0faefa884a64137d9a74a7c0feae08 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Oct 2026 07:04:47 +0000 Subject: [PATCH] tests: restore the negative checks masked by stale fixtures (WP-B groups B-E) 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 --- tests/unit/test_channel_root.py | 2 +- tests/unit/test_refined_dfg.py | 41 ++++++++++++++++--- tests/unit/test_shifted_storage.py | 6 ++- .../multigrid/test_block_stepper.py | 1 + .../multigrid/test_fine_surface_gpu.py | 3 +- .../multigrid/test_refinement_followup.py | 21 ++++++++-- 6 files changed, 61 insertions(+), 13 deletions(-) diff --git a/tests/unit/test_channel_root.py b/tests/unit/test_channel_root.py index 1d4e6e8..4d59830 100644 --- a/tests/unit/test_channel_root.py +++ b/tests/unit/test_channel_root.py @@ -50,7 +50,7 @@ def test_masks_and_minimal_footprint(): def test_actual_closure_read_conflicts(): pair, layout, targets = transfer((6, 6, 18, 14)) validate_channel_transfers(pair, layout, targets) - for target in (layout.slot(layout.owner[5, -1]-1, 2), + for target in (layout.slot(int(layout.owner[5, -1]) - 1, 2), # integer under NumPy 1 and 2 layout.slot(layout.owner[1, 4], 4), layout.slot(layout.owner[-2, 4], 3)): with pytest.raises(ValueError, match="immutable"): diff --git a/tests/unit/test_refined_dfg.py b/tests/unit/test_refined_dfg.py index dd49fed..fff8f2f 100644 --- a/tests/unit/test_refined_dfg.py +++ b/tests/unit/test_refined_dfg.py @@ -141,16 +141,47 @@ def test_axis_specific_sampling_phase(): np.testing.assert_allclose(fine_y - ((k + 43) - 0.5) * 0.00125, 0, atol=1e-15) +def frozen_manifest(observation_mode): + """Frozen MRT manifest JSON as recorded, without hashing the working tree.""" + name = "source_manifest_window.json" if observation_mode == "window" else "source_manifest_mrt.json" + return json.loads((r.HERE / "data/refined_dfg" / name).read_text()) + + +def selected_manifest(collision, observation_mode): + """verify_source's manifest selection with its working-tree hash comparison neutralised. + + Source identity is owned by test_source_pin; this exercises only which frozen manifest + verify_source selects and returns for (collision, observation_mode). + """ + from unittest.mock import patch + + class Digest(str): + def __ne__(self, other): + return False + + class Hash: + def __init__(self, data=b""): + pass + + def hexdigest(self): + return Digest() + + with patch.object(r.hashlib, "sha256", Hash): + return r.verify_source(r.DEFAULT_SOURCE, collision, observation_mode) + + def test_full_requires_completed_pilot(): with unittest.TestCase().assertRaisesRegex(ValueError, "pilot-results"): - r.verify_pilot(None, r.verify_source(r.DEFAULT_SOURCE, "MRT", "window")) + r.verify_pilot(None, frozen_manifest("window")) def pilot_fixture(path, observation_mode="window", jet_scenario="none", case_selection="both", uniform_diameter=80, placement="wide"): """Synthetic contract fixture only; never a physical result or run receipt.""" + # Receipt-logic fixture: the frozen manifest verify_source returns for a matching tree. + # Source identity itself is checked only by test_source_pin. manifest = (r.verify_source(r.DEFAULT_SOURCE, "MRT", "window", jet_scenario) - if observation_mode == "window" else - json.loads((r.HERE / "data/refined_dfg/source_manifest_mrt.json").read_text())) + if observation_mode == "window" and jet_scenario != "none" else + frozen_manifest(observation_mode)) selection = dict(case_selection=case_selection, uniform_diameter=uniform_diameter, placement=placement) (path / "plan.json").write_text( json.dumps( @@ -348,7 +379,7 @@ def test_record_actual_checkout_separately(): actual = checkout_provenance(r.DEFAULT_SOURCE) assert len(actual["checkout_revision"]) == 40 assert isinstance(actual["checkout_dirty"], bool) - assert r.verify_source(r.DEFAULT_SOURCE, "MRT", "window")["production_origin_commit"].startswith("d930") + assert selected_manifest("MRT", "window")["production_origin_commit"].startswith("d930") def test_window_plan_preserves_physics(): @@ -358,7 +389,7 @@ def test_window_plan_preserves_physics(): assert baseline.pop("observation_mode") == "last_base_step" assert window.pop("observation_mode") == "window" assert baseline == window - assert r.verify_source(r.DEFAULT_SOURCE, collision, "window")["observation_mode"] == "window" + assert selected_manifest(collision, "window")["observation_mode"] == "window" with unittest.TestCase().assertRaises(ValueError): r.verify_source(r.DEFAULT_SOURCE, "MRT", "unknown") diff --git a/tests/unit/test_shifted_storage.py b/tests/unit/test_shifted_storage.py index ea3a373..8e5ea07 100644 --- a/tests/unit/test_shifted_storage.py +++ b/tests/unit/test_shifted_storage.py @@ -78,13 +78,15 @@ class ShiftedStorage(unittest.TestCase): def test_shifted_density_and_tag_validation(self): old,new = topology(A),topology(B) - a = tuple(np.where(m[None], np.float32(-.001), np.nan).repeat(9,axis=0) for m in old.leaf_masks) + a = tuple(np.where(m[None], np.float32(-.001), np.float32(np.nan)).repeat(9,axis=0) + for m in old.leaf_masks) # FP32 under NumPy 1 and 2 promotion rules remap(old,new,a) with self.assertRaisesRegex(ValueError,'representation'): remap(old,new,a,False) with self.assertRaisesRegex(ValueError,'FP32'): remap(old,new,tuple(x.astype(np.float64) for x in a)) a[0][:,old.leaf_masks[0]] = -1 with self.assertRaisesRegex(ValueError,'positive density'): remap(old,new,a) - rest = tuple(np.where(m[None],np.float32(0),np.nan).repeat(9,axis=0) for m in old.leaf_masks) + rest = tuple(np.where(m[None],np.float32(0),np.float32(np.nan)).repeat(9,axis=0) + for m in old.leaf_masks) remap(old,new,rest) with self.assertRaisesRegex(ValueError,'positive density'): remap_synchronized(old,new,rest,base_count=7,level_steps=(7,14,28),phase='postcollision_g') diff --git a/tests/validation/multigrid/test_block_stepper.py b/tests/validation/multigrid/test_block_stepper.py index ecebb80..4ec7abc 100644 --- a/tests/validation/multigrid/test_block_stepper.py +++ b/tests/validation/multigrid/test_block_stepper.py @@ -192,6 +192,7 @@ class CpuContracts(unittest.TestCase): backend._lock = RLock() backend._status = "ready" backend._step_count = 0 + backend._ddf_shifting = False # unshifted storage, as for the default config backend._stream = Mock() backend._module = Mock() backend._copy = backend._step = Mock() diff --git a/tests/validation/multigrid/test_fine_surface_gpu.py b/tests/validation/multigrid/test_fine_surface_gpu.py index 85fc266..4b961cc 100644 --- a/tests/validation/multigrid/test_fine_surface_gpu.py +++ b/tests/validation/multigrid/test_fine_surface_gpu.py @@ -282,7 +282,8 @@ def test_fine_surface_four_hops(speed): @pytest.mark.parametrize("missing", ["surface_velocity_gpu", "link_exchange_gpu"]) def test_missing_surface_device_buffer_rejects_before_launch(missing): backend = implementation.FixedPatchStepper.__new__(implementation.FixedPatchStepper) - backend.fine_boundary = SimpleNamespace(objects=[object_spec(.002)]) + backend._boundary_hosts = [None, SimpleNamespace(objects=[object_spec(.002)])] + backend._level_jets = [(), ()] backend._fine_curved = SimpleNamespace(fluid_idx_gpu=object(), surface_velocity_gpu=object(), link_exchange_gpu=object()) setattr(backend._fine_curved, missing, None) diff --git a/tests/validation/multigrid/test_refinement_followup.py b/tests/validation/multigrid/test_refinement_followup.py index da0a35e..da7384e 100644 --- a/tests/validation/multigrid/test_refinement_followup.py +++ b/tests/validation/multigrid/test_refinement_followup.py @@ -108,7 +108,9 @@ class FaultGuardsCPU(unittest.TestCase): def fake_backend(self): backend = PeriodicPatchStepper.__new__(PeriodicPatchStepper) - backend.fine_layout = None # dense fine storage + backend._layouts = [None, None] # dense storage on both levels + backend._ddf_shifting = False # unshifted on every level, as _check_storage expects + backend._level_cfgs = [LBMConfig(nx=16, ny=16, viscosity=.1)] * 2 # ddf_shifting off backend.ctx = Mock(activate=nullcontext) backend._lock = RLock() backend._status = "ready" @@ -158,10 +160,21 @@ class FaultGuardsCPU(unittest.TestCase): with self.assertRaisesRegex(RuntimeError, "four-cell"): PeriodicPatchStepper(cfg, context=context, refinements=[(4, 4, 12, 12)]) p = implementation.FixedPatch2D.from_config(cfg, (4, 4, 12, 12)) - with patch.object(cuda, "Stream"), patch.object(implementation.FixedPatch2D, "from_config", - return_value=replace(p, tau_coarse=.9)): - with self.assertRaisesRegex(RuntimeError, "omega/tau"): + from CelerisLab.lbm import hierarchy + bad = patch.object(implementation.FixedPatch2D, "from_config", + return_value=replace(p, tau_coarse=.9)) + # A pair tau inconsistent with its level config is rejected twice over, both before + # any device allocation or upload: first by the hierarchy chain check, and, if that + # is bypassed, by the per-level omega/tau check in _build_level. + with patch.object(cuda, "Stream"), bad, patch.object(cuda, "mem_alloc") as alloc, \ + patch.object(cuda, "memcpy_htod") as upload: + with self.assertRaisesRegex(RuntimeError, "config chain is inconsistent"): PeriodicPatchStepper(cfg, context=context, refinements=[p.bounds]) + with patch.object(hierarchy, "_check_chain"), \ + self.assertRaisesRegex(RuntimeError, "omega/tau"): + PeriodicPatchStepper(cfg, context=context, refinements=[p.bounds]) + alloc.assert_not_called() + upload.assert_not_called() module = Mock() module.get_global.return_value = (Mock(), 16) with patch.object(cuda, "Stream"), patch.object(compiler, "generate_config"), \