Skip to main content

supercode_harness/
orchestrator.rs

1//! The orchestrator's home, its daemon lease, and the service unit the
2//! operator verbs print (ORC-7).
3//!
4//! supercode does not perform orchestration; the `supercode-orchestrator`
5//! package does (`docs/ORCHESTRATOR-IR.md` §0.1). This module holds the three
6//! facts supercode's own surfaces need about it:
7//!
8//! * **where its state lives** — `SUPERCODE_ORCHESTRATOR_HOME`, default
9//!   `~/.supercode/orchestrator`, resolved once in
10//!   [`crate::HarnessHomes::orchestrator`]; the root folder IS the `default`
11//!   profile and `profiles/<name>/` are the named ones
12//!   (`docs/ORCHESTRATOR-IR.md` §6).
13//! * **whether the daemon is up** — the lease file `<home>/orchestrator.lock`,
14//!   plus a liveness signal on the pid it names. A lock whose process is gone
15//!   is stale, never "up".
16//! * **what a service unit for it would say, and whether it is installed** —
17//!   [`service_unit`] renders the launchd plist / systemd unit `setup` writes
18//!   under `<home>/service/`; [`install_service`], [`uninstall_service`] and
19//!   [`service_status`] drive `launchctl` / `systemctl --user` over it.
20//!
21//! The lease FILE is written by the daemon itself (`bin/orchestrator.mjs`), not
22//! by this crate: one writer means a service-managed daemon reports the same
23//! lease a foreground one does, and a lock left by a process that is gone is
24//! the daemon's own signal to replay (§4.7).
25//!
26//! Reading the folder is every existing ORCH reader's job: `jobs`, `runs`,
27//! `routes`, `channels`, `triggers`, `profiles` and session discovery point
28//! their Hermes-shaped code paths at these same profile folders.
29
30use std::path::{Path, PathBuf};
31
32use serde::{Deserialize, Serialize};
33
34/// Lease file the daemon writes while it serves a home, relative to the home.
35pub const LOCK_FILE: &str = "orchestrator.lock";
36
37/// Directory `setup` writes the rendered service unit into.
38pub const SERVICE_DIR: &str = "service";
39
40/// The daemon entry inside the `sdk/orchestrator` package.
41pub const DAEMON_ENTRY: &str = "bin/orchestrator.mjs";
42
43/// launchd label / systemd unit name for the orchestrator daemon.
44pub const SERVICE_NAME: &str = "ai.volter.supercode.orchestrator";
45
46/// The lease `<home>/orchestrator.lock` holds: which process is serving this
47/// home, and since when.
48#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
49pub struct Lease {
50    /// Daemon process id.
51    pub pid: u32,
52    /// RFC3339 instant the daemon recorded at startup.
53    pub started_at: String,
54    /// The home the daemon was started against.
55    pub root: PathBuf,
56    /// The machine the daemon runs on. A home on a volume another machine
57    /// mounted names that machine's pid, which says nothing about this one.
58    #[serde(default, skip_serializing_if = "Option::is_none")]
59    pub host: Option<String>,
60    /// That machine's boot (Linux's `boot_id`), where it has one: a pid from
61    /// before a restart names nothing now.
62    #[serde(default, skip_serializing_if = "Option::is_none")]
63    pub boot: Option<String>,
64}
65
66impl Lease {
67    /// Whether the daemon this lease names is alive: on this machine, since
68    /// this boot, and its pid a live process. A lease from elsewhere is never
69    /// live here, so nothing here is signalled on its word.
70    pub fn is_live(&self) -> bool {
71        let here = this_host();
72        if self
73            .host
74            .as_deref()
75            .is_some_and(|host| Some(host) != here.0.as_deref())
76        {
77            return false;
78        }
79        if let (Some(boot), Some(now)) = (self.boot.as_deref(), here.1.as_deref()) {
80            if boot != now {
81                return false;
82            }
83        }
84        pid_is_live(self.pid)
85    }
86}
87
88/// This machine's name and, on Linux, its boot id: what a lease is compared with.
89pub fn this_host() -> (Option<String>, Option<String>) {
90    let boot = std::fs::read_to_string("/proc/sys/kernel/random/boot_id")
91        .ok()
92        .map(|text| text.trim().to_string())
93        .filter(|text| !text.is_empty());
94    (hostname(), boot)
95}
96
97fn hostname() -> Option<String> {
98    #[cfg(unix)]
99    {
100        let mut buffer = [0u8; 256];
101        // SAFETY: the buffer outlives the call and its length is passed.
102        let status = unsafe { libc::gethostname(buffer.as_mut_ptr().cast(), buffer.len()) };
103        if status != 0 {
104            return None;
105        }
106        let end = buffer
107            .iter()
108            .position(|byte| *byte == 0)
109            .unwrap_or(buffer.len());
110        String::from_utf8(buffer[..end].to_vec())
111            .ok()
112            .filter(|name| !name.is_empty())
113    }
114    #[cfg(not(unix))]
115    {
116        std::env::var("COMPUTERNAME").ok()
117    }
118}
119
120/// Why an operator verb could not do its work.
121#[derive(Debug, thiserror::Error)]
122pub enum OrchestratorError {
123    /// No lease file, or one that no longer names a live process.
124    #[error("the orchestrator is not running for `{0}` (no live lease at `{1}`)", root.display(), lock.display())]
125    NotRunning {
126        /// The home that was asked about.
127        root: PathBuf,
128        /// Where its lease would be.
129        lock: PathBuf,
130    },
131    /// A lease exists and its process is alive.
132    #[error("the orchestrator is already running for `{}` (pid {pid})", root.display())]
133    AlreadyRunning {
134        /// The home that was asked about.
135        root: PathBuf,
136        /// The live daemon's pid.
137        pid: u32,
138    },
139    /// The Node daemon entry could not be located.
140    #[error("no orchestrator daemon entry found (looked for `{DAEMON_ENTRY}` under: {searched})")]
141    NoDaemonEntry {
142        /// The candidate roots that were searched, joined.
143        searched: String,
144    },
145    /// The lease file could not be read or written.
146    #[error("orchestrator lease `{}`: {source}", path.display())]
147    Lease {
148        /// The lease path.
149        path: PathBuf,
150        /// The underlying I/O failure.
151        source: std::io::Error,
152    },
153    /// A service manager refused, or there is none on this platform.
154    #[error("orchestrator service: {action} failed: {detail}")]
155    Service {
156        /// What was attempted (`install`, `uninstall`).
157        action: &'static str,
158        /// What the service manager (or this module) said about it.
159        detail: String,
160    },
161}
162
163/// The lease path for one home.
164pub fn lock_path(root: &Path) -> PathBuf {
165    root.join(LOCK_FILE)
166}
167
168/// Read the lease, whether or not its process is still alive.
169pub fn read_lease(root: &Path) -> Option<Lease> {
170    let text = std::fs::read_to_string(lock_path(root)).ok()?;
171    serde_json::from_str(&text).ok()
172}
173
174/// Write the lease for a running daemon.
175pub fn write_lease(root: &Path, lease: &Lease) -> Result<(), OrchestratorError> {
176    let path = lock_path(root);
177    if let Some(parent) = path.parent() {
178        std::fs::create_dir_all(parent).map_err(|source| OrchestratorError::Lease {
179            path: path.clone(),
180            source,
181        })?;
182    }
183    let text = serde_json::to_string_pretty(lease).unwrap_or_default();
184    std::fs::write(&path, format!("{text}\n")).map_err(|source| OrchestratorError::Lease {
185        path: path.clone(),
186        source,
187    })
188}
189
190/// Remove the lease file. A missing file is not an error — `stop` is
191/// idempotent by design.
192pub fn clear_lease(root: &Path) -> Result<(), OrchestratorError> {
193    let path = lock_path(root);
194    match std::fs::remove_file(&path) {
195        Ok(()) => Ok(()),
196        Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
197        Err(source) => Err(OrchestratorError::Lease { path, source }),
198    }
199}
200
201/// Whether `pid` is a live process this user can signal.
202///
203/// `kill(pid, 0)` is the liveness question POSIX answers without touching the
204/// process. On a non-unix target there is no equivalent that does not start
205/// something, so the lease alone is the answer.
206pub fn pid_is_live(pid: u32) -> bool {
207    #[cfg(unix)]
208    {
209        if pid == 0 {
210            return false;
211        }
212        // SAFETY: signal 0 performs error checking only; it delivers nothing.
213        unsafe { libc::kill(pid as libc::pid_t, 0) == 0 }
214    }
215    #[cfg(not(unix))]
216    {
217        let _ = pid;
218        true
219    }
220}
221
222/// The lease of a daemon that is actually alive right now.
223pub fn live_lease(root: &Path) -> Option<Lease> {
224    read_lease(root).filter(Lease::is_live)
225}
226
227/// Ask the daemon to stop: SIGTERM to the leased pid, then clear the lease.
228///
229/// The daemon's own SIGTERM handler is what closes its adapters; this never
230/// escalates to SIGKILL and never signals anything but the pid the lease
231/// names.
232pub fn stop(root: &Path) -> Result<Lease, OrchestratorError> {
233    let Some(lease) = live_lease(root) else {
234        return Err(OrchestratorError::NotRunning {
235            root: root.to_path_buf(),
236            lock: lock_path(root),
237        });
238    };
239    #[cfg(unix)]
240    // SAFETY: the pid comes from this home's own lease and is known live.
241    unsafe {
242        libc::kill(lease.pid as libc::pid_t, libc::SIGTERM);
243    }
244    clear_lease(root)?;
245    Ok(lease)
246}
247
248/// Locate the Node daemon entry (`sdk/orchestrator/bin/orchestrator.mjs`).
249///
250/// Candidates, in order: `SUPERCODE_ORCHESTRATOR_ENTRY` (an explicit
251/// override, which is also how a test points at a fake), the published
252/// package's `supercode-orchestrator` command on PATH (what `npm install -g
253/// @volter-ai-dev/supercode-orchestrator` puts there), the repo checkout the
254/// running binary sits in, and the current directory's `sdk/orchestrator`.
255pub fn daemon_entry() -> Result<PathBuf, OrchestratorError> {
256    let mut searched = Vec::new();
257    if let Some(explicit) = std::env::var_os("SUPERCODE_ORCHESTRATOR_ENTRY") {
258        let path = PathBuf::from(explicit);
259        if path.is_file() {
260            return Ok(path);
261        }
262        searched.push(path.display().to_string());
263    }
264    // An installed binary has no checkout beside it: the orchestrator is its
265    // own package, and npm links its daemon entry onto PATH by that name.
266    for dir in std::env::var_os("PATH")
267        .iter()
268        .flat_map(std::env::split_paths)
269    {
270        let command = dir.join("supercode-orchestrator");
271        if let Ok(entry) = std::fs::canonicalize(&command) {
272            if entry.is_file() && entry.ends_with(DAEMON_ENTRY) {
273                return Ok(entry);
274            }
275        }
276    }
277    searched.push("supercode-orchestrator on PATH".to_string());
278    let mut roots: Vec<PathBuf> = Vec::new();
279    if let Ok(exe) = std::env::current_exe() {
280        // target/<profile>/supercode → the workspace root is two levels up.
281        roots.extend(exe.ancestors().skip(1).take(4).map(Path::to_path_buf));
282    }
283    if let Ok(cwd) = std::env::current_dir() {
284        roots.push(cwd);
285    }
286    // A locally built binary's target directory can live anywhere (a shared
287    // cargo build dir, another volume), so the checkout it was built from is
288    // the last candidate. On an installed binary this path simply does not
289    // exist and is skipped like any other miss.
290    if let Some(workspace) = Path::new(env!("CARGO_MANIFEST_DIR")).ancestors().nth(2) {
291        roots.push(workspace.to_path_buf());
292    }
293    for root in roots {
294        let candidate = root.join("sdk/orchestrator").join(DAEMON_ENTRY);
295        if candidate.is_file() {
296            return Ok(candidate);
297        }
298        searched.push(candidate.display().to_string());
299    }
300    Err(OrchestratorError::NoDaemonEntry {
301        searched: searched.join(", "),
302    })
303}
304
305/// A rendered service unit: what `setup` prints and writes.
306#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
307pub struct ServiceUnit {
308    /// `launchd` or `systemd`.
309    pub kind: &'static str,
310    /// Where `setup` writes the rendered text under `<home>/service/`.
311    pub path: PathBuf,
312    /// The unit text itself.
313    pub text: String,
314    /// The command an operator (or ORC-10) runs to install it.
315    pub install_command: String,
316}
317
318/// Render the per-platform service unit for one home.
319///
320/// Nothing is installed here: ORC-10 owns installation. `setup` writes this
321/// text under `<home>/service/` so the operator can read exactly what would
322/// be installed before anything registers a daemon.
323pub fn service_unit(root: &Path, entry: &Path, node: &str) -> ServiceUnit {
324    let root_display = root.display().to_string();
325    let entry_display = entry.display().to_string();
326    if cfg!(target_os = "macos") {
327        let path = root.join(SERVICE_DIR).join(format!("{SERVICE_NAME}.plist"));
328        let text = format!(
329            r#"<?xml version="1.0" encoding="UTF-8"?>
330<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
331<plist version="1.0">
332<dict>
333  <key>Label</key><string>{SERVICE_NAME}</string>
334  <key>ProgramArguments</key>
335  <array>
336    <string>{node}</string>
337    <string>{entry_display}</string>
338    <string>--root</string>
339    <string>{root_display}</string>
340  </array>
341  <key>RunAtLoad</key><true/>
342  <key>KeepAlive</key><true/>
343  <key>StandardOutPath</key><string>{root_display}/service/orchestrator.out.log</string>
344  <key>StandardErrorPath</key><string>{root_display}/service/orchestrator.err.log</string>
345</dict>
346</plist>
347"#
348        );
349        let install = format!("launchctl bootstrap gui/$(id -u) {}", path.display());
350        ServiceUnit {
351            kind: "launchd",
352            path,
353            text,
354            install_command: install,
355        }
356    } else {
357        let path = root
358            .join(SERVICE_DIR)
359            .join(format!("{SERVICE_NAME}.service"));
360        let text = format!(
361            "[Unit]\n\
362             Description=supercode orchestrator ({root_display})\n\
363             After=network.target\n\
364             \n\
365             [Service]\n\
366             ExecStart={node} {entry_display} --root {root_display}\n\
367             Restart=on-failure\n\
368             KillSignal=SIGTERM\n\
369             \n\
370             [Install]\n\
371             WantedBy=default.target\n"
372        );
373        let install = format!(
374            "systemctl --user link {} && systemctl --user enable --now {SERVICE_NAME}",
375            path.display()
376        );
377        ServiceUnit {
378            kind: "systemd",
379            path,
380            text,
381            install_command: install,
382        }
383    }
384}
385
386/// What the platform's service manager says about the orchestrator unit.
387#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
388pub struct ServiceState {
389    /// `launchd`, `systemd`, or `none` where neither is available.
390    pub kind: &'static str,
391    /// The label / unit name asked about.
392    pub label: String,
393    /// Whether the service manager holds the unit at all.
394    pub installed: bool,
395    /// The daemon's pid, where the service manager knows it.
396    pub pid: Option<u32>,
397    /// The manager's own words, or why the question could not be asked.
398    pub detail: String,
399}
400
401/// launchd and systemd start a unit with a minimal `PATH`, so the unit names
402/// the interpreter absolutely wherever one can be resolved.
403pub fn absolute_program(program: &str) -> String {
404    if program.contains('/') {
405        return program.to_string();
406    }
407    if let Some(path) = std::env::var_os("PATH") {
408        for dir in std::env::split_paths(&path) {
409            let candidate = dir.join(program);
410            if candidate.is_file() {
411                return candidate.display().to_string();
412            }
413        }
414    }
415    program.to_string()
416}
417
418/// Run a service-manager command and return (success, stdout+stderr).
419fn run_tool(program: &str, args: &[&str]) -> Result<(bool, String), std::io::Error> {
420    let output = std::process::Command::new(program).args(args).output()?;
421    let mut text = String::from_utf8_lossy(&output.stdout).into_owned();
422    text.push_str(&String::from_utf8_lossy(&output.stderr));
423    Ok((output.status.success(), text.trim().to_string()))
424}
425
426#[cfg(target_os = "macos")]
427fn gui_domain() -> String {
428    // SAFETY: `getuid` reads this process's own real user id and cannot fail.
429    format!("gui/{}", unsafe { libc::getuid() })
430}
431
432/// Ask the platform's service manager about the orchestrator unit.
433///
434/// Never starts or installs anything: `status` calls this on every run.
435pub fn service_status(root: &Path) -> ServiceState {
436    platform_status(root)
437}
438
439#[cfg(target_os = "macos")]
440fn platform_status(_root: &Path) -> ServiceState {
441    let label = SERVICE_NAME.to_string();
442    let target = format!("{}/{SERVICE_NAME}", gui_domain());
443    match run_tool("launchctl", &["print", &target]) {
444        Ok((true, text)) => ServiceState {
445            kind: "launchd",
446            label,
447            installed: true,
448            pid: field_of(&text, "pid = ").and_then(|value| value.parse().ok()),
449            detail: field_of(&text, "state = ").unwrap_or_else(|| "loaded".into()),
450        },
451        Ok((false, _)) => ServiceState {
452            kind: "launchd",
453            label,
454            installed: false,
455            pid: None,
456            detail: format!("not bootstrapped in {}", gui_domain()),
457        },
458        Err(error) => ServiceState {
459            kind: "launchd",
460            label,
461            installed: false,
462            pid: None,
463            detail: format!("launchctl unavailable: {error}"),
464        },
465    }
466}
467
468#[cfg(all(unix, not(target_os = "macos")))]
469fn platform_status(_root: &Path) -> ServiceState {
470    let label = SERVICE_NAME.to_string();
471    match run_tool("systemctl", &["--user", "is-active", SERVICE_NAME]) {
472        Ok((active, text)) => {
473            let known = run_tool("systemctl", &["--user", "is-enabled", SERVICE_NAME])
474                .map(|(ok, _)| ok)
475                .unwrap_or(false);
476            ServiceState {
477                kind: "systemd",
478                label,
479                installed: active || known,
480                pid: None,
481                detail: if text.is_empty() {
482                    "unknown".into()
483                } else {
484                    text
485                },
486            }
487        }
488        Err(error) => ServiceState {
489            kind: "systemd",
490            label,
491            installed: false,
492            pid: None,
493            detail: format!("systemctl unavailable: {error}"),
494        },
495    }
496}
497
498#[cfg(not(unix))]
499fn platform_status(_root: &Path) -> ServiceState {
500    ServiceState {
501        kind: "none",
502        label: SERVICE_NAME.to_string(),
503        installed: false,
504        pid: None,
505        detail: "no service manager on this platform".into(),
506    }
507}
508
509/// `key = value` out of a service manager's block output.
510#[cfg(target_os = "macos")]
511fn field_of(text: &str, key: &str) -> Option<String> {
512    text.lines()
513        .find_map(|line| line.trim().strip_prefix(key))
514        .map(|value| value.trim().to_string())
515}
516
517/// Render the unit, hand it to the platform's service manager, and start it.
518///
519/// Refuses a label the manager already holds rather than replacing it: two
520/// homes share one label, so an install that silently took it over would point
521/// a running service at a different folder.
522pub fn install_service(
523    root: &Path,
524    entry: &Path,
525    node: &str,
526) -> Result<(ServiceUnit, ServiceState), OrchestratorError> {
527    let existing = service_status(root);
528    if existing.installed {
529        return Err(OrchestratorError::Service {
530            action: "install",
531            detail: format!(
532                "`{}` is already installed ({}); `supercode orchestrator setup --uninstall` first",
533                existing.label, existing.detail
534            ),
535        });
536    }
537    let unit = service_unit(root, entry, &absolute_program(node));
538    write_unit(&unit)?;
539    platform_install(&unit)?;
540    Ok((unit, service_status(root)))
541}
542
543#[cfg(target_os = "macos")]
544fn platform_install(unit: &ServiceUnit) -> Result<(), OrchestratorError> {
545    let path = unit.path.display().to_string();
546    let (ok, text) =
547        run_tool("launchctl", &["bootstrap", &gui_domain(), &path]).map_err(|error| {
548            OrchestratorError::Service {
549                action: "install",
550                detail: format!("launchctl: {error}"),
551            }
552        })?;
553    if !ok {
554        return Err(OrchestratorError::Service {
555            action: "install",
556            detail: format!("launchctl bootstrap {}: {text}", gui_domain()),
557        });
558    }
559    Ok(())
560}
561
562/// Untested on this box (the receipt is macOS); these are the commands
563/// `service_unit` has always printed as its `install_command`.
564#[cfg(all(unix, not(target_os = "macos")))]
565fn platform_install(unit: &ServiceUnit) -> Result<(), OrchestratorError> {
566    let path = unit.path.display().to_string();
567    for args in [
568        vec!["--user", "link", path.as_str()],
569        vec!["--user", "enable", "--now", SERVICE_NAME],
570    ] {
571        let (ok, text) =
572            run_tool("systemctl", &args).map_err(|error| OrchestratorError::Service {
573                action: "install",
574                detail: format!("systemctl: {error}"),
575            })?;
576        if !ok {
577            return Err(OrchestratorError::Service {
578                action: "install",
579                detail: format!("systemctl {}: {text}", args.join(" ")),
580            });
581        }
582    }
583    Ok(())
584}
585
586#[cfg(not(unix))]
587fn platform_install(_unit: &ServiceUnit) -> Result<(), OrchestratorError> {
588    Err(OrchestratorError::Service {
589        action: "install",
590        detail: "no service manager on this platform".into(),
591    })
592}
593
594/// Stop and unregister the unit, and remove the rendered file `setup` wrote.
595///
596/// Idempotent: a unit the manager does not hold is not an error, because the
597/// state the operator asked for is the state they get.
598pub fn uninstall_service(root: &Path) -> Result<ServiceState, OrchestratorError> {
599    platform_uninstall()?;
600    let unit_path = root.join(SERVICE_DIR).join(unit_file_name());
601    match std::fs::remove_file(&unit_path) {
602        Ok(()) => {}
603        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
604        Err(source) => {
605            return Err(OrchestratorError::Lease {
606                path: unit_path,
607                source,
608            })
609        }
610    }
611    // `launchctl bootout` returns before the job is torn down, so the state
612    // this reports is the settled one, not the manager mid-teardown.
613    let mut state = service_status(root);
614    for _ in 0..40 {
615        if !state.installed {
616            break;
617        }
618        std::thread::sleep(std::time::Duration::from_millis(100));
619        state = service_status(root);
620    }
621    Ok(state)
622}
623
624#[cfg(target_os = "macos")]
625fn platform_uninstall() -> Result<(), OrchestratorError> {
626    let target = format!("{}/{SERVICE_NAME}", gui_domain());
627    let (ok, text) = run_tool("launchctl", &["bootout", &target]).map_err(|error| {
628        OrchestratorError::Service {
629            action: "uninstall",
630            detail: format!("launchctl: {error}"),
631        }
632    })?;
633    // `bootout` on a label nobody holds says so and exits non-zero.
634    if !ok && !text.contains("No such process") && !text.contains("not find") {
635        return Err(OrchestratorError::Service {
636            action: "uninstall",
637            detail: format!("launchctl bootout {target}: {text}"),
638        });
639    }
640    Ok(())
641}
642
643#[cfg(all(unix, not(target_os = "macos")))]
644fn platform_uninstall() -> Result<(), OrchestratorError> {
645    let _ = run_tool("systemctl", &["--user", "disable", "--now", SERVICE_NAME]);
646    Ok(())
647}
648
649#[cfg(not(unix))]
650fn platform_uninstall() -> Result<(), OrchestratorError> {
651    Ok(())
652}
653
654/// The file name `service_unit` renders for this platform.
655fn unit_file_name() -> String {
656    if cfg!(target_os = "macos") {
657        format!("{SERVICE_NAME}.plist")
658    } else {
659        format!("{SERVICE_NAME}.service")
660    }
661}
662
663/// Write a rendered unit under `<home>/service/`.
664pub fn write_unit(unit: &ServiceUnit) -> Result<(), OrchestratorError> {
665    if let Some(parent) = unit.path.parent() {
666        std::fs::create_dir_all(parent).map_err(|source| OrchestratorError::Lease {
667            path: unit.path.clone(),
668            source,
669        })?;
670    }
671    std::fs::write(&unit.path, &unit.text).map_err(|source| OrchestratorError::Lease {
672        path: unit.path.clone(),
673        source,
674    })
675}
676
677#[cfg(test)]
678mod tests {
679    use super::*;
680
681    /// A scratch home for one test, removed by the test that made it.
682    fn scratch(label: &str) -> PathBuf {
683        let root = std::env::temp_dir().join(format!(
684            "supercode-orchestrator-{label}-{}-{}",
685            std::process::id(),
686            std::time::SystemTime::now()
687                .duration_since(std::time::UNIX_EPOCH)
688                .unwrap()
689                .as_nanos()
690        ));
691        std::fs::create_dir_all(&root).unwrap();
692        root
693    }
694
695    #[test]
696    fn a_lease_round_trips_and_a_missing_one_is_not_running() {
697        let root = &scratch("lease");
698        let root = root.as_path();
699        assert!(read_lease(root).is_none());
700        assert!(live_lease(root).is_none());
701        let lease = Lease {
702            pid: std::process::id(),
703            started_at: "2026-09-04T00:00:00Z".into(),
704            root: root.to_path_buf(),
705            host: None,
706            boot: None,
707        };
708        write_lease(root, &lease).unwrap();
709        assert_eq!(read_lease(root).as_ref(), Some(&lease));
710        // This process is alive, so its own lease reads as live.
711        assert!(live_lease(root).is_some());
712        clear_lease(root).unwrap();
713        assert!(read_lease(root).is_none());
714        // `stop` on a home with no lease refuses by name.
715        assert!(matches!(
716            stop(root),
717            Err(OrchestratorError::NotRunning { .. })
718        ));
719        std::fs::remove_dir_all(root).ok();
720    }
721
722    /// A lease whose process is gone is STALE: `status` must say down, not
723    /// inherit the file's claim.
724    #[test]
725    fn a_stale_lease_is_not_live() {
726        let root = &scratch("stale");
727        let root = root.as_path();
728        write_lease(
729            root,
730            &Lease {
731                // A pid no process can hold (max_pid is far below this).
732                pid: 0x7FFF_FFFF,
733                started_at: "2026-09-04T00:00:00Z".into(),
734                root: root.to_path_buf(),
735                host: None,
736                boot: None,
737            },
738        )
739        .unwrap();
740        assert!(read_lease(root).is_some(), "the file is still there");
741        assert!(live_lease(root).is_none(), "but nothing is serving it");
742        std::fs::remove_dir_all(root).ok();
743    }
744
745    #[test]
746    fn the_service_unit_names_the_home_the_entry_and_its_install_command() {
747        let root = &scratch("unit");
748        let root = root.as_path();
749        let entry = PathBuf::from("/opt/supercode/sdk/orchestrator/bin/orchestrator.mjs");
750        let unit = service_unit(root, &entry, "/usr/bin/node");
751        assert!(unit.text.contains(&root.display().to_string()));
752        assert!(unit.text.contains("orchestrator.mjs"));
753        assert!(unit.text.contains(SERVICE_NAME));
754        assert!(unit
755            .install_command
756            .contains(&unit.path.display().to_string()));
757        assert!(unit.path.starts_with(root.join(SERVICE_DIR)));
758        assert_eq!(
759            unit.kind,
760            if cfg!(target_os = "macos") {
761                "launchd"
762            } else {
763                "systemd"
764            }
765        );
766        std::fs::remove_dir_all(root).ok();
767    }
768
769    /// Asking the service manager is a READ: `status` calls it on every run,
770    /// and must never register or render anything on the way.
771    #[test]
772    fn service_status_reports_the_label_and_installs_nothing() {
773        let root = &scratch("service-status");
774        let root = root.as_path();
775        let state = service_status(root);
776        assert_eq!(state.label, SERVICE_NAME);
777        assert!(
778            matches!(state.kind, "launchd" | "systemd" | "none"),
779            "{state:?}"
780        );
781        assert!(
782            !root.join(SERVICE_DIR).exists(),
783            "asking never writes a unit"
784        );
785        std::fs::remove_dir_all(root).ok();
786    }
787
788    /// launchd and systemd start a unit with a minimal PATH, so a bare program
789    /// name in the unit would not resolve at boot.
790    #[test]
791    fn a_program_is_resolved_absolutely_for_the_service_manager() {
792        assert_eq!(absolute_program("/usr/bin/env"), "/usr/bin/env");
793        let resolved = absolute_program("sh");
794        assert!(resolved.starts_with('/'), "{resolved}");
795        // an unresolvable name is left as it was, for the manager to refuse
796        assert_eq!(
797            absolute_program("definitely-not-a-program"),
798            "definitely-not-a-program"
799        );
800    }
801
802    /// The entry resolver must find the package in this checkout — the
803    /// `start` verb has nothing to spawn otherwise.
804    #[test]
805    fn the_daemon_entry_resolves_in_this_checkout() {
806        let entry = daemon_entry().expect("sdk/orchestrator/bin/orchestrator.mjs");
807        assert!(entry.ends_with(DAEMON_ENTRY));
808    }
809}