carlos / platform Public
Region HA plan 2b: copy record (approved by Paul 2026-10-17)
Every user-facing string plan 2b (2026-10-17-region-ha-2b-joining.md) writes: the output and refusals of carlos system host-env, install-channel and join, the first line of the host.env file it writes, the operator alert the console's enrolment pass sends, the descriptions systemd shows for the two join units, the carlos system usage lines, and the docs prose. The gate is approved_region_ha_2b_copy_test.go at the repo root, which reuses the moves gate's parser, so the format is the moves record's: one table per heading, columns id, file, text, status.
The rules:
- A row is
pendinguntil Paul approves it in the copy review (thecopy-reviewskill). His edits are applied to the text here verbatim and the row becomesapproved. - No pending string reaches code, CLI help or docs. The task that writes a row's text adds its id to
regionHA2bCopyBuiltin the gate in the same commit, and from then on the gate fails unless the row isapprovedand its text is in the file it names. Tasks 2, 3, 7 and 9 therefore wait for their rows' approval. - In a Go file the text is one string literal, or one
fmt.Sprintf,fmt.Errorforerrors.Newformat, equal to the row with a format verb where the row has a<placeholder>. A row whose file cell says "a fragment" is a piece of a larger literal (a usage text). - Command syntax is exempt: the
usage:lines, flag names and the commands in the docs' code blocks are not rows. - Log lines are not rows, as in plan 2a: the joining agent's and the console enrollment pass's.
- Ids are not renumbered: a row added in review takes the next free id and goes in its task's table (RHB-C62 to RHB-C64, round 1; RHB-C65 to RHB-C67, round 3; RHB-C68, round 4; RHB-C69, build Task 3 round 1, approved by Paul 2026-10-17; RHB-C70 and RHB-C71, build Task 7 round 1; C70 approved by Paul 2026-10-17). A withdrawn row's id is not reused: RHB-C65 and RHB-C66, the operator alert of round 3, went with the read-back they belonged to in round 4.
- No em dashes. A full stop and a new sentence instead. Refusals start lower case, as the CLI's others do.
Paul approved RHB-C1, C5 to C9, C11 to C32, C34 to C64 and C67 to C68 unedited in the copy review on 2026-10-17, RHB-C69, added in build Task 3 round 1, the same day, and RHB-C70, added in build Task 7 round 1, the same day. RHB-C2 to C4, C10, C33 and C71 are internal error fragments, left out of the review under his rule that reviews hold only text a person reads in normal use; they ship as drafted.
Placeholders: <reason> the text of the error underneath; <path> a file; <region> a placement code; <deployment> a deployment's name; <scope> a region or shared; <prefix> a parameter path such as /carlos/prod/ie/; <n> a count; <name> and <names> one or more variable names; <variable> and <value> a variable and its value; <version> a platform release such as v0.31.0; <tag> its release tag; <release> the host floor's minimum release; <channel> a channel such as stable; <platform> such as linux-arm64; <box> a box's reference.
host.env from the deployment's parameters (Task 2)
| id | file | text | status | |---|---|---|---| | RHB-C1 | internal/hostenv/hostenv.go | # Written by carlos system host-env write from the deployment's parameters. Do not edit by hand. | approved | | RHB-C2 | internal/hostenv/hostenv.go | required values are missing | approved | | RHB-C3 | internal/hostenv/hostenv.go | values conflict | approved | | RHB-C4 | internal/hostenv/hostenv.go | a name or value host.env cannot hold | approved | | RHB-C5 | internal/hostenv/hostenv.go | <reason>: <deployment> and <scope> must be lower-case labels | approved | | RHB-C6 | internal/hostenv/hostenv.go | <reason>: <names> set both for the region and shared | approved | | RHB-C7 | internal/hostenv/hostenv.go | <reason>: line <n> is not KEY=value | approved | | RHB-C8 | internal/hostenv/hostenv.go | <reason>: <name> is set twice | approved | | RHB-C9 | internal/hostenv/hostenv.go | <reason>: <region> is not a region | approved | | RHB-C10 | internal/hostenv/hostenv.go | parameters under <prefix>: <reason> | approved | | RHB-C11 | internal/hostenv/hostenv.go | <reason>: the shared <names> already differ | approved | | RHB-C12 | internal/hostenv/cli.go (a fragment of the usage) | build host.env from the deployment's parameters (root) | approved | | RHB-C13 | internal/hostenv/cli.go (a fragment of the usage) | copy a box's host.env into the deployment's parameters | approved | | RHB-C14 | internal/hostenv/cli.go | carlos system host-env write runs as root: it writes a root-owned file | approved | | RHB-C15 | internal/hostenv/cli.go | host.env was not written: <reason> | approved | | RHB-C16 | internal/hostenv/cli.go | wrote <path> from the parameters for <region> | approved | | RHB-C17 | internal/hostenv/cli.go | the parameters were not all written: <reason> | approved | | RHB-C18 | internal/hostenv/cli.go | wrote <n> parameters under <prefix> and <n> under <prefix> | approved | | RHB-C64 | internal/hostenv/hostenv.go | already set by another seed | approved | | RHB-C67 | internal/hostenv/writelinux.go | <path> is not a directory only root can write | approved | | RHB-C68 | internal/hostenv/writeother.go | carlos system host-env write runs only on Linux | approved |
carlos system install-channel (Task 3)
| id | file | text | status | |---|---|---|---| | RHB-C19 | internal/host/installchannel.go (a fragment of the usage, re-approved by Paul 2026-10-18 (claim-prev-rehearsal), re-approved by Paul 2026-10-18 (claim-untagged-pointer)) | usage: carlos system install-channel [--policy FILE --identity FILE]\n\nInstall the release this box's channel names, as root, on a box that has none yet. | approved | | RHB-C20 | internal/host/installchannel.go | carlos system install-channel runs as root: it installs the platform binary | approved | | RHB-C21 | internal/host/installchannel.go | <variable>=<value> is not a channel, so nothing was installed | approved | | RHB-C22 | internal/host/installchannel.go | <version> (<tag>) from the <channel> channel is already installed | approved | | RHB-C23 | internal/host/installchannel.go | installed <version> (<tag>) from the <channel> channel as carlos and carlos.prev | approved | | RHB-C24 | internal/host/installchannel.go | an update is running on this box, so nothing was installed: <reason> | approved | | RHB-C25 | internal/host/installchannel.go | the <channel> channel could not be read, so nothing was installed: <reason> | approved | | RHB-C26 | internal/host/installchannel.go | the <channel> channel names <version> with no artifact for <platform>, so nothing was installed | approved | | RHB-C27 | internal/host/installchannel.go | this box's host lifecycle guard is armed, so carlos system update installs its releases | approved | | RHB-C28 | internal/host/installchannel.go | this box's host lifecycle guard could not be read, so nothing was installed: <reason> | approved | | RHB-C29 | internal/host/installchannel.go | this box's install record could not be read, so nothing was installed: <reason> | approved | | RHB-C30 | internal/host/installchannel.go | this box already runs <version>, so carlos system update installs its releases | approved | | RHB-C31 | internal/host/installchannel.go | <version> could not be fetched, so nothing was installed: <reason> | approved | | RHB-C32 | internal/host/installchannel.go | <version> did not verify, so nothing was installed: <reason> | approved | | RHB-C33 | internal/host/installchannel.go | <path> does not hold <version> after the copy | approved | | RHB-C34 | internal/host/installchannel.go | no host floor is published, so this box could not arm its guard and nothing was installed | approved | | RHB-C35 | internal/host/installchannel.go | the host floor could not be read, so nothing was installed: <reason> | approved | | RHB-C36 | internal/host/installchannel.go | the host floor does not verify, so nothing was installed: <reason> | approved | | RHB-C37 | internal/host/installchannel.go | the <channel> channel names <version> with no release tag, so nothing was installed | approved | | RHB-C38 | internal/host/installchannel.go | the release identity for <tag> could not be read, so nothing was installed: <reason> | approved | | RHB-C39 | internal/host/installchannel.go | <version> (<tag>) is below the host floor <release> or is not the release its identity names, so nothing was installed | approved | | RHB-C69 | internal/host/installchannel.go | <path> holds a build this command did not install, so nothing was installed | approved |
carlos system join (Task 7)
| id | file | text | status | |---|---|---|---| | RHB-C40 | internal/host/joinroot.go (a fragment of the usage) | Arm the host lifecycle guard of a joining box, as root, once the console has invited it. | approved | | RHB-C41 | internal/host/joinroot.go | carlos system join runs as root: it arms the host lifecycle guard | approved | | RHB-C42 | internal/host/joinroot.go | CARLOSHOSTCLAIM or CARLOSREGIONHA is off, so this box does not join | approved | | RHB-C43 | internal/host/joinroot.go | the invitation for <box> could not be read: <reason> | approved | | RHB-C44 | internal/host/joinroot.go | the invitation for <box> does not verify, so the guard was not armed | approved | | RHB-C45 | internal/host/joinroot.go | the identity record for <box> could not be read: <reason> | approved | | RHB-C46 | internal/host/joinroot.go | the invitation for <box> is for another identity record, so the guard was not armed | approved | | RHB-C47 | internal/host/joinroot.go | the identity record for <box> is not this instance's, so the guard was not armed | approved | | RHB-C48 | internal/host/joinroot.go | the host floor could not be read: <reason> | approved | | RHB-C49 | internal/host/joinroot.go | the host floor does not verify, so the guard was not armed: <reason> | approved | | RHB-C62 | internal/host/units/carlos-system-join.path | carlos joining: arm the host lifecycle guard on agent request | approved | | RHB-C63 | internal/host/units/carlos-system-join.service | carlos joining (root: arm the host lifecycle guard) | approved | | RHB-C70 | internal/host/joinroot.go | this box's AWS identity could not be read, so it cannot join yet: <reason> | approved | | RHB-C71 | internal/host/joinroot.go | this box has no name to join under | approved |
The carlos system usage and the docs (Task 9)
| id | file | text | status | |---|---|---|---| | RHB-C50 | system.go (a fragment of the usage) | A box a region's group launches (region HA): | approved | | RHB-C51 | system.go (a fragment of the usage) | build host.env from the deployment's parameters (root) | approved | | RHB-C52 | system.go (a fragment of the usage) | copy a box's host.env into the deployment's parameters | approved | | RHB-C53 | system.go (a fragment of the usage) | install the release this box's channel names (root) | approved | | RHB-C54 | system.go (a fragment of the usage) | (root oneshot behind carlos-system-join.service; not for operators) | approved | | RHB-C55 | docs/site/cli.md | Boxes a region's group launches | approved | | RHB-C56 | docs/site/cli.md | In a region with HA on, the boxes its Auto Scaling group launches set themselves up with no hand steps. A box's start-up runs two commands as root before it starts the agent. | approved | | RHB-C57 | docs/site/cli.md | carlos system host-env write builds /etc/carlos/host.env from the deployment's parameters: SecureStrings in AWS SSM under /carlos/<deployment>/<region>/ and, for the values every region shares, /carlos/<deployment>/shared/. If a required value is missing, it stops and writes nothing. | approved | | RHB-C58 | docs/site/cli.md | carlos system install-channel installs the release the box's channel names, as both carlos and carlos.prev, once it passes the published host floor. A box that already runs a release is refused: carlos system update moves it. | approved | | RHB-C59 | docs/site/cli.md | The agent then joins. It publishes the box's identity record and hosts nothing. Once the console has checked with AWS that the new box belongs to the region's group, it invites the box. The box arms its host lifecycle guard, the console checks the group again and enrolls it, and the box restarts as a hosting box. Only then does the load balancer send it traffic. | approved | | RHB-C60 | docs/site/cli.md | carlos system host-env seed copies a box's existing host.env into those parameters, once per region. It writes the region's own values and any shared value not yet set. It refuses to change a shared value another region has set. | approved | | RHB-C61 | docs/site/cli.md | Seeding needs ssm:GetParametersByPath and ssm:PutParameter on the deployment's two parameter paths, and kms:Encrypt and kms:Decrypt on its configuration key. | approved |