git.lucas.co / cce-designer
graphic design tool
git clone https://git.lucas.co/cce-designer.git

commit23e984b8ad818d11ef34884169dd8faf26fec1e5
parent062d98298e
authorLucas Galante <lsgalante12@gmail.com>
date2026-09-30 12:21
fix: MCP's enter asks is_enterable, so an empty simnet can be entered

The MCP arm kept a hand-copied test that predated simnet and missed it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

 src/main.rs   | 32 ++++++++++++++++++++++++++++++++
 src/window.rs |  2 +-
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/src/main.rs b/src/main.rs
index 9abcefa..6c4b88a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12067,6 +12067,38 @@ mod tests {
         assert_eq!(still.positions(), moved.positions());
     }
 
+    /// MCP's `enter` dives into exactly what the keyboard does: a simnet
+    /// with no children yet is a container, a native node is not.
+    #[test]
+    fn mcp_enter_agrees_with_the_keyboard_about_what_is_enterable() {
+        let mut state = State::new(false);
+        let node = |name: &str, ty: &str| crate::app::FsNode {
+            id: format!("{name}-id"),
+            name: name.to_string(),
+            node_type: ty.to_string(),
+            children: vec![],
+            params: vec![],
+            geometry_visible: false,
+            bypassed: false,
+            position: (0.0, 0.0),
+            inputs: 1,
+            outputs: 1,
+        };
+        state.current_path.clear();
+        state.fs_root.children.push(node("sim_empty", "simnet"));
+        state.fs_root.children.push(node("remesh_leaf", "remesh"));
+        let mut redraw = false;
+        for (i, child) in state.fs_root.children.clone().iter().enumerate() {
+            let entered = state.apply_action(McpAction::Enter { slot: i }, &mut redraw).is_ok();
+            assert_eq!(entered, child.is_enterable(), "{} ({})", child.name, child.node_type);
+            if entered {
+                state.apply_action(McpAction::Up, &mut redraw).unwrap();
+            }
+        }
+        let names: Vec<_> = state.fs_root.children.iter().map(|c| c.name.as_str()).collect();
+        assert!(names.contains(&"sim_empty") && names.contains(&"remesh_leaf"));
+    }
+
     /// A bypassed node is in the graph and does nothing: what reads it gets
     /// what it reads. A generator, which reads nothing, gives nothing; a
     /// subnet passes its Input and its children are not run; and a node
diff --git a/src/window.rs b/src/window.rs
index fb8d1cd..3a59016 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -322,7 +322,7 @@ impl State {
             }
             McpAction::Enter { slot } => {
                 let dir = state.current_dir();
-                if slot < dir.children.len() && (dir.children[slot].node_type == "node" || !dir.children[slot].children.is_empty()) {
+                if slot < dir.children.len() && dir.children[slot].is_enterable() {
                     state.current_path.push(slot);
                     state.on_path_changed();
                     state.sync_parameters_pane();