From 668465042537856589a4f62d7a2e761abfe6b916 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 11 Nov 2026 00:01:48 -0800 Subject: [PATCH] Reshape: an empty focal list cannot be combined with radius path.reshape refused focal with radius only when focal named an anchor. Since an empty focal list chooses the focal-point rule, a call with "focal": [] and a radius was accepted and used the radius falloff, although the params text and docs/mcp.md say the two cannot be used together. Any focal other than null now goes with radius as an error. --- crates/engine/src/cmd/path.rs | 3 ++- crates/engine/src/tests.rs | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/engine/src/cmd/path.rs b/crates/engine/src/cmd/path.rs index 7d7d635c9..d00ba7192 100644 --- a/crates/engine/src/cmd/path.rs +++ b/crates/engine/src/cmd/path.rs @@ -1578,7 +1578,8 @@ fn reshape(s: &mut Session, p: &Value) -> Result { Some(v) if v.is_array() => super::select::checked_refs(Some(v), "path.reshape")?.into_iter().collect(), Some(_) => return Err(bad("path.reshape", "`focal` must be an array of [subpath, anchor] pairs")), }; - if radius.is_some() && !focal.is_empty() { + // An empty `focal` chooses the focal-point rule too. + if radius.is_some() && !matches!(p.get("focal"), None | Some(Value::Null)) { return Err(bad("path.reshape", "`focal` and `radius` cannot be used together")); } // A step that names neither `focal` nor `radius` (as the Reshape tool recorded one before it diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs index 5021c879f..9ad671843 100644 --- a/crates/engine/src/tests.rs +++ b/crates/engine/src/tests.rs @@ -3622,9 +3622,12 @@ fn reshape_refuses_a_focal_point_that_is_not_an_anchor() { } assert_eq!(reshape_anchors(&s, id), before); let steps = s.doc().unwrap().history.undo.len(); - let e = - s.execute("path.reshape", &json!({"id": id.0, "x": 420.0, "y": 0.0, "dx": 0.0, "dy": 10.0, "focal": [[0, 2]], "radius": 50.0})).unwrap_err(); - assert!(e.to_string().contains("`focal` and `radius` cannot be used together"), "{e}"); + // An empty `focal` chooses the focal-point rule too, so it cannot go with `radius` either. + for focal in [json!([[0, 2]]), json!([])] { + let e = + s.execute("path.reshape", &json!({"id": id.0, "x": 420.0, "y": 0.0, "dx": 0.0, "dy": 10.0, "focal": focal, "radius": 50.0})).unwrap_err(); + assert!(e.to_string().contains("`focal` and `radius` cannot be used together"), "{focal}: {e}"); + } assert_eq!(reshape_anchors(&s, id), before); assert_eq!(s.doc().unwrap().history.undo.len(), steps); }