plan rev 2.2: rule 3 final from platform-1e (claims-on boxes: no published row, census.json present, pools don't match)
1 file changed,
+11
−1
docs/superpowers/plans/2026-10-20-offline-operator-move.md+11 −1
diff --git a/docs/superpowers/plans/2026-10-20-offline-operator-move.md b/docs/superpowers/plans/2026-10-20-offline-operator-move.md| index ca3fb620c..2d98a7c1b 100644 |
| --- a/docs/superpowers/plans/2026-10-20-offline-operator-move.md |
| +++ b/docs/superpowers/plans/2026-10-20-offline-operator-move.md |
| @@ -172,7 +172,17 @@ The `docs/site/cli.md` paragraph under `### carlos move` (Task 7) is copy too. T |
| It refuses (MV-O20) on a `control/hosts-backfill.json` whose phase is `collecting` or `adopting`. A plan at `done` is allowed, with any number of hosts. |
| 2. **A console on the claim path refuses (MV-O20).** This is unchanged. |
| - 3. **The region-wide capability check narrows.** The start door refuses (MV-O21) when the target box lacks `offline-move-1`, or when any box that publishes the source placement lacks it. Those are the boxes whose pools match the record's placement, the ones that could serve or wake the host. It also refuses when the record's placement matches the pools of any box that runs claims-on. Boxes in the region that cannot hold the host are not consulted. This point may be confirmed or tightened later. |
| + 3. **FINAL (platform-1e, from code at 96db0efe).** The start door refuses (MV-O21) unless every claims-on box in the source or target region meets all three conditions: |
| + - (a) It publishes NO row for the host. The evidence is that box's published edges file and box report (every host it serves), never the operator's word. |
| + - (b) It reports `/var/lib/carlos-claims/authority/exec/census.json` present, so root's legacy restart fallback (`legacyrestart.go:21-27`) can't start anything. |
| + - (c) Its pool set doesn't match the record's placement. |
| + |
| + If any of this evidence is missing from a box's published state, the door refuses. It fails closed, and the move adds no new box report field just to satisfy this. The reasons: |
| + - On a claims-on box, wakes go through `doClaimWake` and refuse a claimless host (`activator.go:2085`, `claimwake.go:182-201`), and reconcile mints only through `claimInstall` (`provision/claimassembly.go:20-38`). |
| + - The exceptions are an existing non-hibernating row the edge proxies without a check (`edge.go:851`), root's legacy fallback when census.json is missing, and the domains apex mint (`domains/reconcile.go:312`). |
| + |
| + Boxes that publish the source placement, and the target box, must also carry `offline-move-1`. The interim wording follows for reference. |
| + 3a. *(interim, superseded by 3)* **The region-wide capability check narrows.** The start door refuses (MV-O21) when the target box lacks `offline-move-1`, or when any box that publishes the source placement lacks it. Those are the boxes whose pools match the record's placement, the ones that could serve or wake the host. It also refuses when the record's placement matches the pools of any box that runs claims-on. Boxes in the region that cannot hold the host are not consulted. This point may be confirmed or tightened later. |
| 4. **An armed or enforced guard is NOT a refusal.** The capability depends only on hibernation being configured and `CARLOS_HOST_CLAIM` and `CARLOS_MOVES_PHASE1` being unset. The guard mode is not read for the capability. The target's build stages through ordinary adoption, so root's existing floor check applies on a guarded target box, and the move adds no other stage, adopt or restart path. |
| - **Switches stay off, and claims are refused from evidence.** Every offline door refuses with MV-O20 when the console runs with `HostClaim` or `MovesEnabled`. A box publishes the `offline-move-1` capability, and runs any offline step, only when hibernation is configured, `CARLOS_HOST_CLAIM` and `CARLOS_MOVES_PHASE1` are unset, and the guard policy (`/opt/carlos/system/guard/policy.json`, `internal/hostfloor/floor.go:33`, `:141`) is absent or its `Mode` is neither `armed` nor `enforced`; otherwise it logs one notice per host and does nothing. The start door refuses (MV-O21) when any box in the source or target region lacks the capability, refuses MV-O29 when `control/hosts/<host>.json` exists, and refuses MV-O20 when `control/hosts-backfill.json` (`hostops.BackfillKey`) exists or the console is on the claim path at all (`HostClaim`, which includes the `claimMoveUnsupportedMsg` case, `apiinstancemove.go:575-578`). Nothing here reads `CONSOLE_APP_REGIONS`, `CARLOS_SWAP` or `CARLOS_REGION_HA`, and nothing takes the operator's word for any of it. |