Fixed fd number rbnx exports as ROBONIX_SOMA_STAGE_FD in somaβs
environment. Any fd β₯ 3 works β we pick 3 because itβs the first
non-stdio slot, which keeps ls /proc/<soma>/fd readable at a
glance. Soma reads the trigger line, then closes it.
Issue one Driver(cmd) RPC against a freshly-connected channel, then
release the channel. Returns the responseβs state string on success;
bail-errors when ok=false or the RPC itself fails. Used by the boot
path for both CMD_INIT and CMD_ACTIVATE, with identical timeout / channel
hygiene.
Mirrors robonix_codegen::contract_gen::contract_id_to_service_name.
Uniform PascalCase: robonix/primitive/chassis/driver β
RobonixPrimitiveChassisDriver. No prefix stripping. Full gRPC
service path: /robonix.contracts.<this>/Driver.
Probe a host:port. Returns Ok(()) when nothing is listening (we can
safely bind), Err describing the live owner otherwise. This is a
race-prone pre-check (someone else can grab the port between probe
and spawn) but in practice the failure mode it catches β a stale
previous-boot daemon β has been alive for minutes, not seconds, so
a single connect attempt is enough.
Apply top-level deployment variables, then expand every scalar in the
manifest. Build and boot share this preparation path so package locations,
target-manifest selectors, system settings, and package config all resolve
against the same environment.
Read the last max_lines lines of a file for embedding into an
error message. Best-effort: an unreadable/missing file returns an
empty string rather than an error β the caller already reports the
path, we just enrich when we can. We read the whole file (soma.log
is scribe-managed and stays small during boot), split, and take
the tail β no seek-from-end acrobatics needed for the boot-time
use case.
Summarize a package that exited before Atlas registration. Providers often
forward Python tracebacks through Scribe at info level, so the lifecycle-
specific parser above may intentionally return None. In that case the last
structured message is the most useful single-line cause for boot output.
Return the providerβs actual lifecycle failure rather than whichever
shutdown record happened to be written last. Scribe records are JSONL;
providers commonly report lifecycle transitions at info level, so prefer
-> ERROR (...) messages before falling back to an error-level record.
Compute a PackageEntryβs expected on-disk path. PURE β no I/O,
no logging, no cloning. path: entries land at manifest_dir/path;
url: entries land at cache_root/<name> (whether or not itβs
been cloned yet). Use entry_path_exists_on_disk to check
presence; use the public cmd::fetch::clone_remote_packages
(called from rbnx build) to actually populate the cache.
Cache directory name for a url-remote package: the git REPO name (last path
segment of the url, minus .git), NOT the per-instance provider id.
Render a one-line βwhat is this binary doingβ string for the boot
log. Pulls out the high-signal flags (port, vlm model+host) and
drops noisy ones (βcapabilities, βlog, raw API keys).
Per-binary required-arg sanity check, run before spawning.
Poll atlas until a provider NOT in before appears. Returns the new
provider_id plus every distinct lifecycle Driver observed after the
declaration settle window. The caller verifies this list before sending
config or lifecycle commands.
Strip the leading <component>_ from the boot-log pkg_label.
system_memory β memory; primitive_tiago_chassis β tiago_chassis.
Keeps boot-output columns narrow (the section header above already
said which class the entry belongs to).
Spawn soma with an inherited pipe on SOMA_STAGE_FD. The parent
keeps the write end and later writes stage2\n to it (see
write_stage2_trigger below). Layered on spawn_system_binaryβs
stdio+scribe pattern but adds:
Translate a system.<name>: block into CLI args for the corresponding
Rust binary. Per-binary mapping kept narrow β adding a new flag means
touching exactly this function plus the binaryβs clap struct.
Run fut while animating the boot spinner so the user sees the
[ β ] name msg_prefix N.Ns line update steadily even when the
underlying RPC takes a while (Driver(CMD_INIT) for sensor-warm-up
packages routinely sits at 30+ seconds). Without this the line goes
silent right after wait_for_registration finishes and rbnx looks
hung between OK lines.
Write the stage2\n trigger into the pipe rbnx and soma share
(see spawn_soma_binary). This is a one-shot: soma reads the
line, unblocks its skill-package launcher, and closes its read
end. rbnx-side we drop the writer here β no reason to hold it
open, and closing gives soma an immediate EOF on the (very
unlikely) chance it re-reads.