From f1e03423f336bfdf120e5f2ee5c949fded17130c Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 15 Oct 2026 09:03:11 +0000 Subject: [PATCH] Action upload: keep 2D slot fallback for ObjectManager(cfg=None) 19bd308 computed slot = 3*self.cfg.dim unconditionally, so a default manager without cfg raised even when empty. Use the existing fallback (cfg.dim if cfg else 2). Regression for empty and one-body managers. Co-Authored-By: Claude Opus 5.5 --- src/CelerisLab/body/manager.py | 2 +- tests/unit/test_jets.py | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/CelerisLab/body/manager.py b/src/CelerisLab/body/manager.py index d901428..feafb1f 100644 --- a/src/CelerisLab/body/manager.py +++ b/src/CelerisLab/body/manager.py @@ -627,7 +627,7 @@ class ObjectManager: Single gate for every action path (setters or direct ``action`` edits): surface-actuated and Jet-driven bodies must keep zero motion slots. """ - slot = 3*self.cfg.dim + slot = 3*(self.cfg.dim if self.cfg else 2) for obj in self.objects: obj.validate_surface_actuation(self.cfg) base = obj.obj_id*slot diff --git a/tests/unit/test_jets.py b/tests/unit/test_jets.py index 3548649..7d0293a 100644 --- a/tests/unit/test_jets.py +++ b/tests/unit/test_jets.py @@ -300,3 +300,13 @@ def test_fine_boundary_keeps_edge_frame_hits_and_checks_jets(): refinement.prepare_fine_boundary(cfg, patch, [legacy], jets=[jet]) disjoint = Jet(Sector(C, math.pi, .5, R + .01), Radial(C, inward=False)) refinement.prepare_fine_boundary(cfg, patch, [legacy], jets=[disjoint]) + + +def test_action_upload_keeps_cfg_none_fallback(device): + # Default ObjectManager(cfg=None) keeps the 2D slot fallback, empty or not. + from CelerisLab.body.manager import ObjectManager + stream = SimpleNamespace(synchronize=lambda: None) + bodies = ObjectManager(12, 10, 1, 9) + bodies._upload_action_async(stream) + bodies.add(circle(radius=2.)) + bodies._upload_action_async(stream)