Replacing a program other products call
Replacing a program other products call
Every stado invocation records, once per caller and command, which executable started it and which command it ran, under ~/.stado/callers/. Nobody writes that list: it is what the installed programs did.
Before stado product install or stado product update places a program, and before stado release local install replaces one, Stado reads the records whose callee is the program being replaced. It keeps those whose caller is another product's recorded installed path and has not changed since it was recorded, and asks the incoming program for each recorded command with <command> --help. A command the incoming program does not answer refuses the installation:
<incoming> does not answer commands installed products still run, so it would break them; update these products to a revision that no longer runs them, then install again: oko cli (installed at ~/.stado/bin/oko, source revision <revision>) runs `~/.stado/bin/stado secrets get`
Update the named product first, then install again. A record whose caller has since been replaced or removed is deleted when it is read, and a caller that is no product's installed path (a shell, a script) is never a reason to refuse. A caller that cannot be read is written to standard error as stado: the program that ran this command was not recorded: <error> and the command still runs.
A record this account cannot read was not written by this account's programs, so it says nothing about what they run: it is named on standard error as caller record <path> cannot be read by this account (<error>); it was not written by this account's programs and is left out of the check, kept, and the installation goes on. A Stado run under another effective user than the owner of HOME (sudo stado …) records nothing, so it leaves no such record behind.
For Stado's resident unit, stado product install stado --surface cli
uses the prepared candidate to reconcile the existing native unit from the
candidate's catalog before replacing the executable. It checks the installed
unit's actual argv with stado quality units --candidate <prepared-stado> --program stado --host <registry-host>. A parser refusal names the host,
unit file, argv, candidate and error, and leaves the executable untouched.
stado quality parse -- <argv> checks the same parser without running that
command. Once files are placed, the real resident process must serve its
declared port through stado service serving stado --host <registry-host> --wait --json; an activation failure restores the exact recorded product
backup, restarts its unit and reports the observed predecessor state. Stado
Desktop → Products keeps the install refusal and status receipt; Services →
Managed services shows the unit's last exit and stderr evidence.
A resident unit that serves none of its declared ports when the installation
begins (stado service serving stado --host <registry-host> --json answers
anything but serving for a row, refuses, or prints no rows, which it does
when the registry it reads through is unreachable; the reason then says its serving state could not be read and quotes its last stderr line) is not
reconciled before placement: the
candidate's service ensure would restart it onto the executable still
installed, the one that does not serve, and an installation of a release that
fixes exactly that hang failed there every time. The installation says
stado: com.wisent.stado on <host> serves none of its declared ports (<rows>); it is rendered through the installed release once that is placed, places the
files, then renders the unit through the placed executable (rendered com.wisent.stado on <host> through <installed>) and waits for it to serve as
above. The real journey tests/install/resident/resident_unit.mjs stops the
unit's process with SIGSTOP before an installation and requires a new process
on the placed release that serves.
From the migration on, the unit carries the candidate's command line, so an
installation that stops before it commits (the candidate's own unit check or
the receipt write refuses) renders the unit again through the executable still
installed, which the unit goes on starting. The refusal then ends with the unit was rendered again through <installed>, which is still installed, or,
when that render fails too, with rendering it again through <installed> failed too, so the unit may carry options that executable refuses: <error>.
stado product rollback stado --surface cli does the same after it restores
the predecessor's files: the restored executable renders the unit from its own
catalog, and the rolled-back receipt records resident_unit with the host and
the executable that rendered it (stado product status stado --surface cli --json). A render the restored executable refuses fails the rollback with
the files of stado were rolled back, but its resident unit was not rendered again through <program>.
A unit no installation wrote (one an older Stado rendered, or one edited by
hand) can still start the installed executable with an option it refuses.
When the argument vector Stado refuses is exactly the one its resident unit
file starts (the per-user or system launchd plist, or the systemd unit, under
the catalog's label), the refusing executable starts stado service ensure stado --host <this host> as its own process-group leader before it exits, so
the unit is rendered from that executable's catalog and restarted without any
command from outside. Its stderr, which the unit's log keeps, then says
<label> (<unit file>) starts <executable> with an argument vector this build refuses; ... (pid <pid>) renders it again from this executable's own catalog and restarts it, and writes its answer to ~/.stado/logs/resident-converge.log;
a converge that cannot start says why on the same line. The host is read from
this machine's own registry copy, never from the authority the dead unit
serves. The converge's pid, kernel birth second (null when it had already
ended by the time it was recorded) and the command line it was started for
are kept in ~/.stado/logs/resident-converge.json, so init's next start of
the unit says the converge started earlier (pid <pid>) is still rendering it instead of starting a second one while that process runs; a pid another
process now holds does not count, and a record that cannot be read is said
and ignored. Any other refused command line is answered by the parser
alone. The host process's health pass starts the same converge when the
registry declares serve roles the resident unit's own process does not run,
and starts none for a line a converge already ran for (the beacon's
roles block says which).
On macOS, takeover and resident handover require exact membership in a complete native services table, not a matching domain metadata value or a running-PID guess. A registered job may have PID zero; unreadable or unsupported evidence refuses judgment. See Native scope membership. Linux release handover likewise requires an exact loaded manager-roster entry; enablement is not membership, and failed native reads keep their scope and cause. Reader convergence also requires complete native inventory; a missing completion or unreadable baseline read remains an installation failure, not an empty set of readers. Products retains the ordinary failure receipt.
Source: this website