Option A per triage's normalization on #95: derive, never mint. The
derivation is pinned — sha256("rig-machine-id:<machine-id>"), first 32 hex
as 8-4-4-4-12 — and the prefix is the contract that keeps the id
uncorrelatable with other tools' derivations, per machine-id(5)'s own
guidance not to expose the raw value.
Missing, empty and 'uninitialized' machine-id files degrade loudly to an
'unavailable (reason)' line: hashing nothing would hand every such machine
the same identity, the worst possible failure for an identity field.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review found `commands/platform.sh` still telling future readers that a
missing converged_* pair is a legitimate state on a freshly bootstrapped box.
It is not, and the rest of this PR already says so: #61's writer records both
pairs equally at bootstrap, so no writer produces that manifest -- its absence
means partial or hand-edited. README and the fixtures were corrected in an
earlier commit of this series; the comment beside the code was not, which
left the one artifact a future change actually reads while editing this block
still arguing the retired position.
Also corrects two examples that went stale under this PR rather than in it.
#76 and #77 merged while this was in review, so the marker example in the
same file -- and the sample `rig platform` output in README -- still showed
`role=dev class=human host=yes join=authkey`, a spelling bootstrap no longer
writes. Now `role=dev-server root-door=closed host=yes join=authkey`, with a
note that the renderer prints whatever fields a marker carries, so a
pre-rename box still shows its own class= line unchanged.
Comments and docs only; no behaviour change. Same defect class both times --
prose that contradicts the contract the tests pin -- which is why the sweep
went wider than the one site reported.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The reader asked for `version` and `bootstrapped`. #61 specifies `schema`,
`bootstrapped_by`/`bootstrapped_at` and `converged_by`/`converged_at` — so
no writer would ever have produced the keys being read, and the day #61
landed this command would have rendered 'unknown' with the timestamp
omitted, forever, with nothing to say why.
Keyed to #61's spelling, with fixtures carrying that schema verbatim so
the contract is pinned rather than assumed. Birth and latest are reported
separately and neither is inferred from the other: under #61 rule 2
converged_* is written only when the version differs, so its absence is a
legitimate state on a freshly bootstrapped box, printed 'not recorded'
rather than backfilled from birth. A manifest whose schema this rig does
not know is named as such instead of being half-read in silence.
Found in review of #74.
Refs #64
`while IFS='=' read -r k v` drops an unterminated final line: read returns
1 at EOF even having filled k and v. A manifest ending `bootstrapped=...Z`
with no trailing \n rendered `RIG 1.2.3` with the timestamp silently gone
— the version read fine, so nothing looked wrong.
Guarded with `|| [ -n "$k" ]`, the same shape parse_users_file already
uses (lib/users-config.sh:47). #61's writer should not have to know
whether this reader tolerates a missing newline.
Also make human_b fall back like human_kb. With numfmt absent, memory
degraded to a raw number while disk printed 'unknown' beside it, from data
already in hand.
Both found in review of #74.
Refs #64
rig read no hardware at all. The single exception was `uname -m` in
runner-install.sh, used to pick a runner tarball and then discarded — so
"is this the 32GB one, or the M900?" was a question you answered by
logging in and running free -h, nproc, df -h and uname -r by hand, four
commands deep, on a machine you were already unsure about.
`rig platform` prints hostname, OS, kernel, CPU, memory, disk and
virtualization, then a provenance block: which rig, when, and the role
marker's traits.
It COMPUTES rather than stores, and that is the design rather than an
implementation detail. Specs change without rig doing anything — RAM
added, root disk resized, the unattended-upgrades bootstrap itself
enables patching the kernel — so a stored spec is stale the moment the
machine changes, and refreshing one on every run would collide with
bootstrap's "safe to re-run; a second run changes nothing" contract.
Nothing is written, so nothing can go stale.
The corollary is deliberate: reading only /proc, uname, /etc/os-release,
df and systemd-detect-virt means no root, no network, and it runs on a
pristine Debian box rig has never bootstrapped — useful for deciding
what to converge a machine into, not only for auditing it afterwards.
That also makes it the rare rig command the harness can RUN for real
rather than grep: the tests assert the answer describes the actual test
machine (kernel and hostname compared against independently computed
values), and assert it writes nothing.
Both known traps are handled explicitly. /etc/os-release is sourced in a
SUBSHELL — it defines VERSION, NAME and ID and would otherwise clobber
same-named script variables, the form every other site in this tree uses
and test/cli.sh already greps for. systemd-detect-virt exits non-zero on
bare metal while printing 'none', a normal answer that set -e would
otherwise turn into a failed run, so it is wrapped in `|| true`.
Provenance is read, never written, and degrades per file.
/etc/rig/manifest is #61 and does not exist yet, so that line reads
'not bootstrapped' on every machine today; the command ships complete
without it and neither blocks the other.
Named `platform` and not `status`: `users status` and `runner status`
cross-check recorded against live state and print DRIFT, and a command
that records nothing cannot drift, so calling it status would borrow a
promise it structurally cannot make. It also leaves `rig status` free
for the machine-wide roll-up it will eventually want to be.
Refs #64