Two review findings from the bot round on this stack.
BLOCKING (codex-bot, claude-bot -- both, independently). bootstrap-tenant.sh
emits the staging guest's tailnet-join next step at the end of a converge
("box shell -> sudo rig bootstrap workload"), repeats it in usage, and two of
its refusals recite the old machine-role list. Fixed here rather than on the
stacked tenant PR because THIS is the branch that removes the `workload` role
-- shipping it alone would print a next step naming a role that no longer
exists.
None of those four sites is code that ACCEPTS a role, which is why the rename
missed them, and is also what makes them the worse failure. A stale flag dies
immediately with a usage error. A stale next-step is copy-pasted by a human
onto a DIFFERENT box, minutes after the run that printed it reported success,
and dies there with no thread back to the cause.
So test/cli.sh sweeps every shipped script under bin/ and commands/ for
`rig bootstrap <pre-#76 name>` rather than pinning the four known sites: the
next instance of this class will be somewhere else. Proven non-vacuous --
reintroducing the bare `workload` next-step turns the suite red (412/1),
restoring it turns it green (413/0).
NON-BLOCKING (claude-bot). The migration story was documented and untested:
every marker fixture was renamed alongside the code, so nothing asserted what
a real pre-rename box does. A `role=control-plane` fixture now pins both
halves of the promise -- such a box WARNS on the coolify verbs (its marker no
longer names a role that exists) and is never REFUSED. Both halves matter: a
rename that turned this into a refusal would break the exact boxes the
CHANGELOG promises keep working, on the command that installs the control
plane.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rig builds two kinds of thing on opposite sides of a trust boundary --
tailnet machines it converges, and guests a box mints -- and both families
lived in one flat namespace with nothing in a role name saying which you
meant. `staging` is where that stopped being cosmetic: the word names the
metal that hosts guests and the guests on it, only one could have it, and
#31 gave it to the guests. The VM-host shape was left nameless, spelled
`custom --class server --host yes --join authkey`, which is what every
refusal recited at an operator who had confused the two.
The suffix now names the family: control-plane-server, workload-server,
runner-server, dev-server, plus the restored staging-server (class=server
host=yes join=authkey). host=yes already installs the box CLI and runs box's
setup-host, so staging-server is a table row, not new machinery. It stays
OUT of the tag:server allow-list deliberately -- a host is never managed by
the control plane, its guests are -- so its key is minted tag:local.
custom and workstation keep bare names as the rule, not an exception to it:
custom presets nothing and can be any shape including a guest, so a family
claim is one it cannot make; a workstation is somebody's own device, joined
by interactive login, user-owned and untagged, never tailnet-managed.
Hard cut, no aliases -- old names are refused as unknown. Two consequences
this reaches beyond the CLI surface. TS_HOSTNAME defaults to the role name,
so a box taking the default now comes up control-plane-server. And the two
coolify commands match the ROLE NAME in /etc/rig/role, not the traits, so
they now look for role=control-plane-server; a pre-rename control plane
takes their warning branch, which is advisory and never a gate, so the run
proceeds and the message names the repair.
dev-server is class=human, which reads like a contradiction and is not: the
suffix names the family, the class names the root-SSH door policy. The two
axes share the word "server", which is a real wart -- #77 renames the class
trait to what it controls, kept separate because it reaches markers on live
machines that guard root SSH.
Tests cover both directions of the cut: every new name resolves, every old
name is refused as unknown, and the two deliberately-bare roles are proven
NOT to have been swept up -- the inverse error, which would otherwise only
surface at somebody's laptop.
Closes#76 (machine-role half)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>