fix: treat single node with children as one sequence element
A single node with non-dash children was deserialized as multiple
sequence elements (one per child). This broke single-element
vec-of-structs, where the node itself should be the sole element
with its children as struct fields. The `-` convention remains
the correct way to express child-based sequences.

Assisted-by: Claude Opus 4.6 via pi
change pmtwoklnszpyvtptlnnupnxvtzwtnrsp
commit 1c9e2bcecf7ccd43049e42c9b555e08ba465e113
author Alpha Chen <alpha@kejadlen.dev>
date
parent smrouxkk
diff --git a/src/de.rs b/src/de.rs
index 6689757..e6d6779 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -353,8 +353,8 @@ impl<'de, 'a> de::Deserializer<'de> for FieldDeserializer<'a> {
         // Strategy:
         // 1. Multiple nodes with same name → each node is an element
         // 2. Single node with `-` children → each `-` child is an element
-        // 3. Single node with multiple args → each arg is an element
-        // 4. Single node with non-`-` children → children nodes are elements
+        // 3. Single node with children → single-element sequence (the node itself)
+        // 4. Single node with multiple args → each arg is an element
 
         if self.nodes.len() > 1 {
             // Multiple nodes → each node contributes one element
@@ -378,17 +378,16 @@ impl<'de, 'a> de::Deserializer<'de> for FieldDeserializer<'a> {
                         index: 0,
                     });
                 }
-                // Non-dash children: treat each child as an element
-                let child_nodes: Vec<&KdlNode> = children.nodes().iter().collect();
-                if !child_nodes.is_empty() {
-                    return visitor.visit_seq(ChildNodeSeqAccess {
-                        nodes: child_nodes,
+                // Single node with non-empty children → treat node as single element
+                if !children.nodes().is_empty() {
+                    return visitor.visit_seq(MultiNodeSeqAccess {
+                        nodes: self.nodes,
                         index: 0,
                     });
                 }
             }
 
-            // Arguments as elements
+            // Arguments as elements (or empty seq if no args)
             let args = node_args(node);
             visitor.visit_seq(ArgsSeqAccess { args, index: 0 })
         }
diff --git a/tests/integration.rs b/tests/integration.rs
index 98d0ad1..377cb86 100644
--- a/tests/integration.rs
+++ b/tests/integration.rs
@@ -1493,15 +1493,17 @@ deser_field!(
 );
 
 // ── Non-dash children as sequence ──────────────────────────────────────
+// A single node with children is treated as a single-element sequence,
+// not as individual elements. Use `-` convention for child elements.
 
 deser_field!(
     deserialize_children_as_sequence,
     items: Vec<i32>,
     indoc! {"
         items {
-            item 1
-            item 2
-            item 3
+            - 1
+            - 2
+            - 3
         }
     "},
     vec![1, 2, 3]
diff --git a/tests/integration_collections.rs b/tests/integration_collections.rs
index 01a1fc0..9c70db2 100644
--- a/tests/integration_collections.rs
+++ b/tests/integration_collections.rs
@@ -129,6 +129,36 @@ roundtrip!(
     }
 );
 
+// ── Single-element vec of structs ──────────────────────────────────────
+
+deser_ok!(
+    deserialize_single_element_vec_structs,
+    Cluster,
+    indoc! {r#"
+        server {
+            host "localhost"
+            port 8080
+        }
+    "#},
+    Cluster {
+        server: vec![Server {
+            host: "localhost".into(),
+            port: 8080,
+        }],
+    }
+);
+
+roundtrip!(
+    roundtrip_single_element_vec_structs,
+    Cluster,
+    Cluster {
+        server: vec![Server {
+            host: "localhost".into(),
+            port: 8080,
+        }],
+    }
+);
+
 // ── Dash children ──────────────────────────────────────────────────────
 
 deser_field!(