Reviewed `ddd0617f` against its code base, `origin/main` at `70e57449`, and the supplied flagship checkout. No files changed; no builds, tests or infrastructure commands run.

1. **P1 — The NLB cannot use both boxes with only one enabled zone.**  
   [Spec:83](/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:83) specifies one subnet mapping but instance targets spread across two zones. Cross-zone balancing reaches targets in **enabled** zones; the second zone’s target remains `unused`. If the first box hangs while its zone remains available, the healthy second box cannot receive ingress. Enable both target zones; customers can retain their existing A record. [AWS target-health documentation](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/target-group-health-checks.html).

2. **P1 — Boot and enrolment have a circular dependency.**  
   [Spec:128–134](/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:128) starts the claim-enabled agent before enrolment, then enrols before arming the guard. Today, agent construction requires `/etc/carlos/host-actor.json` and a matching roster entry ([claimproduction.go:87](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/host/claimproduction.go:87)); failure exits before the identity-publication loop starts. Separately, adding a box after floor publication requires its guard-ready report ([membership.go:40](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/hostactors/membership.go:40)). A clean replacement therefore cannot complete either ordering. Specify a non-hosting enrolment mode, signed invitation, guard installation and readiness report **before** final enrolment.

3. **P1 — Fixed group size does not prevent healthy-box termination.**  
   [Spec:81](/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:81) omits scale-in protection because scaling is deferred. However, `AZRebalance` can launch and terminate instances without changing desired capacity. If an unavailable zone forces both boxes into the surviving zone, recovery can trigger termination of a healthy box hosting customer instances. Spec 2 then leaves those instances down until spec 3. Explicitly suspend zone rebalancing or provide a relocation-aware protection mechanism. [AWS process behaviour](https://docs.aws.amazon.com/autoscaling/ec2/userguide/understand-how-suspending-processes-affects-other-processes.html).

4. **P1 — IE’s relay and MX move too late.**  
   [Spec:246](/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:246) assigns the platform EIP and changes relay/MX DNS only after all customer instances migrate. From step 2 onward, their old address belongs to an NLB accepting only 80/443. Relay traffic and inbound mail therefore fail for the entire migration, plus DNS cache expiry—not merely the announced web cut-over. The current relay record directly uses the IE EIP ([dns53.tf:103](/home/paulca/github.com/carlosframework/carloku-infrastructure/dns53.tf:103)). Move these services and account for DNS TTLs before transferring that address.

5. **P2 — Pre-enrolment publication can permanently disqualify automatic enrolment.**  
   [Spec:130](/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:130) needs an explicit publication boundary. Once pre-enrolment startup is enabled, the normal agent also starts `edgesFileLoop`. An edges file naming the new box makes `Directory.Referenced` true, and automatic enrolment explicitly rejects referenced boxes ([enroll.go:37](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/hostactors/enroll.go:37), [references.go:63](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/hostactors/references.go:63)). A delayed confirmation can consequently turn an otherwise valid replacement into an operator-only case. Suppress ordinary edges publication until enrolment, or define a safely distinguishable provisional record.

6. **P2 — `carlos bootstrap` does not install the signed channel release.**  
   [Spec:119](/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:119) attributes release installation to a command that installs users, directories and units. It finishes by instructing the operator to copy the binary and configure the host ([bootstrap.go:619](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/host/bootstrap.go:619)). A replacement would run the bootstrap object’s version, potentially below the published floor. Specify the signed-release installation step, including identity and previous-binary material required by guard-arm; obtain its verification configuration beforehand.

7. **P2 — `unplaced` needs a claim transition and recovery contract.**  
   [Spec:207](/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:207) cannot use today’s create path unchanged. `BeginCreateOn` rejects an empty executor, and production recovery requires both `selected_executor` and `executor_enrollment` ([create.go:109](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/hostclaim/create.go:109), [production_create.go:257](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/hostops/production_create.go:257)). A persisted executor-less create would remain unrecoverable after capacity returns. Define reservation, cancellation, concurrent placer CAS, one-time executor selection, and old-reader behaviour. Also define how edges recognise an unplaced hostname and return the promised 503 without a published home.

8. **P2 — Healthy boxes will repeatedly fail the freshness threshold.**  
   [Spec:195](/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:195) rejects edges files older than five minutes, but publication is **five minutes plus up to one minute of jitter**, not every 30 seconds ([edgesfile.go:794–798](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/host/edgesfile.go:794)). Quiet, healthy boxes periodically become ineligible; overlapping windows produce false capacity alerts and unplaced instances. Change the publication cadence explicitly or set the cutoff above its maximum interval plus delivery margin.

9. **P2 — §8 omits customer operations and accounting that depend on the console’s local registry.**  
   [Spec:217](/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:217) does not close these concrete regressions when IE customers leave the console box:

   - Scoped restart refuses hosts known only to another box ([apirestartscope.go:45](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/console/apirestartscope.go:45)).
   - Domain attachment finds no existing primary route and takes the first-route path ([domainattach.go:150](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/console/domainattach.go:150)).
   - Remote customer processes fall into platform-overhead attribution ([economicspass.go:308](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/console/economicspass.go:308)).
   - Fleet app/service listings use the elected publisher’s local routes ([fleet.go:154](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/status/fleet.go:154)); retention enumerates apps from the housekeeper’s local registry ([retention.go:49](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/host/retention.go:49)).

   Add these consumers to the prerequisite audit and give them complete, ownership-checked inputs.

10. **P2 — Loading the forwarding map once does not prove forwarding readiness.**  
    [Spec:149](/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:149) permits a permanent 200 after one map load. Map and mesh-key refreshes fail independently ([homemap.go:259](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/edge/homemap.go:259)); forwarding refuses without a key. A new forwarding-only box can therefore pass health checks while every forwarded request fails. The same answer does not establish TLS readiness or detect a stalled hosting worker. Define cached readiness and local liveness conditions for the services this health check is meant to protect.

11. **P2 — Pending enrolment is invisible to the proposed alarms.**  
    [Spec:141](/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:141) promises an alert after 15 minutes, but an unenrolled forwarding box can be both ASG `InService` and NLB healthy. Both proposed alarm predicates remain false indefinitely. Add an enrolment-age or eligible-capacity signal. Initial boot failure also needs qualification: AWS does not replace ELB-unhealthy instances while an attached target group has never reached its first healthy target. [ASG metrics](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-metrics.html), [attachment-state behaviour](https://docs.aws.amazon.com/autoscaling/ec2/userguide/load-balancer-status.html).

12. **P2 — EIP cut-over needs a direct-address publication barrier.**  
    [Spec:240–242](/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:240) moves the old box’s published dial address onto the NLB. The publisher re-probes it only on timed passes and retains the previous address across blank IMDS reads ([edgesfile.go:589](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/host/edgesfile.go:589)). During that interval, another region forwards a signed hop to the NLB; a group box receiving it cannot forward again and returns 503 ([edge.go:1505](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-region-ha-two-box/internal/edge/edge.go:1505)). Require a direct public address, forced publication and reader convergence for the old box during cut-over, as well as private forwarding within its region.

13. **P2 — Rollback omits releasing the NLB-owned address and retaining the old executor.**  
    [Spec:250](/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:250) cannot be executed as a direct EIP reassociation: AWS forbids disassociating addresses from requester-managed interfaces. The owning NLB/subnet mapping must release it first. After step 4 terminates the old box, the stated rollback is no longer available at all. Define the rollback boundary, preserve the allocation, retain the old box until acceptance, and specify the release/wait/reassociate sequence. [AWS interface restrictions](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/requester-managed-eni.html).

For §13:

- **Fresh headroom:** resolve finding 8 first. Five minutes is workable only with an explicitly faster publisher.
- **Temporary NLB:** the creation-only assertion is too broad. `SetSubnets` accepts an EIP when adding a mapping. A temporary mapping in the other zone, followed by adding the existing-EIP mapping, could retain the rehearsal NLB and address finding 1. Rehearse that exact sequence on dev. [AWS API](https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_SetSubnets.html).
- **SSM/KMS:** a separate secrets key only adds isolation if its authorised readers differ. A dedicated deployment configuration key can suffice, with exact parameter-path restrictions and decrypt conditions binding SSM and `PARAMETER_ARN`. Keep the existing explicit Deny covering all four read operations outside the permitted paths; adding a narrow Allow alone does not constrain the managed-policy grants. [AWS encryption-context documentation](https://docs.aws.amazon.com/systems-manager/latest/userguide/secure-string-parameter-kms-encryption.html).

I found no new two-writer path in the existing cold-admission mechanism. Preserve H13: exclusive executorship alone does **not** make an old local database safe after relocation. Certificate challenge read-through supports the proposed ingress, and preserving client IPs avoids an inherent NLB-induced GeoIP change.

**Verdict: not ready for a plan.**