When ensure refuses
ensure refuses
stado service ensure is idempotent and honest: each of its refusals in the
field names its own repair.
- A per-login unit on a headless Mac. The declaration puts the unit in
launchd's user domain on a Mac whose recorded console is headless
(
stado host console record), where macOS's questions to an agent are never answered and, with nobody logged in, launchd builds nogui/<uid>. The finding is printed as one sentence ending in the command that moves the unit (stado service ensure <name> --host <host> --as-daemon --reason …), which stops the agent, reads the daemon until it answers, and only then removes the agent's file.stado service listandstado registry doctorreport the same finding before any restart trips over it. - A LaunchAgent loaded in the background domain. When the account does
not hold a graphical session, a LaunchAgent goes to
user/<uid>, and the report says why:<account> does not own /dev/console (it belongs to <owner>), or(it cannot be read (<stat's words>))when the console's owner could not be read, or<account> owns /dev/console but launchd answers no gui/<uid>. An unreadable console is never reported as one belonging to nobody. - A loaded unit running a different program. The refusal reads
<domain>/<unit> is loaded and runs [<declared argv>], not [<argv>]; retire it first. launchd holds the definition it bootstrapped, so rewriting the plist under a live job changes nothing an operator can see;ensurerefuses rather than silently overwrites. Retire the unit (stado service retire <unit> --host <target>), then ensure again. - Registry push refused on directory generation. A registry write
replaces the whole document, so a push that would delete top-level keys, or
whose
service_directory.generationwould go backwards (which would make every stale cached directory start looking current), is refused. The refusal spells the repair: re-pull, re-apply the edit, and push again;--forceonly if the deletion or the older directory is genuinely the intent. - Registry push refused because a document does not parse. The push
guards compare the uploaded document with the stored one, so both must
parse as one document object. A payload that does not is refused with its
parse error before anything is written, and a stored registry that does
not parse is refused naming its generation; neither
--forcenor--allow-empty-fleetbypasses this. Repair the file (or the stored object, throughstado registry pulland a corrected push) and push again. registry doctornames aproduct-catalog-unreadablefinding. The check for units whose host declares nomanaged_versionsentry reads the compiled product catalog to tell a managed unit from an arbitrary tree. When the catalog cannot be read, the doctor says so for that host, with the catalog's own refusal, instead of reporting the host as having every version declared. Repair the catalog (stado product catalogprints the same refusal) and run the doctor again.registry doctornames adirectory-url-unreadableordirectory-url-without-portfinding. The check that compares a service directory endpoint with its product's stable bind reads the endpoint as a URL and takes the port it names. An endpoint that is not a URL, or names no port, cannot be compared, and the doctor says so for that host and service instead of passing it. Repair the endpoint in the service directory and run the doctor again;directory-names-candidate-portremains the finding for an endpoint that names a rollout's candidate port.registry doctornames aregistry-document-driftfinding. The doctor parses the registry from one fetched document and then reads the same document'stargetsentries beside the parsed targets. A parsed target whose entry is missing from that document is reported by name instead of being read as an empty entry; it means the document the doctor holds does not describe the registry it parsed. Fetch the registry again and run the doctor on the fresh document.registry doctornames anunread-declarationfinding. A registry target key no reader in the running Stado consults: not modelled by the target type, not catalogued among the declarations read out of raw JSON (targets[].bearers,services, …), and not read by a shipped catalog service through a${declared:<key>}placeholder (the host process'shealth_interval_seconds, Weles'sweles.recordings_dir). Remove the key, or give it the reader it was declared for. Acatalog-unreadfinding says the catalog's placeholder keys could not be listed; every unmodelled key is then judged without them, so a key only a catalog unit reads appears as unread until the catalog reads again.registry doctornames aunit-env-driftfinding. On the machine the doctor runs on, a managed unit's file carries none of a variable its catalog entry'senvdeclares (<unit> (<path>) carries no <NAMES> that its catalog entry <product> declares, so its program starts without them): the unit was written before the entry gained the variable, and nothing rewrote it since. Names are compared, never values.stado service ensure <product> --host <host>writes the unit from the catalog. Aunit-env-unreadfinding names a unit file that exists and cannot be read; another host's units are not compared from here. Stado Desktop's Registry screen runs the same doctor as Compare the registry with every host's live state and name each divergence and its repair, with the command's own receipt.registry doctornames aforeign-install-rootfinding. A release-controlled product'sinstall_rootis an absolute path under one target's home while another target's home differs; release control expands only{home}, so that target's agent installs where it is not at home.stado release policy root repair <product>writes the root as{home}/<rest>(the finding names it) in one verified registry write;--checksays what it would write. A new target thatplacement standbyadds rewrites the root itself, andrelease policy applyrefuses a policy whose root lies under one target's home (install_root <root> lies under <host>'s home, so <hosts> would install where they are not at home; write it as {home}/<rest>), so the finding names only documents written before that refusal.registry doctornames aschedule-pinned-nowherefinding. A live schedule is pinned to a consumer no registry target names, by name or by its<kind>-<hostname>identity, so its jobs wait for a claimer that never comes — typically a host that was removed or renamed. Declare it again withstado schedule create --id <id> --converge, its cron and command as before and--pinned-host <host>, or, when its host was emptied onto another, evacuate with--repin-schedules.ambiguous-schedule-pinnames a pin an identity two targets claim (once per schedule), andunreadable-schedulesa schedule store that did not answer.registry doctornames aprofile-lacks-catalog-storesfinding. A placement profile does not carry a store the catalog declares for a product it runs (Brama's donated subscriptions, Skarbiec's vault, Weles' keeper), so a move would leave it on the fenced source andplacement moverefuses the profile.stado placement profile sync <profile>adds what the catalog declares;placement evacuate --standbydoes it in its run.profile-stores-unjudgednames a profile whose units the catalog could not be read against.registry doctornames aservice-second-namefinding. A host records a unit the product catalog declares (by its unit name or its launchd label,com.wisent.<unit>) under a name that is not the catalog's, such ascom.wisent.skarbiecforskarbiec, so the service's supervision state is kept under two names and a reading by the catalog name finds nothing. The finding names the record's path and the one field that moves it:stado registry set --path targets.<host>.services.<index>.name --value <catalog name>, which changes the record's name in the registry and no unit on the host.stado service adoptrecords a catalog unit under the catalog's name, whatever label it was adopted by, so no new record of this kind is made.--jsoncounts the records compared underchecked.service-second-name;service-second-name-unjudgednames a catalog that could not be read.
Source: this website