carlos / platform Public

docs: stage B Task 10's activation record names every switch-on gate with its owner and status, C12, C13, C14, Task 11 after J2, O1 with W5 and the instance-key work among them

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by claude agent, operated by paul@keymail.dev 6dfb955dff4b7233f7ffc58497be4f440740c7d9 parent e08ea5b
1 file changed, +50 −11
  • docs/superpowers/plans/2026-10-10-region-ha-1b-next-stage-b.md +50 −11
diff --git a/docs/superpowers/plans/2026-10-10-region-ha-1b-next-stage-b.md b/docs/superpowers/plans/2026-10-10-region-ha-1b-next-stage-b.md
index c6ec4499f..977fd3fc9 100644
--- a/docs/superpowers/plans/2026-10-10-region-ha-1b-next-stage-b.md
+++ b/docs/superpowers/plans/2026-10-10-region-ha-1b-next-stage-b.md
@@ -14753,30 +14753,69 @@ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>"
- [ ] **Step 9: The rollout checklist** (not code; recorded in the plan and in the handoff)
-Before `CARLOS_REGION_HA` is set on any box with a second box in its region, on dev with two fixed boxes:
+**Rev 5.4 (Task 10 fix round 1, review I1): the activation record.** This is the whole list of what must be true before relocation is switched on anywhere: the gate table first, every ask, dependency and task named with its owner and its status, then the dev-box checks in order. The "After this plan" row "Switching relocation on anywhere" points here. Status is as of 2026-10-12 (branch tip at this commit); a gate is open until its status says otherwise.
+
+**Gates.**
+
+| Gate | What must be true | Owner | Status | Until then |
+|---|---|---|---|---|
+| **C1** | A discharge for a fenced or stuck source's `relocation-release`, and release authority for a `probe-failed` target | claim session (#236) | Asked; open | **Drains (`drain`, `rebalance`) stay off.** Failover is unaffected (ruling 33). |
+| **C4** | `PredecessorCertified` accepted as the relocation release's certification | claim session (#236) | Asked; open (`hostbox.Writer.Admit` refuses `PredecessorCertified` today) | **Drains stay off** (Task 8d ruling): a drain cannot open P. |
+| **C6** | A kind-scoped CC9 discharge for an excluded target | claim session (#236) | Asked; open | Ruling 63's two safe outcomes; checked on dev (item 11). Not a switch-on gate. |
+| ~~C7~~ | ~~Re-labelled handover~~ | claim | **Withdrawn** (rev 3, ruling 56): root's `ColdHandover.Run` takes the probe's receipt (N6) | none |
+| **C9** | The claim's `Policy` admits the install's three actions | claim session (#236) | Asked; open | `relocationInstallPolicy` (ruling 46). Not a switch-on gate. |
+| **C10** | The CC9 discharge of a relocation participation by its binding and completed probe evidence | claim session (#236) | Code committed (Task 9); **confirmation outstanding** | **Switch-on gate.** If refused, Task 9's C10 commit is reverted and region HA releases nothing (ruling 66). |
+| **C11** | A relocating launch pinned to `install_stamp` only for P's opening | claim session (#236) | Asked; open | One launchable probe attempt per target (ruling 58); `LaterProbeAttempts` stays false (item 16). |
+| **C12** | `StartGuard`'s completion barrier (N13) | claim session (#236) | Code committed (Task 8a, N13); **confirmation outstanding** | **Switch-on gate.** If refused, N13 is reverted and the guard the claim names takes the one-line call (item 20). |
+| **C13** | The loss route in claim mode for a completion box that is permanently dead and never terminated (ruling 84's residual): the claim's scoped loss writer | claim session (#236) | Asked with the ruling 84 residual; open | Such a host waits for the claim's loss path; the console's `declare-lost` refuses in claim mode (item 19). Not a switch-on gate. |
+| **C14** | Root reading the agent-written `relocate/ops/<op>/attempts.json` (hardened read, Task 8d fix round) as its relocating attempt authority | claim session (#236) | Posted; open | **Gate on W4** (item 14). If refused, a root-side attempt record is built first. |
+| **M1** | Moves closes the move record after a converted landing (`released_move`) | moves session (#236) | Asked; open | A converted host cannot move again until an operator closes it (item 8). |
+| **M2** | Moves' `sourceOf` accepts a converted claim | moves session (#236) | Asked; open | The source's `park-local` waits; the row stays held (item 8). |
+| **M3** | Moves' held-stage relay serves a relocating request (`Stamp` on `HeldStageRequest`) | moves session (#236) | Asked; open | **Switch-on gate** (item 6): relocation waits in `installed`. |
+| **M-K25** | Moves classifies `moves/held-stage` and `moves/held-staged` census-opaque, or keys the relay by op | moves session | Asked; open | N11 (committed) classifies them; item 15 checks the census. Not a switch-on gate. |
+| **J2** | Moves Plan 5 Task 9's park arming with the files live set | moves session | Open | Task 11's joint round waits for it. |
+| **Task 11** | The joint round on the two-box model passes, then the branch gate (L18) | region HA (this plan) | Not run; waits on J2 | **Merge and switch-on gate** (item 21). |
+| **C8 + O1′** | Moves' production `ClaimFilesManifest` provider registered on every box (`RegisterProductionClaimMoveSources`), `Establish` publishing `<host>.env`'s exact bytes and starting each admission with no adoption item | moves session (platform-d8, #236); O1′ from the instance-key plan | Not built on this branch | **Switch-on gate** (item 13): relocation stays unbound (ruling 53). |
+| **W5** | Wake state published continuously, outside the release flush (spec A1-7) | region HA follow-up (likely with O1's provider) | Not built | **Switch-on gate** (item 13): failover refuses at install, `stuck`. |
+| **Instance-key plan** | `internal/instancekey` (IK-1, merged at cf22260a) and the rest of the instance-key plan rolled to the region's boxes, with its rollout step 1 pre-roll check run first (every replica's key against its home's, into `CARLOS_REPLICA_HOME_KEYS`) | instance-key plan (`instance-key-build`) | IK-1 merged; the plan's later tasks and roll not done | **Switch-on gate** (item 9). |
+| **O2′, O3′, O5** | The pinner's key evidence, the install's delivered-key check, the flush's adoption item | region HA (Tasks 8a to 8c) | Built on this branch | Checked on dev (item 17). |
+| **O6** | Claim launches bind a control socket and mount the adoption verb, with `CARLOS_INSTANCE_KEY_SOURCE` | claim Plan 9 Group D (instance-key plan obligation) | Not built; ships only after O7 | **Explicit refusal** (ruling 55, item 9): platform-key and configured-key apps' relocations refuse (`stuck`). |
+| **O7** | Moves' journalled artifact lists retire the adoption record | moves session (instance-key plan obligation) | Not built | Before O6 nothing writes a record; O6 does not ship without it. |
+| **O8** | A keyless replica handed its home's platform-minted key (replica placements, #162) | replica placements (#162) | Not built (instance-key ruling 28) | A relocated keyless replica keeps refusing to start unless it has a verified configured key or a control socket (`replicaKeyGate`); item 9. |
+| **Task 10b** | The source's row held at its fence's close (`Reconciler.FenceClosed`, `HoldRow`) | region HA (this plan) | Written, **not built** | **Mandatory switch-on gate** (R5-3, ruling 79; item 18). |
+| **Checklist 12** | The two-box dev run: failover, the completion, the first serving wake handed over from the probe's receipt | region HA, on dev (operator: Paul) | Not run | **Switch-on gate** (R5-4). The unit e2e (`TestCompletionPassThenFirstServingWakeWithRegionHAOff`) runs the wake runtime, not `OpenProductionClaimAssembly` in agent mode, which needs root's socket, the carlos uid and a cgroup manager. |
+| **W1** | The live Litestream witness for a drain | region HA, on dev | Not run | Drains fail closed (`stuck`); with C1/C4 drains are off anyway (item 5). |
+| **W2** | Root's writers-stopped scan under the deployed unit (host PID namespace, ptrace) | region HA, on dev | Not run | Releases fail closed (item 4). |
+| **W3** | IAM: create-only `PutObject` under `control/hosts/*/evidence/*`, `control/relocations/*` and the data bucket's `instances/*/files/*/` | infrastructure (tofu; Paul) | Not applied | **Switch-on gate** (item 3): receipts and pins fail to write. |
+| **W4** | Root's relocating attempt reader live under the deployed unit | region HA, on dev | Not run; rests on C14 | **Switch-on gate** (item 14): every relocating launch is refused at `PreflightKind`. |
+| **Root capability** | Every box's root runs `isolated-unit-v3` and answers the relocating capability; every box and edge publishes `region-ha-1` | region HA, on dev; the release floor | Not run | **Switch-on gate** (items 1, 2, 10). |
+
+**Dev-box checks**, in order, on dev with two fixed boxes, before `CARLOS_REGION_HA` is set on any box with a second box in its region:
1. **Floor and flags.** The release floor includes claim Plan 11's additions (its rollout section); `CARLOS_HOST_CLAIM` and `CARLOS_MOVES_PHASE1` are on; claim Plan 9's activation census and floor guard pass (`#250`); every box's root runs `isolated-unit-v3`.
-2. **Preflight.** On each box, a serving wake passes `ClaimRoleAssembly.Preflight` (the isolated launch). While root refuses the relocating kind, the participant counts no attempt and the pass logs the refusal once per host.
+2. **Preflight.** On each box, a serving wake passes `ClaimRoleAssembly.Preflight` (the isolated launch). While root refuses the relocating kind, the participant counts no attempt and the pass logs the refusal once per host and step.
3. **IAM (W3).** The box role may create-only `PutObject` under `control/hosts/*/evidence/*`, `control/relocations/*` and the data bucket's `instances/*/files/*/` prefixes; `DeleteObject` denies do not cover them (the lease-release outage rule).
4. **Root's scan (W2).** Terminate a drain on dev: root's writers-stopped observation passes under the deployed `carlos-instance-control.service` (host PID namespace, ptrace), and the full stop's receipt lands with its `.sig`.
5. **The live witness (W1).** With the real Litestream replicator, a drain's `WritersStopped` passes; if root refuses on a descriptor outside the hint, file the claim ask of ruling 29 and keep drains off.
6. **M3.** Root's held-stage relay serves a relocating request (the target's `live/<host>` names `install_release`). Until then relocation waits in `installed`.
-7. **C1.** Drains stay off until the claim answers C1 (ruling 33). Test failover first: terminate the executor of one host; watch `starting -> pinning -> installing -> installed -> probing -> serving`, one cold restart on the target, the source's `park-local` left open (no `enrolled_at` discharge yet unless the roster has it).
-8. **J3.** A committed landing whose target is terminated converts; moves' M1/M2 close it.
-9. **L21.** The instance-key plan is rolled to the region's boxes, and O1′, O2′, O3′, O5 and O7 are in. **O6 gates platform-key and configured-key relocation:** until claim launches bind a control socket and mount the adoption verb, an app whose key is not its own `instance.key` cannot report adoption on a claim box, and its relocation refuses (stuck). That is an explicit refusal, not HA support for those apps. Apps must also run a rastrillo release with the adoption call (#66 ask and addendum).
+7. **C1 and C4.** Drains stay off until the claim answers C1 (ruling 33) and accepts C4. Test failover first: terminate the executor of one host; watch `starting -> pinning -> installing -> installed -> probing -> serving`, one cold restart on the target, the source's `park-local` left open (no `enrolled_at` discharge yet unless the roster has it).
+8. **J3, M1 and M2.** A committed landing whose target is terminated converts. Until moves' M1 and M2 land, the converted host cannot move again and the source's `park-local` waits; an operator closes the move record.
+9. **L21 (the instance-key plan, O6, O7, O8).** The instance-key plan is rolled to the region's boxes after its pre-roll check (its rollout step 1: every replica's key against its home's, into `CARLOS_REPLICA_HOME_KEYS`), and O1′, O2′, O3′, O5 and O7 are in. **O6 gates platform-key and configured-key relocation:** until claim launches bind a control socket and mount the adoption verb, an app whose key is not its own `instance.key` cannot report adoption on a claim box, and its relocation refuses (stuck). That is an explicit refusal, not HA support for those apps. Apps must also run a rastrillo release with the adoption call (#66 ask and addendum). **O8:** until it lands, a keyless replica relocated to a new box is still refused unless it has a verified configured key or a control socket.
10. **Capabilities.** Every box and edge publishes `region-ha-1` (spec §8 step 3).
11. **C6.** An excluded target's participation ends in one of ruling 63's two safe outcomes. Check that no writer starts on it and that its `park-local` retires the inert installation.
12. **C10 and the two-box run (gate; R5-4).** With C10 confirmed on #236: after a failover on dev, the first request after completion is served on the target from a cold serving wake, handed over from the probe's receipt (N6), with no agent restart; `.hostexec/<host>.json` is gone on the target before its row leaves `relocating`.
-13. **C8 and O1 (gate).** Moves' `ClaimProductionMoveSources` is registered on every box, with `Establish` publishing `<host>.env`'s exact bytes. Without it, the agent logs "relocation owners not opened" and nothing relocates.
-14. **W4.** Root's relocating attempt reader is live: `carlos-instance-control` answers the relocating capability, and a probe's first launch is authorized from `<DataDir>/relocate/ops/<op>/attempts.json`.
-15. **Census.** After a relocation completes on dev, `find /data -path '*<host>*'` on the target lists only the host's instance directory, the census-opaque `relocate/` (N9) and moves' relay directories (N11, until M-K25), and on the source nothing outside them after its `park-local`; within a pass of completion `relocate/` holds nothing of that op.
+13. **C8 with O1, and W5 (gate).** Moves' `ClaimProductionMoveSources` is registered on every box, with `Establish` publishing `<host>.env`'s exact bytes. Without it, the agent logs "relocation owners not opened" and nothing relocates. **Failover refuses at install until both O1/C8 (`<host>.env` published at admission) and W5 (wake state published outside the release flush, spec A1-7) exist:** the pinner and the install refuse a missing env or wake item without evidence of its absence, and the op goes `stuck` for an operator. Until both are in, failover is not HA.
+14. **W4 and C14.** Root's relocating attempt reader is live: `carlos-instance-control` answers the relocating capability, and a probe's first launch is authorized from `<DataDir>/relocate/ops/<op>/attempts.json`. That reading rests on claim ask **C14** (root reading the agent-written journal); if the claim refuses it, a root-side attempt record is built first and this item waits for it.
+15. **Census and M-K25.** After a relocation completes on dev, `find /data -path '*<host>*'` on the target lists only the host's instance directory, the census-opaque `relocate/` (N9) and moves' relay directories (N11, until M-K25), and on the source nothing outside them after its `park-local`; within a pass of the completion's mark `relocate/` holds nothing of that op.
16. **C11.** Until it lands each target gets one launchable probe attempt; set `LaterProbeAttempts` only after it does.
17. **O2′ on dev.** A relocation of an app on its own `instance.key` pins with no `InstanceKey`. After O6, a relocation of a platform-key app pins `InstanceKey`, and changing a configured key between pin and install makes the install refuse (`VerifyDelivered`).
18. **Task 10b (gate; R5-3).** Task 10b has landed and its tests pass: `Reconciler.FenceClosed` and `HoldRow` are wired, the source's row goes held at its fence's close with a status the edge does not serve, and the completion or the source's park-local ends the hold. Relocation is not switched on anywhere before this.
-19. **A completion its box cannot finish (ruling 82; runbook).** With claim mode on, every box runs the completion pass, whatever `CARLOS_REGION_HA` says. The agent logs "relocation pass started (completions only: true)" with region HA off. A host whose serving op shows `completed_relocation` without `discharged` refuses every start (moves, deletes, purges, placements, relocations) with "relocation <op> is not yet discharged on <box>" until that box's pass marks it. Usually the next pass does. If the box can never run its pass (it will not boot, or its discharge is refused for good), use the existing loss path; there is no override:
+19. **A completion its box cannot finish (ruling 82; runbook; C13).** With claim mode on, every box runs the completion pass, whatever `CARLOS_REGION_HA` says: the agent logs "relocation pass started (completions only: true)" with region HA off, and "relocation completion pass not started" with its reason if it cannot start one. With region HA on the full pass is built on the pass's first, bounded, run and retried every pass until it builds (said once per cause). The completion pass reads this box's registry rows and every host its `relocate/ops/*/{probe-fence,attempts}.json` journals name, so a completion whose row is gone is still visited and its refusal ("has no row on this box") said once. A host whose serving op shows `completed_relocation` without `discharged` refuses every start (moves, deletes, purges, placements, relocations) with "relocation <op> is not yet discharged on <box>" until that box's pass marks it. Usually the next pass does. If the box can never run its pass (it will not boot, or its discharge is refused for good), use the existing loss path; there is no override:
- **Terminate the box.** The termination worker writes its fence. A failover relocation from the box then cites that fence, which the barrier exempts (ruling 81), and puts the box on `lost`. After that every start passes.
- - **Or have the box declared lost** through the claim's loss declaration (`hostclaim.DeclareLost`), which puts it on `lost`. The console's `declare-lost` action refuses while claim mode is on (apihostclaim.go), so in claim mode this path waits for the claim's scoped writer.
+ - **Or have the box declared lost** through the claim's loss declaration (`hostclaim.DeclareLost`), which puts it on `lost`. The console's `declare-lost` action refuses while claim mode is on (apihostclaim.go), so in claim mode this path waits for the claim's scoped writer: claim ask **C13** (ruling 84's residual).
- Never edit the claim by hand to clear the record. That reopens round 7's conflict: the box's participation slot is still the old op's, and the successor's `Prepare` answers `ErrLost`.
+20. **C12 (gate).** C12 is confirmed on #236: `StartGuard`'s completion barrier (N13) is the claim's. If it is refused, N13 is reverted and the guard the claim names takes the one-line call; relocation is not switched on before one of the two is on main.
+21. **Task 11 and J2 (gate).** Task 11's joint round has passed on the two-box model, after moves' J2 (Plan 5 Task 9's park arming with the files live set), and the branch gate has run. Relocation does not merge or switch on before.
---
@@ -14813,7 +14852,7 @@ Unchanged from the 1b-next plan's Task 11 (L13558-13586), with the model at `ori
| What | Waits for |
|---|---|
| Drains (`reason: drain`, `rebalance`) | C1 |
-| Switching relocation on anywhere | C10 and C12 confirmed on #236, C8 with O1 registered, O2′ wired, Task 10b landed (R5-3), the two-box run on dev (checklist item 12), Task 11 |
+| Switching relocation on anywhere | Every switch-on gate in Task 10 step 9's activation record (rev 5.4): C10 and C12 confirmed on #236, C8 with O1 and W5, M3, W3, W4 with C14, the instance-key plan rolled, Task 10b landed (R5-3), the two-box run on dev (checklist item 12), Task 11 after J2 |
| More than one probe attempt per target | C11 |
| A shorter denial for an excluded target | C6 |
| The install's three actions under the claim's own Policy | C9 |