Deviation: REQUIRES is a hard dependency — "Required services are started first; if required service fails to become healthy, dependent does not start." On launchd and orchdi, a REQUIRES dep without a HEALTHCHECK produces no readiness gate and no enforcement at all.
src/orchdi.rs::build_dep_gates():
for (names, required) in [(&service.requires, true), (&service.after, false)] {
for dep_name in names {
if let Some(dep) = lookup(dep_name) {
if let Some(hc) = &dep.healthcheck { // skipped when no healthcheck
gates.push(...)
}
}
}
}
A REQUIRES dep with no healthcheck → no DepGate, so the supervisor starts the dependent with no requirement check. This ties back to the root-cause issue: the "started" readiness signal is missing, so the requirement is only expressible via healthcheck.
On systemd the requirement holds even without a healthcheck (REQUIRES emits BindsTo+After unconditionally), so this is a launchd/orchdi-specific gap.
Fix: per the root-cause issue — gate every dependency on start/completion first, and layer the healthcheck poll on top when present. A REQUIRES dep must at least have a start/completion gate.
Deviation:
REQUIRESis a hard dependency — "Required services are started first; if required service fails to become healthy, dependent does not start." On launchd and orchdi, a REQUIRES dep without aHEALTHCHECKproduces no readiness gate and no enforcement at all.src/orchdi.rs::build_dep_gates():A REQUIRES dep with no healthcheck → no
DepGate, so the supervisor starts the dependent with no requirement check. This ties back to the root-cause issue: the "started" readiness signal is missing, so the requirement is only expressible via healthcheck.On systemd the requirement holds even without a healthcheck (REQUIRES emits
BindsTo+Afterunconditionally), so this is a launchd/orchdi-specific gap.Fix: per the root-cause issue — gate every dependency on start/completion first, and layer the healthcheck poll on top when present. A REQUIRES dep must at least have a start/completion gate.