fix(mission_runtime): full-uuid container names + assertion fix
ci / gates (push) Successful in 6s
ci / frontend (push) Successful in 26s
ci / rust (push) Successful in 3m20s
ci / e2e (push) Skipped
ci / publish (push) Successful in 4m5s

UUIDv7 encodes time in the leading bytes so 12-hex prefixes are
NOT unique across missions minted in the same second. Docker
accepts up to 253 chars; use the full uuid.
This commit is contained in:
Omar Sobh
2026-07-21 22:53:51 -07:00
parent bb5cfc1519
commit 5a1fcba403
+11 -11
View File
@@ -53,14 +53,13 @@ const EDGE_NETWORK: &str = "clawmates_edge";
/// by `clawmates-runtime.service`. /// by `clawmates-runtime.service`.
const MISSIONS_HOST_ROOT: &str = "/var/lib/clawmates-missions"; const MISSIONS_HOST_ROOT: &str = "/var/lib/clawmates-missions";
/// Deterministic docker container name for a mission's runtime. Short /// Deterministic docker container name for a mission's runtime.
/// enough to fit alongside project prefixes, unique per mission. /// Uses the full UUID hex — UUIDv7 encodes time in the leading bytes,
/// so a short prefix isn't guaranteed unique across missions minted
/// in the same second. Docker permits up to 253 characters in a name,
/// so the extra length is free.
pub fn container_name(mission_id: Uuid) -> String { pub fn container_name(mission_id: Uuid) -> String {
let hex = mission_id.simple().to_string(); format!("cm-runtime-mission-{}", mission_id.simple())
// 12 hex chars = 48 bits of the uuid — enough to avoid collision
// among the missions any single deployment will ever see, and
// short enough to keep container names glanceable in `docker ps`.
format!("cm-runtime-mission-{}", &hex[..12])
} }
/// Endpoint URL the topology_worker's ZeroClawDriveExecutor will dial. /// Endpoint URL the topology_worker's ZeroClawDriveExecutor will dial.
@@ -304,18 +303,19 @@ mod tests {
fn container_name_is_stable_and_prefixed() { fn container_name_is_stable_and_prefixed() {
let id = Uuid::parse_str("019f84a0-f2a2-7bd0-be9b-86713ec73693").unwrap(); let id = Uuid::parse_str("019f84a0-f2a2-7bd0-be9b-86713ec73693").unwrap();
let name = container_name(id); let name = container_name(id);
assert_eq!(name, "cm-runtime-mission-019f84a0f2a2"); assert_eq!(name, "cm-runtime-mission-019f84a0f2a27bd0be9b86713ec73693");
// Determinism: same input → same output. // Determinism: same input → same output.
assert_eq!(name, container_name(id)); assert_eq!(name, container_name(id));
} }
#[test] #[test]
fn container_names_differ_across_missions() { fn container_names_differ_across_missions() {
// Two UUIDs differing only in the trailing hex char — full-uuid
// naming must distinguish them (UUIDv7's timestamp shares
// leading bytes for missions minted in the same second).
let a = container_name(Uuid::parse_str("019f84a0-f2a2-7bd0-be9b-86713ec73693").unwrap()); let a = container_name(Uuid::parse_str("019f84a0-f2a2-7bd0-be9b-86713ec73693").unwrap());
let b = container_name(Uuid::parse_str("019f84a0-f2a2-7bd0-be9b-86713ec7369f").unwrap()); let b = container_name(Uuid::parse_str("019f84a0-f2a2-7bd0-be9b-86713ec7369f").unwrap());
// 12-char slug covers the leading bits, so different tails still assert_ne!(a, b);
// share prefix — this test guards the *choice* of slug length.
assert_ne!(a, b, "container name slug must include enough entropy");
} }
#[test] #[test]