# Region HA plan 2a: copy record (pending Paul's review)

**Approved by Paul, 2026-10-16**, through the copy review: all 25 rows (RHA-C1 to RHA-C25) unedited.

Every user-facing string plan 2a (`2026-10-16-region-ha-2a-core.md`)
writes: console refusals, CLI output and usage lines, the operator alert,
and the docs prose. The gate is `approved_region_ha_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 `pending` until Paul approves it in the copy review (the
  `copy-review` skill). His edits are applied to the text here verbatim
  and the row becomes `approved`.
- No pending string reaches code, CLI help or docs. The task that writes
  a row's text adds its id to `regionHACopyBuilt` in the gate in the same
  commit, and from then on the gate fails unless the row is `approved`
  and its text is in the file it names. Tasks 10 and 11 therefore wait
  for their rows' approval.
- In a Go file the text is one string literal, or one `fmt.Sprintf`
  format, equal to the row with `%s` where the row has a `<placeholder>`.
  A row whose file cell says "a fragment" is a piece of a larger literal
  (the `carlos system` usage text).
- No em dashes. A full stop and a new sentence instead. The role doors'
  refusals start lower case, as the console's other CLI refusals do; the
  no-capacity refusal is shared with the browser's domain door, so it is
  a capitalised sentence, as `claimResponseUnavailable` is.

Placeholders: `<box>` a box's roster reference or label; `<role>` a role
name (default, legacy or platform); `<region>` a placement code or the
home region's name.

## Box and group roles (Task 10)

| id | file | text | status |
|---|---|---|---|
| RHA-C1 | internal/console/apiboxroles.go | role must be default, legacy or platform | approved |
| RHA-C2 | internal/console/apiboxroles.go | a group's role must be default or legacy | approved |
| RHA-C3 | internal/console/apiboxroles.go | could not read the box roster. Try again. | approved |
| RHA-C4 | internal/console/apiboxroles.go | the box roster changed while the role was being saved, and nothing was changed. Try again. | approved |
| RHA-C5 | internal/console/apiboxroles.go | could not save the role. Try again. | approved |
| RHA-C6 | internal/console/apiboxroles.go | no enrolled box is named <box> | approved |
| RHA-C7 | internal/console/apiboxroles.go | <region> has no group | approved |
| RHA-C8 | internal/console/apiboxroles.go | <box> is retired, so it takes no role | approved |
| RHA-C9 | system_roles.go | <box> now has the <role> role | approved |
| RHA-C10 | system_roles.go | the group in <region> now has the <role> role | approved |
| RHA-C11 | system.go (a fragment of the usage) | whether new instances may be placed on a box. A legacy or | approved |
| RHA-C12 | system.go (a fragment of the usage) | platform box keeps the instances it has and takes no new ones | approved |
| RHA-C13 | system.go (a fragment of the usage) | the same for every box a region's group has enrolled, and for | approved |
| RHA-C14 | system.go (a fragment of the usage) | every box it enrolls later | approved |
| RHA-C15 | docs/site/cli.md | Box and group roles | approved |
| RHA-C16 | docs/site/cli.md | carlos system box role says whether new instances may be placed on a box. A box with the default role can take them. A legacy or platform box keeps the instances it has and takes no new ones: no new instance, relocation or move lands on it. carlos system group role sets the role of every box a region's group has enrolled, and of every box it enrolls later. Both work only on a console with region HA on. | approved |
## No box has room (Task 11)

One refusal for every door that chooses a box (H27): instance create,
domain attach, standalone sidecar create and the move door's destination.

| id | file | text | status |
|---|---|---|---|
| RHA-C17 | internal/console/nocapacity.go | No box in <region> has room right now. Try again in a few minutes. | approved |
| RHA-C18 | internal/console/nocapacity.go (the operator alert's subject) | No box in <region> has room | approved |
| RHA-C19 | internal/console/nocapacity.go (the operator alert's body) | A request in <region> was refused because no box there can take it. Every box is full, stale or excluded by its role. Add a box, or free memory or disk on one, and check the eligible-capacity alarm for <region>. | approved |
## More Task 10 rows

Added at Task 10's build (controller ruling): every sentence a person reads
that the role doors, the CLI and the docs section carry and the rows above
do not. Command syntax (the usage synopses and the docs example's commands)
is not copy. The numbering follows Task 11's, which is why these start at
RHA-C20.

| id | file | text | status |
|---|---|---|---|
| RHA-C20 | system_roles.go | unreadable response: <error> | approved |
| RHA-C21 | docs/site/cli.md | Ops account owners and `CARLOS_SYSTEM_OPERATORS`. | approved |
| RHA-C22 | docs/site/cli.md | Do not set a role until every box and console in the deployment runs a release that knows about roles. A box on an older release cannot read a roster that carries one. | approved |
| RHA-C23 | internal/console/apiboxroles.go (the ops audit row's detail) | gave <box> the <role> role | approved |
| RHA-C24 | internal/console/apiboxroles.go (the ops audit row's detail) | gave the group in <region> and its boxes the <role> role | approved |
| RHA-C25 | internal/console/apiboxroles.go | the box roster can't be changed right now. Try again later. | approved |