orchestrator: Add the LockdownLatch terminal capability trait

The Effect::LatchLockdown executor has no capability seam. Add
LockdownLatch: a one-way latch into the platform safe state, a sticky
bit rather than an acquire/release lock. Ok only when the safe state is
in force; a failed latch is a hard fault the caller must treat as
terminal. Trait only; the platform driver composition follows
separately.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Christina Quast <christina.quast@9elements.com>
diff --git a/services/orchestrator/capabilities/BUILD.bazel b/services/orchestrator/capabilities/BUILD.bazel
index 859f7a9..c1c4d8e 100644
--- a/services/orchestrator/capabilities/BUILD.bazel
+++ b/services/orchestrator/capabilities/BUILD.bazel
@@ -10,6 +10,7 @@
         "src/boot_watch.rs",
         "src/evidence.rs",
         "src/lib.rs",
+        "src/lockdown_latch.rs",
         "src/svn_floor.rs",
     ],
     edition = "2024",
diff --git a/services/orchestrator/capabilities/src/lib.rs b/services/orchestrator/capabilities/src/lib.rs
index 0a721ea..cf71cde 100644
--- a/services/orchestrator/capabilities/src/lib.rs
+++ b/services/orchestrator/capabilities/src/lib.rs
@@ -19,6 +19,9 @@
 //! `BootWatch` is the seam the orchestrator polls: one device's boot walk,
 //! erased of every device-specific type, answering with a `WalkVerdict`.
 //!
+//! `LockdownLatch` is the terminal capability: latch the platform into its safe
+//! state, one-way, at the top of the escalation ladder.
+//!
 //! This crate is a dependency-free leaf: it holds the capability contracts,
 //! and everything depends downward on it. Concrete adapters bind a capability
 //! to a signal source and live in their own crates, so naming a capability
@@ -32,9 +35,11 @@
 mod boot_control;
 mod boot_watch;
 mod evidence;
+mod lockdown_latch;
 mod svn_floor;
 
 pub use boot_control::BootControl;
 pub use boot_watch::{BootWatch, FailureCause, WalkVerdict};
 pub use evidence::{BootStatus, EvidenceReader};
+pub use lockdown_latch::LockdownLatch;
 pub use svn_floor::{Svn, SvnFloor};
diff --git a/services/orchestrator/capabilities/src/lockdown_latch.rs b/services/orchestrator/capabilities/src/lockdown_latch.rs
new file mode 100644
index 0000000..f57686d
--- /dev/null
+++ b/services/orchestrator/capabilities/src/lockdown_latch.rs
@@ -0,0 +1,88 @@
+// Licensed under the Apache-2.0 license
+// SPDX-License-Identifier: Apache-2.0
+
+//! The [`LockdownLatch`] terminal safe-state capability contract.
+
+/// Latch capability: put the platform into its terminal safe state.
+///
+/// What the safe state is (gating every managed device, tripping a fuse,
+/// parking straps) is board wiring and never leaks through this seam.
+///
+/// The latch is one-way and idempotent: nothing short of a platform reset
+/// unlatches it, and latching an already-latched platform succeeds. `Ok`
+/// means the safe state is in force, not merely requested. A failed latch
+/// is a hard fault: `Err` means the safe state is not in force and the
+/// caller must not continue as if it were. How the platform escalates from
+/// there is board policy, outside this contract.
+pub trait LockdownLatch {
+    /// The error type of this platform's latch mechanism.
+    ///
+    /// Bounded by [`core::error::Error`] so the caller gets `Display` and a
+    /// `source()` cause chain. Error categories are implementation-defined.
+    type Error: core::error::Error;
+
+    /// Latches the platform into the safe state.
+    fn latch(&mut self) -> Result<(), Self::Error>;
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    // Implements LockdownLatch with no HAL dependency: the contract must be
+    // satisfiable from any stack (mock, IPC proxy, simulator). A HAL-bound
+    // `Error` type would stop this compiling.
+    struct MockLatch {
+        latched: bool,
+        fail: bool,
+    }
+
+    #[derive(Debug, PartialEq, Eq)]
+    struct MockFault;
+
+    impl core::fmt::Display for MockFault {
+        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+            f.write_str("mock latch fault")
+        }
+    }
+
+    impl core::error::Error for MockFault {}
+
+    impl LockdownLatch for MockLatch {
+        type Error = MockFault;
+
+        fn latch(&mut self) -> Result<(), MockFault> {
+            if self.fail {
+                return Err(MockFault);
+            }
+            self.latched = true;
+            Ok(())
+        }
+    }
+
+    #[test]
+    fn contract_is_implementable_without_the_hal() {
+        let mut dev = MockLatch {
+            latched: false,
+            fail: false,
+        };
+
+        dev.latch().expect("latch failed");
+        dev.latch().expect("repeated latch failed"); // idempotent
+
+        assert!(dev.latched);
+    }
+
+    #[test]
+    fn errors_surface_through_the_generic_seam() {
+        let mut dev = MockLatch {
+            latched: false,
+            fail: true,
+        };
+
+        let err = dev.latch().expect_err("expected the latch fault");
+
+        // Display comes from the core::error::Error bound, not a Debug dump.
+        assert_eq!(err.to_string(), "mock latch fault");
+    }
+}