carlos / platform Public

region HA spec 2, rev 12: answers Astra round 11 (1 P2, accepted); group-level role inherited at enrolment; round 11 findings committed unedited

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by claude agent, operated by paul@keymail.dev bed2f06d780ada6064e12428b2f2345839b4ba42 parent 6f88e54
2 files changed, +52 −4
  • docs/superpowers/specs/2026-10-15-region-ha-two-box-regions-design.md +18 −4
  • docs/superpowers/specs/CODEX-FINDINGS-REGION-HA-SPEC2-11.md +34 −0
diff --git a/docs/superpowers/specs/2026-10-15-region-ha-two-box-regions-design.md b/docs/superpowers/specs/2026-10-15-region-ha-two-box-regions-design.md
index 2649be21f..927748fad 100644
--- a/docs/superpowers/specs/2026-10-15-region-ha-two-box-regions-design.md
+++ b/docs/superpowers/specs/2026-10-15-region-ha-two-box-regions-design.md
@@ -1,6 +1,8 @@
# Region HA, spec 2: two-box regions
-Design, 2026-10-15, **rev 11**. DRAFT. Nothing here is built.
+Design, 2026-10-15, **rev 12**. DRAFT. Nothing here is built.
+
+**Rev 12** answers Astra's round 11 (`CODEX-FINDINGS-REGION-HA-SPEC2-11.md`, **A11-1**, P2, accepted). Rollback's exclusion is set on the region's group, and every box the group launches inherits it at enrolment, so a replacement can't reopen placement. §24.
**Rev 11** answers Astra's round 10, a full pass (`CODEX-FINDINGS-REGION-HA-SPEC2-10.md`, cited **A10-n**): three P2s and one P3, all accepted. Rollback now restores only the ingress and never destroys a group that has hosted an instance, so retiring a group is spec 4's drain too. Moves take their source from the claim, not from placement eligibility. §23 maps them.
@@ -300,7 +302,12 @@ The choice is made once and recorded in the create intent, as now (H12). Recover
- the box's existing instances stay where they are;
- operations already heading to it before the role was set simply finish there, and the instance joins the box's existing ones. Nothing needs to be empty, so nothing needs to be waited for.
-The roles are set by an operator, through `carlos system box role <ref> legacy|platform|default`, a console API only an operator may call, and they persist in the roster. Spec 4's drain later moves a `legacy` box's instances to the group, and then the box is retired.
+The roles are set by an operator, through `carlos system box role <ref> legacy|platform|default`, a console API only an operator may call, and they persist in the roster.
+
+**A group-level role** (A11-1). Each region's group has its own entry in the roster: the `Region` struct already carries `GroupName` and `GroupARN`. That entry gains a **default role for its boxes**, normally `default`, set with `carlos system group role <region> legacy|default`.
+- The console's enrolment pass (§5) gives every box it enrols from that group the group's role, in the same roster write that enrols it.
+- So a replacement launched after the group was excluded enrols already excluded, and is never placeable even for a moment.
+- Changing the group's role also changes the role of every box currently enrolled from it, in one roster write. Spec 4's drain later moves a `legacy` box's instances to the group, and then the box is retired.
**Rebalancing:** none automatic. An operator moves an instance between boxes in a region with spec 1's relocation. Automatic rebalancing is spec 4's.
@@ -354,13 +361,13 @@ Each is closed by a code change, or by showing it's safe under claim mode, befor
- **Before any group box reaches hosting mode** (step 1 failing): destroy the group and NLB freely. Nothing has been placed on them.
- **After that, before step 3:**
- set the old box's role back to `default`, so new instances can land on it again;
- - set both group boxes to `legacy`, so nothing new lands on them.
+ - set **the group's** role to `legacy` (`carlos system group role <region> legacy`). That excludes both current group boxes and every replacement the group launches later (A11-1).
- The group boxes keep whatever they host. They stay in service, behind the old box's forwarding, until spec 4's drain retires them.
- **From step 3 until acceptance:**
1. Remove zone A's mapping from the NLB. An address on a requester-managed interface can't be disassociated directly. The NLB itself is kept, because the group boxes are its targets.
2. Wait until the EIP shows as unassociated.
3. Swap the old box's addresses back: disassociate its new EIP, associate the region's EIP, and force a republication. In IE, switch the relay and MX records back and restart the relay advertising the region's address (A2-9).
- 4. Set the roles as for "before step 3". Group instances stay where they are, reached through the old box privately.
+ 4. Set the roles as for "before step 3", the group's role included. Group instances stay where they are, reached through the old box privately.
- **After acceptance:** recovery is forward, within the group.
**Cost.**
@@ -403,6 +410,7 @@ Each is closed by a code change, or by showing it's safe under claim mode, befor
- **Rehearsal on dev:**
- the full §9 sequence, with the cut-over window measured, the zone-B rehearsal, and both rollback sequences run once. Rollback leaves the group in service with its instances, including one that was never woken;
- outbound moves from a `legacy` box and from the `platform` box;
+ - a group box replaced after rollback, and one already joining during rollback: each enrols with the group's `legacy` role and is never placeable;
- the old box's address swap at the cut-over: forced republication, and cross-region forwards to its instances recovering within a minute;
- the `legacy` and `platform` roles excluding a box from creates, relocation targets and move targets, persisting across console and box restarts, and an operation already heading to the box finishing there;
- one group box terminated by hand, with replacement and re-enrolment observed;
@@ -526,3 +534,9 @@ All three were answered in Astra's round 1 and folded in:
| A10-2 P2: rollback can't relocate a never-woken group instance | Accepted by the same change: rollback moves nothing (§9) |
| A10-3 P2: moves need source validation separate from destination eligibility | Accepted: the source comes from the claim and is checked only as enrolled, active and unfenced. Only the destination uses §7 (§8) |
| A10-4 P3: §6 still requires emptying the old box | Accepted: §6 describes the address swap (§6) |
+
+## 24. Astra round 11 dispositions (rev 12)
+
+| Finding | Disposition |
+|---|---|
+| A11-1 P2: rollback's exclusion doesn't survive box replacement | Accepted: a role on the region's group entry in the roster, inherited at enrolment in the same write, and applied to current members when changed (§7, §9) |
diff --git a/docs/superpowers/specs/CODEX-FINDINGS-REGION-HA-SPEC2-11.md b/docs/superpowers/specs/CODEX-FINDINGS-REGION-HA-SPEC2-11.md
new file mode 100644
index 000000000..934ad4c6f
--- /dev/null
+++ b/docs/superpowers/specs/CODEX-FINDINGS-REGION-HA-SPEC2-11.md
@@ -0,0 +1,34 @@
+A10-1 through A10-4 are closed at design level. One new finding:
+
+**P2 — Rollback’s placement exclusion does not survive box replacement.**
+[Spec:357](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/docs/superpowers/specs/2026-10-15-region-ha-two-box-regions-design.md:357)
+
+Rollback sets the two current group boxes to `legacy`, but leaves automatic replacement and enrolment running. [§10 explicitly makes replacements placeable](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/docs/superpowers/specs/2026-10-15-region-ha-two-box-regions-design.md:375). The exclusion belongs to each box’s roster entry; no group-level exclusion or inheritance is specified.
+
+**Failure scenario:** rollback excludes both boxes after a group boot/configuration problem. One fails and is replaced. Its replacement enrols under a new reference and accepts new customer instances into the group the operator rolled back. A replacement already joining during rollback has the same gap.
+
+Persist the exclusion for the group and enforce it before replacements become eligible. Rehearse replacement during and after rollback.
+
+Reviewed platform `6f88e541` and flagship `7c99ff8f`. No files changed; no builds, tests or infrastructure commands run.
+
+---
+
+**FIRST PROMPT:**
+Review spec 2 round 11 at the pinned HEAD against flagship tofu, read-only.
+
+**WHAT:**
+Confirm the previous fixes and report new findings.
+
+**STATUS:**
+Four findings closed; one new P2.
+
+**NEEDED:**
+Nothing.
+
+**RECOMMENDED:**
+Make rollback’s placement exclusion survive replacement.
+
+**SESSION:**
+Safe to close; nothing modified or left running.
+
+**Verdict: not ready for a plan.**
\ No newline at end of file