orchestrator: Reject duplicate checkpoint names; pin max_retries=0 meaning

Failure reports identify a checkpoint by name, so a duplicate within a
device would make them ambiguous — validate now rejects it at build
time (str comparison by hand: == on &str is not const). Also state
explicitly that max_retries=0 means the one attempt is all the device
gets.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Christina Quast <christina.quast@9elements.com>
diff --git a/services/orchestrator/config/src/lib.rs b/services/orchestrator/config/src/lib.rs
index f3c8b02..2a63cc6 100644
--- a/services/orchestrator/config/src/lib.rs
+++ b/services/orchestrator/config/src/lib.rs
@@ -41,6 +41,7 @@
     /// orchestrator's own judgment; hung devices report nothing.
     pub timeout: core::time::Duration,
     /// Attempts allowed beyond the first before the failure is final.
+    /// `0` means the one attempt is all the device gets.
     pub max_retries: u8,
 }
 
@@ -90,12 +91,41 @@
                 !devices[i].checkpoints[c].timeout.is_zero(),
                 "checkpoint timeout must not be zero"
             );
+            // Failure reports identify a checkpoint by name; a duplicate
+            // would make them ambiguous.
+            let mut d = c + 1;
+            while d < devices[i].checkpoints.len() {
+                assert!(
+                    !str_eq(
+                        devices[i].checkpoints[c].name,
+                        devices[i].checkpoints[d].name
+                    ),
+                    "checkpoint names must be unique per device"
+                );
+                d += 1;
+            }
             c += 1;
         }
         i += 1;
     }
 }
 
+// `==` on `&str` is not const; compare bytes by hand.
+const fn str_eq(a: &str, b: &str) -> bool {
+    let (a, b) = (a.as_bytes(), b.as_bytes());
+    if a.len() != b.len() {
+        return false;
+    }
+    let mut i = 0;
+    while i < a.len() {
+        if a[i] != b[i] {
+            return false;
+        }
+        i += 1;
+    }
+    true
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -126,6 +156,21 @@
     }
 
     #[test]
+    #[should_panic(expected = "checkpoint names must be unique")]
+    fn rejects_duplicate_checkpoint_names() {
+        validate(&[DeviceConfig {
+            checkpoints: &[
+                CHECKPOINT,
+                BootCheckpoint {
+                    signal: 1,
+                    ..CHECKPOINT
+                },
+            ],
+            ..DEVICE
+        }]);
+    }
+
+    #[test]
     #[should_panic(expected = "device name must not be empty")]
     fn rejects_an_empty_device_name() {
         validate(&[DEVICE, DeviceConfig { name: "", ..DEVICE }]);