carlos / platform Public

plan: moves into the home region (home part 2)

Plan for home-region part 2 (amadan #236): a Phase 1 move whose target is
the home region, under host claims. Six tasks: spec amendment, T3's home
rule (CompareEnv fails every move into home today), the into-home harness
and commit witness, rollback/abort/loss/conversion witnesses, the door
(home staging fold, home-named box refusal, plain path refusal), and the
rehearsal runbook. Seven rulings for Paul; confirm-only asks of
platform-1e (A1-A3) and region HA (H1-H3). No claim or region HA code
changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev be29ccd02e1e485db92b03b55b2b2d4b2aca61b5 parent a5003ab
1 file changed, +317 −0
  • docs/superpowers/plans/2026-10-15-moves-home-region-part2.md +317 −0

CI passed — run details

CI log
=== gate ===
cd launchctx && go vet ./... && go test ./... -count=1
ok  	amadan.net/carlos/platform.git/launchctx	0.011s
?   	amadan.net/carlos/platform.git/launchctx/controlname	[no test files]
?   	amadan.net/carlos/platform.git/launchctx/wireid	[no test files]
go vet ./...
gofmt -l .: clean
go test ./... -count=1 -timeout 30m
ok  	github.com/carlosframework/platform	294.170s
?   	github.com/carlosframework/platform/cmd/changelog	[no test files]
ok  	github.com/carlosframework/platform/cmd/console	2.668s
ok  	github.com/carlosframework/platform/cmd/moveprobe	92.218s
ok  	github.com/carlosframework/platform/cmd/zddprobe	0.704s
ok  	github.com/carlosframework/platform/internal/activator	249.974s
ok  	github.com/carlosframework/platform/internal/agentsock	0.017s
ok  	github.com/carlosframework/platform/internal/alerting	0.003s
ok  	github.com/carlosframework/platform/internal/analytics	0.022s
ok  	github.com/carlosframework/platform/internal/appconfig	2.456s
ok  	github.com/carlosframework/platform/internal/apperr	0.073s
ok  	github.com/carlosframework/platform/internal/applog	0.133s
ok  	github.com/carlosframework/platform/internal/awsinv	0.004s
ok  	github.com/carlosframework/platform/internal/boxchoice	0.004s
ok  	github.com/carlosframework/platform/internal/boxid	0.654s
?   	github.com/carlosframework/platform/internal/boxid/boxidtest	[no test files]
?   	github.com/carlosframework/platform/internal/boxid/internal/signtest	[no test files]
ok  	github.com/carlosframework/platform/internal/boxvolumes	0.008s
ok  	github.com/carlosframework/platform/internal/caps	0.013s
ok  	github.com/carlosframework/platform/internal/certwarm	0.003s
ok  	github.com/carlosframework/platform/internal/cgroup	0.693s
ok  	github.com/carlosframework/platform/internal/changelog	0.310s
ok  	github.com/carlosframework/platform/internal/clamd	0.055s
?   	github.com/carlosframework/platform/internal/cliflag	[no test files]
ok  	github.com/carlosframework/platform/internal/console	387.886s
?   	github.com/carlosframework/platform/internal/controlname	[no test files]
?   	github.com/carlosframework/platform/internal/controlsock	[no test files]
ok  	github.com/carlosframework/platform/internal/dbdoor	6.292s
ok  	github.com/carlosframework/platform/internal/dbdoor/dbdoortest	0.009s
ok  	github.com/carlosframework/platform/internal/dbverify	0.004s
ok  	github.com/carlosframework/platform/internal/dnsrec	0.002s
ok  	github.com/carlosframework/platform/internal/docsite	0.005s
ok  	github.com/carlosframework/platform/internal/domains	2.447s
ok  	github.com/carlosframework/platform/internal/doorkey	0.006s
ok  	github.com/carlosframework/platform/internal/economics	0.004s
ok  	github.com/carlosframework/platform/internal/edge	26.765s
?   	github.com/carlosframework/platform/internal/edgeproof	[no test files]
ok  	github.com/carlosframework/platform/internal/edgesfile	0.007s
ok  	github.com/carlosframework/platform/internal/fleetapi	0.148s
ok  	github.com/carlosframework/platform/internal/gate	1.655s
ok  	github.com/carlosframework/platform/internal/genselect	0.014s
ok  	github.com/carlosframework/platform/internal/geo	0.020s
ok  	github.com/carlosframework/platform/internal/geoip	0.035s
ok  	github.com/carlosframework/platform/internal/host	135.235s
ok  	github.com/carlosframework/platform/internal/hostactors	0.337s
ok  	github.com/carlosframework/platform/internal/hostbox	2.244s
ok  	github.com/carlosframework/platform/internal/hostclaim	0.497s
ok  	github.com/carlosframework/platform/internal/hostevidence	0.016s
ok  	github.com/carlosframework/platform/internal/hostexec	4.928s
ok  	github.com/carlosframework/platform/internal/hostfence	0.036s
ok  	github.com/carlosframework/platform/internal/hostfiles	10.510s
ok  	github.com/carlosframework/platform/internal/hostfloor	0.016s
ok  	github.com/carlosframework/platform/internal/hostguard	1.006s
ok  	github.com/carlosframework/platform/internal/hostops	1.531s
?   	github.com/carlosframework/platform/internal/hostops/fencerelease	[no test files]
ok  	github.com/carlosframework/platform/internal/hostops/internal/fencerelease	0.017s
ok  	github.com/carlosframework/platform/internal/hostquarantine	0.016s
ok  	github.com/carlosframework/platform/internal/hostrelocate	0.443s
ok  	github.com/carlosframework/platform/internal/hostresolve	0.143s
ok  	github.com/carlosframework/platform/internal/hostwrite	0.017s
ok  	github.com/carlosframework/platform/internal/infraview	0.016s
ok  	github.com/carlosframework/platform/internal/instancectl	4.160s
ok  	github.com/carlosframework/platform/internal/instanceexec	2.739s
ok  	github.com/carlosframework/platform/internal/instancefs	0.021s
ok  	github.com/carlosframework/platform/internal/instancekey	0.017s
ok  	github.com/carlosframework/platform/internal/instanceupdates	0.022s
ok  	github.com/carlosframework/platform/internal/layout	1.498s
ok  	github.com/carlosframework/platform/internal/lease	9.817s
ok  	github.com/carlosframework/platform/internal/lease/leasetest	0.005s
ok  	github.com/carlosframework/platform/internal/ledger	0.011s
ok  	github.com/carlosframework/platform/internal/mail	0.155s
ok  	github.com/carlosframework/platform/internal/maintenance	0.085s
ok  	github.com/carlosframework/platform/internal/maintenanceexec	5.524s
ok  	github.com/carlosframework/platform/internal/maintenanceguard	0.072s
ok  	github.com/carlosframework/platform/internal/metrics	0.004s
ok  	github.com/carlosframework/platform/internal/moves	21.160s
ok  	github.com/carlosframework/platform/internal/moves/archive	0.776s
ok  	github.com/carlosframework/platform/internal/objstore	0.177s
ok  	github.com/carlosframework/platform/internal/ops	0.181s
ok  	github.com/carlosframework/platform/internal/park	0.212s
ok  	github.com/carlosframework/platform/internal/privatefile	0.004s
ok  	github.com/carlosframework/platform/internal/provision	16.770s
ok  	github.com/carlosframework/platform/internal/publicrelease	0.009s
?   	github.com/carlosframework/platform/internal/regionname	[no test files]
ok  	github.com/carlosframework/platform/internal/registry	4.910s
ok  	github.com/carlosframework/platform/internal/relay	7.239s
ok  	github.com/carlosframework/platform/internal/release	19.964s
ok  	github.com/carlosframework/platform/internal/rollout	3.774s
ok  	github.com/carlosframework/platform/internal/rolloutwords	0.004s
ok  	github.com/carlosframework/platform/internal/rootaws	0.006s
ok  	github.com/carlosframework/platform/internal/rootparticipation	0.006s
ok  	github.com/carlosframework/platform/internal/rootstate	0.025s
ok  	github.com/carlosframework/platform/internal/runs	0.559s
ok  	github.com/carlosframework/platform/internal/s3compat	0.005s
ok  	github.com/carlosframework/platform/internal/safefile	0.005s
ok  	github.com/carlosframework/platform/internal/schedule	2.483s
ok  	github.com/carlosframework/platform/internal/seeds	0.012s
ok  	github.com/carlosframework/platform/internal/sim/hostlife	9.547s
ok  	github.com/carlosframework/platform/internal/sim/litestreamfacts	3.720s
ok  	github.com/carlosframework/platform/internal/status	0.037s
ok  	github.com/carlosframework/platform/internal/steering	0.005s
ok  	github.com/carlosframework/platform/internal/stopevidence	0.202s
ok  	github.com/carlosframework/platform/internal/svcrole	0.002s
ok  	github.com/carlosframework/platform/internal/telemetry	0.004s
ok  	github.com/carlosframework/platform/internal/termfence	0.004s
ok  	github.com/carlosframework/platform/internal/tunnelclient	0.003s
ok  	github.com/carlosframework/platform/internal/unixdial	0.002s
ok  	github.com/carlosframework/platform/internal/updatewords	0.004s
ok  	github.com/carlosframework/platform/internal/usage	0.004s
ok  	github.com/carlosframework/platform/internal/version	0.001s
ok  	github.com/carlosframework/platform/internal/vet	1.556s
=== cross ===
--- shard 0 of 5 ---
cross-compiling darwin/arm64
--- shard 1 of 5 ---
cross-compiling darwin/amd64
--- shard 2 of 5 ---
cross-compiling linux/arm64
linux/arm64 carlos binary: 46399650 bytes (ceiling 52000000)
--- shard 3 of 5 ---
cross-compiling windows/amd64
--- shard 4 of 5 ---
cross-compiling windows/arm64
=== minio-contract ===
minio contract: arm64, minio RELEASE.2025-09-07T16-13-09Z, mc RELEASE.2025-08-13T08-35-41Z
  minio: downloading https://github.com/minio/minio/releases/download/RELEASE.2025-09-07T16-13-09Z/minio.linux-arm64.RELEASE.2025-09-07T16-13-09Z
  minio: downloaded, digest verified
  mc: downloading https://github.com/minio/mc/releases/download/RELEASE.2025-08-13T08-35-41Z/mc.linux-arm64.RELEASE.2025-08-13T08-35-41Z
  mc: downloaded, digest verified
  minio healthy on 127.0.0.1:20999
Added `local` successfully.
Bucket created successfully `local/contract-bucket`.
Bucket created successfully `local/denied-bucket`.
Created policy `contract-only` successfully.
Added user `scopeduser` successfully.
Attached Policies: [contract-only]
To User: scopeduser
  buckets and scoped user ready
=== RUN   TestDeliveredContractMinio
=== RUN   TestDeliveredContractMinio/put
=== RUN   TestDeliveredContractMinio/get_round-trips_the_body
=== RUN   TestDeliveredContractMinio/list_shows_the_key
=== RUN   TestDeliveredContractMinio/head_and_list_agree_on_the_version
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed
=== RUN   TestDeliveredContractMinio/delete_removes_it
=== RUN   TestDeliveredContractMinio/cross-bucket_denial
--- PASS: TestDeliveredContractMinio (0.02s)
    --- PASS: TestDeliveredContractMinio/put (0.00s)
    --- PASS: TestDeliveredContractMinio/get_round-trips_the_body (0.00s)
    --- PASS: TestDeliveredContractMinio/list_shows_the_key (0.00s)
    --- PASS: TestDeliveredContractMinio/head_and_list_agree_on_the_version (0.00s)
    --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload (0.00s)
    --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route (0.01s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed (0.00s)
    --- PASS: TestDeliveredContractMinio/delete_removes_it (0.00s)
    --- PASS: TestDeliveredContractMinio/cross-bucket_denial (0.00s)
PASS
ok  	github.com/carlosframework/platform/internal/objstore	0.022s
=== RUN   TestT4StorageProbeMinio
2026/10/15 13:32:02 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18DEB730ED0BBECA, HostID: 7c420053e0fbcd7f41653fdd92ffa2802c903d05303b1aa15adc2e8bb65d183f, api error SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
--- PASS: TestT4StorageProbeMinio (0.00s)
PASS
ok  	github.com/carlosframework/platform/internal/host	0.020s
minio contract: PASS
diff --git a/docs/superpowers/plans/2026-10-15-moves-home-region-part2.md b/docs/superpowers/plans/2026-10-15-moves-home-region-part2.md
new file mode 100644
index 000000000..56c311d6f
--- /dev/null
+++ b/docs/superpowers/plans/2026-10-15-moves-home-region-part2.md
@@ -0,0 +1,317 @@
+# Moves into the home region (home-region part 2) Implementation Plan
+
+> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
+
+Rev 1, 2026-10-15. Paul approved starting part 2 on 2026-10-15. Written against `main` at a5003aba. Tracking thread: amadan #236.
+
+**Goal:** Let a Phase 1 move name the home region as its target, under host claims, with the same guarantees a move between two named regions has. That means the commit, a clean or dirty rollback, abort, declare-lost, and the parks in home after the commit. Today the door refuses every such move (MV-N21: "moves to the home region are not supported yet. the home publishes no staging lane").
+
+**Architecture:** Almost all of the box and claim machinery already handles a home target. Part 1 (359e8ac2) maps every record code to an engine region once (`park.PlacementRegion`: the home's `""` is `@home`). Claim Plan 13 (a0806e4c, 2ad5412c) keeps the home box's roster name (for example `ie`) as its claim engine region, grants the `@home` alias only when the signed roster entry equals the signed fleet home designation, and compares the two names through one rule (`regionname.SameRegion` under `op.intent.home_region`). `BeginAdmittedMove` already start-guards both spellings for a home target, `ClaimMoveRosterPlaces` already maps a home roster box to `@home`, and region HA's `ConvertCommittedLanding` already accepts a landing whose `to` is `@home`. What is missing is narrow:
+
+1. **The console door.** It refuses `to == ""` outright. Behind that refusal, its staging capability (`placements()`) skips every edges file without a `placement`, which is exactly the home box, so the home never reads as stageable. Three of its sentences would print the raw code (`""`) for the home. And nothing stops a box whose `CARLOS_REGION` equals the home's name from being picked as a home target, which that box cannot serve.
+2. **T3 on the home box.** `moves.CompareEnv` reports `region-missing` whenever the source sets `CARLOS_REGION` and the target does not. A home box never sets it (`agentOwnedVars` adds it only when the box has a region). So every move into home fails T3 and waits at `preparing` for ever. Moves out of home pass only because the loop runs over the source's variables.
+3. **Proof.** No test runs a move into home through the real box paths. The harness hard-codes the target as `uk`, and its held-env composer sets `CARLOS_REGION=uk`, which would hide gap 2.
+
+Everything else (the staging lane, the lease key, Touch, Commit, the rollback halves, the parks, the loss path) is already written region-agnostically and needs witnesses, not code.
+
+**Tech Stack:** Go; `internal/console`, `internal/moves`, `internal/host` (tests), `internal/hostclaim` and `internal/hostops` (tests only).
+
+**Spec:** move-any-app design rev 7.22 (`docs/superpowers/specs/2026-10-02-move-any-app-design.md`): §2 and §7.1 (the refusal of "a target of home", F2), §7.3 (staging lane and lease, T1 to T13), §7.6 (landing), §7.9 and §7.10 (rollback, return lane, declare-lost), §16 F2 ("Moves into home": `CARLOS_HOME_PLACEMENT`, home as a target, `carlos move back`). Task 0 amends §2, §7.1 and §16. Claim rev 6.33 (Plan 13's Task I) for the home alias. Index: `2026-10-06-moves-phase1-0-index.md`; D6, D13, D14 and D15 bind every task here. Part 1: `git show 359e8ac2`. Plan 13: `docs/superpowers/plans/2026-10-12-host-lifecycle-claim-13-home-region.md` on `design-replica-ownership`.
+
+## Global Constraints
+
+- **Off means off.** Every change is behind `CARLOS_MOVES_PHASE1` (D13). The legacy door (switch off) keeps its own refusal, em dash and all, unchanged. With the switch on, a home target is admitted **only on a host-claim console** (`s.cfg.HostClaim` with a claim runtime). The plain Phase 1 path keeps refusing it before any write (Ruling R1).
+- **One region rule.** A record code becomes an engine region only through `park.PlacementRegion`. Two engine regions are compared only through `park.SameRegion` / `regionname.SameRegion` under the operation's `home_region`, or `park.PlacementMatches` for a code against an engine region. No new `==` between a placement code and an engine region: `TestPlan13NoDirectPlacementEngineComparison` (`home_region_comparison_test.go`) must stay green. No moves call site may pass the home box's roster name where a placement-derived region is meant (Review Focus 1).
+- **Empty is unset.** `""` stays unset at every engine and claim boundary. Do not make `Validate`, `parkQueueGuard`, `AdmitWriter`, `PublishGeneration` or `Cover*Predecessors` accept it (Plan 13's constraint, kept).
+- **No claim or region HA code changes.** This plan writes tests in `internal/hostclaim` and `internal/hostops` only where they drive moves' own call sites. Anything that would change claim or region HA behaviour is an ask (below), not a task.
+- **Cold only (P7, D14); one-box regions only (D15).** Nothing here relaxes either. T8 and S1 keep counting every edges file that publishes the placement (Ruling R2).
+- **Copy.** Every new operator-facing string is a `pending` row in `2026-10-06-moves-phase1-copy.md` in the commit that writes it, and in `movesCopyIDs` (`approved_moves_copy_test.go`). Ids MV-N510 to MV-N529 are reserved for this plan (checked free on every branch on 2026-10-15). No em dashes anywhere: a full stop and a new sentence, lower case where the door's sentences are lower case.
+- **Gate.** While iterating, targeted runs only: `go test ./internal/moves ./internal/console -run 'Home|MoveDoor|CompareEnv' -count=1` and `go test ./internal/host -run 'Home|Plan13' -count=1`. Never run the whole `internal/host` suite locally; CI's `make test` is the full run (Paul, 2026-10-12). Before handing off, once: `go build ./...`, `go vet ./...`, `gofmt -l .`, the copy gate (`go test . -run 'Moves|Copy' -count=1`) and the cross-compile (`GOOS=darwin`, `GOOS=windows`, `GOOS=linux GOARCH=arm64` `go build ./...`). The Go build cache stays at its default. Use `GOFLAGS=-buildvcs=false` if the worktree's VCS metadata is unreadable from the sandbox. Tests serial and niced; no `internal/sim/hostlife` sweep.
+- **Nothing rolls without Paul's go.** Merge only on amadan with `amadan branch merge -squash`, after re-merging `main` and a green CI on the tip.
+
+## What already exists (do not rebuild)
+
+| piece | where | what it already does for a home target |
+|---|---|---|
+| home's engine region | `internal/regionname`, `park.HomeRegion`, `park.PlacementRegion` | `""` maps to `@home`; `@home` is outside the placement alphabet |
+| the alias | `regionname.SameRegion`, `claimRegionBinding` (`internal/host/claimregion.go`), `Roster.MatchesHome` | the roster name and `@home` are one region only under a verified designation |
+| the start CAS | `hostops.BeginClaimMove`, `ClaimMoveRosterPlaces`, `hostclaim.BeginAdmittedMove` | maps a home roster box to `@home`; writes `op.intent.to = @home` and `home_region`; start-guards both spellings (CC11 over `ie` and `@home`) |
+| the home lane's lease | `stagingLeaseKey` (`internal/host/movespass.go`) | `control/staging-leases/@home/<host>` in the deployment bucket, for every caller that passes a record code |
+| the source finds home's bucket | `loadMoveFleet` (`internal/host/movesreport.go`) | keeps the placementless box under `""`, so `fleet.targets[""]` is the home box's `data_bucket` |
+| T8, T9, T12 | `checkOneOwner`, `checkClaim`, `checkQuiet` | name home by the operation's home name; T9 accepts either spelling in `touched`; T12 reads the later of both quiet keys (`TestPlan13HomeTargetReadiness`, `TestPlan13MoveQuietReadsLegacyAndHomeToken`) |
+| arming on the home box | `armMovesParks` | arms only when the claim grants the `@home` alias; T13 fails closed otherwise |
+| parks under either name | `park.Engine.OwnsRegion`, `hostbox.Regional.Run`, the moves filters (`PlacementMatches(cfg.ParkHomeRegion, cfg.Region, o.Region)`) | `region:@home` chores run on the home box's moves engine and its regional runner |
+| predecessor cover | `hostclaim.CoverRegionPredecessors` | compares through `SameRegion` under the op's home binding |
+| fence and loss | `MoveFenceRegions`, `VerifyMoveTargetFence`, `move_loss_owner.go` | a home target's fence binding maps to `@home` (`TestPlan13FenceRecoveryHomeAndNamed`, "target-home") |
+| committed landing on a dead target | `hostclaim.ConvertCommittedLanding` (region HA) | accepts `to = @home` under the op's binding; the relocation's `intent.region` is the roster name |
+| authoritative region | `movesAuthoritative` (`internal/host/movessources.go`) | landing and restoring compare through `SameRegion`; the source stays protected until commit or return (J2/F4) |
+
+## Answers to the brief's questions
+
+**Q1. What is missing for a move whose target is home.**
+
+- **Staging lane.** Bucket: the home box's own data bucket, `CARLOS_HIBERNATE_BUCKET`, which its edges file publishes as `data_bucket` with no `placement`. Lease: `control/staging-leases/@home/<host>` in the deployment bucket (part 1's `stagingLeaseKey`). Lane keys: `moves/<host>/<move id>/...` in the home bucket, written by the named source under its `sibling_staging_arns` grant (M17). Who publishes it: the home box's edges-file pass already publishes the coordinates; the console just does not read them (`placements()` skips a file with no `placement`). Task 4 adds a move-only fold. Nothing new is published.
+- **How the source finds the bucket and the ARNs.** It already does: `loadMoveFleet` keys the home box under `""`, and every source step looks up `fleet.targets[rec.Move.To]`. IAM is infra: every named region's `sibling_staging_arns` must list the home data bucket's ARN (the source pushes the lane into it), and the home box's must list every named bucket (the home target's T10 probe and its dirty return lane). M17's mesh ("every region lists every other region's data bucket") already says this; P-2 of the runbook has to check that the home bucket is in it (Task 5).
+- **T1 to T13 on a home box.** All but T3 already work (table above). T3 is gap 2: `CompareEnv` must accept a home target that sets no `CARLOS_REGION` (Task 1). T8 has a deployment precondition, not a code gap: exactly one edges file in the deployment may lack a `placement` (Ruling R2).
+- **Landing on a home box.** Already written: the landing runs on the box the claim names, queues its earlier-stay residue as `park-generation` chores under `@home` (D6), and commits with `Commit(id, PlacementRegion(From), source, @home, ...)`. The probe's admission records the home box's engine region, its roster name. Task 2 proves it end to end.
+- **Rollback and return lanes (source named, target home).** The home box releases with `TargetReleased(..., @home, ...)`, which matches `op.intent.to` exactly; its cleaning park and the move's lane park are queued under `@home`; a dirty return lane is written by the home box into the named source's bucket under `control/staging-leases/<source>/<host>`, and `QueueReturnLanePark` names the source region. Task 3 proves each.
+- **Parks in home after the commit.** Two kinds, both under `@home` and owner `region:@home`: the staging lane's `park-replica` (queued by `Commit`) and the residue `park-generation` chores of an earlier stay (queued at the landing's `parking` step, including the legacy root generation `@root` of a host that was created in home). The home box's moves engine runs the immediate half; `hostbox.Regional` on the home box acknowledges them (Plan 13 Review Focus 2). The source's location park runs in the named source region.
+- **The `@home` alias in Touch, Commit and Release.** Touch: the source adds `PlacementRegion(To)`, which is `@home`, and the target box; the start CAS already guarded both spellings. Commit: `targetRegion` is the home box's `parkRegion()`, `@home`, which matches `op.intent.to` exactly; the source's quiet key is the named region. Release: `TargetReleased` passes `@home`; `ReleaseMove` and the K8 release name no region. Every one of these comparisons is exact on the claim side, and that is safe only because moves always passes `@home`, never the roster name. Task 2's `TestHomeTargetObligationsUseTheHomeToken` pins it (Review Focus 1, Ask A1).
+- **How the door resolves `--to`.** As today: `homeRegionIn` maps the console's home name (`CONSOLE_HOME_REGION`, or the claim-mode fallback `dbClaimHomeRegion`) to `""`. No `home` keyword (Ruling R3): a named region called `home` stays a named region, as Plan 13 rules. With no home name configured the home cannot be named, and the request is `invalid region` as today.
+
+**Q2. Claim-side and region HA changes.** None required. Four confirmations and one optional hardening are listed under Asks. The design keeps the claim's exact comparisons as they are and pins moves' side of the contract with tests.
+
+**Q3. What is shared with part 1, and the failure modes.** Shared: `park.PlacementRegion`, `stagingLeaseKey`, `cfg.parkRegion()`, `moveFleet`'s home key, the engine bindings (`ParkHomeRegion`), the predecessor mapping and the park view's J2/F4 rule. Part 2 adds no new mapping. The failure modes are listed in Review Focus and in "Failure modes" below.
+
+**Q4. Rollout and Run 4.** See "Rollout order" and "Rehearsal changes" below. Run 4 itself does not need moves into home. It needs Runs 2 and 3, which as written move into home.
+
+## Review Focus
+
+1. **One region, two names (Plan 13's dedupe rule).** The claim compares `op.intent.to` exactly in `Abort`, `Revert`, `TargetReleased`, `QueueStagingPark`, the loss and fence paths, and in `requireRetiredRegion` (`internal/hostclaim/move.go:549`). For a home target `to` is `@home`. If any moves call site passed the home box's roster name (`ie`) instead, most of these refuse (fail closed), but `requireRetiredRegion`'s `region != to` would read `ie` as "not the target" at `landing/committed` and allow a whole-location park in the live home region. The park view still protects the live generation there (`movesAuthoritative` answers `@home`, compared through `SameRegion`), so it is defence in depth, but the reviewer should check every moves call site that hands the claim a region on the home box, and the test that pins them (Task 2, `TestHomeTargetObligationsUseTheHomeToken`). The staging lease is the other place: a key spelled with the roster name would split the lane's lease from the source's `@home` key and let two writers stage at once. `TestHomeLaneStagingLeaseKey` already pins the key for a record code; Task 2 adds the into-home direction.
+2. **T3's home rule.** A home target must set no `CARLOS_REGION`; a named target must still set its own, different from the source's. A target in home that does set one is a box that is not the home box, and T3 must fail it (`region-present`), not wave it through (Task 1).
+3. **The door's home capability must not leak into create.** `placements()` feeds the create gate's `published` flag and `armedPlacements`; adding `""` there would change create. Task 4 folds the home only in a move-only reader, and `TestCreatePlacementsUnchangedByHomeFold` pins create.
+4. **A home-named box is not a home box.** A box with `CARLOS_REGION=<home name>` is home to the console (`homeRegionIn`) but not to itself (no alias; its `cfg.Region` is `ie`, so it never writes a target report, and the source's `fleet.targets[""]` never finds it). The door must refuse it as a home target before any claim write (MV-N511).
+5. **Parks after the commit, from both engines.** The home box runs `@home` chores from its moves engine (region `@home`) and from `hostbox.Regional` (region = roster name, alias `@home`). Both must acknowledge the same chore once, and a named box must never acknowledge either (`TestPlan13NamedBoxCannotAcknowledgeHomeDelete` covers the named side; Task 3 covers the lane park on the home side).
+
+---
+
+## File structure
+
+| path | responsibility |
+|---|---|
+| `docs/superpowers/specs/2026-10-02-move-any-app-design.md` | §2, §7.1, §16 F2 amendment (Task 0) |
+| `internal/moves/envreport.go` | T3's home rule in `CompareEnv` (Task 1) |
+| `internal/host/movesreport.go` | `checkEnv` passes the home target to `CompareEnv` (Task 1) |
+| `internal/host/movesphase1_harness_test.go` | the `intoHome` harness option (Task 2) |
+| `internal/host/moveshome_target_test.go` | new: the into-home witnesses (Tasks 2 and 3) |
+| `internal/console/apiinstancemove.go` | the door's home-target rules (Task 4) |
+| `internal/console/instancesplacement.go` | `movePlacements`, the move-only home fold (Task 4) |
+| `internal/console/boxselect.go` | the target's placement, one home name (Task 4) |
+| `internal/console/apiinstancemove_home_test.go` | new: the door's home-target tests (Task 4) |
+| `docs/superpowers/plans/2026-10-06-moves-phase1-copy.md`, `approved_moves_copy_test.go` | rows MV-N510 to MV-N512, MV-N21 withdrawn |
+| `docs/superpowers/plans/2026-10-06-moves-phase1-rehearsal.md` | P-0, P-2, Run 1b, Runs 2 to 4, Run 6 (Task 5) |
+
+---
+
+### Task 0: Spec amendment
+
+**Files:** modify `docs/superpowers/specs/2026-10-02-move-any-app-design.md`.
+
+- [ ] §2: "between two non-home, non-fleet placements or out of home" becomes "between two non-fleet placements, into home only with host claims on".
+- [ ] §7.1's refusal list: "a target of home" becomes "a target of home on a console without host claims, or a home target box that sets a region code of its own".
+- [ ] §16 F2: home as a target is delivered by this plan. `CARLOS_HOME_PLACEMENT` is superseded by Plan 13's signed fleet home designation, which names home once for every reader; no environment variable is added. `carlos move back` stays a follow-on (Ruling R3).
+- [ ] A spec header line for the revision, citing this plan and #236.
+- [ ] Commit: `git commit -m "spec: moves into home (part 2), §2, §7.1, §16 F2"`.
+
+---
+
+### Task 1: T3 accepts a home target that sets no region
+
+**Files:** modify `internal/moves/envreport.go`, `internal/host/movesreport.go`; tests in `internal/moves/envreport_test.go` (extend) and `internal/host/moveshome_target_test.go` (create).
+
+**Interfaces:**
+- `moves.CompareEnv(source, target EnvReport, flatLayout, targetHome bool) []EnvDiff`. Every existing caller passes `targetHome` explicitly; there is one production caller (`checkEnv`) plus tests.
+- For the region class:
+ - `targetHome` false: unchanged (`region-missing` when the target lacks it, `region-same` when equal).
+ - `targetHome` true: the target must **not** carry `CARLOS_REGION`. Absent is no diff. Present is `EnvDiff{name, "region-present"}`, checked in both loops (the source may or may not carry it: a move between two home boxes is refused at the door, but T3 does not rely on that).
+- `checkEnv` passes `targetHome := rec.Move.To == ""`. That is a record-code test on a record code, which the lint allows. It must not be derived from `cfg.Region`: a second placementless box is a T8 failure, not a T3 pass.
+- `region-present` is a fill-in token inside MV-N129's list (`<NAME (kind)>, ...`), so it gets its own row (MV-N512), as MV-N146's fill-in did.
+
+**Tests:**
+- `TestCompareEnvHomeTargetSetsNoRegion`: source with `CARLOS_REGION=uk`, target without, `targetHome` true: no diff. The same pair with `targetHome` false: `region-missing` (today's rule kept). Target with `CARLOS_REGION=ie` and `targetHome` true: `region-present`. Source without and target without, `targetHome` true: no diff.
+- `TestHomeTargetT3FromTheRealComposition`: build the home box's held environment through the production composer (`agentOwnedVars` with no region) rather than the harness's fixture, so the test fails today and passes after the fix. Assert the target report's T3 is `ok`.
+- `TestNamedTargetT3Unchanged`: the existing T3 tests pass with `targetHome` false at every call.
+
+**Copy:** MV-N512 (below), pending.
+
+- [ ] Write the failing tests; implement; targeted runs; commit with the copy row and the inventory line: `git commit -m "moves: T3 accepts a home target that sets no region (home part 2)"`.
+
+---
+
+### Task 2: The into-home harness and the commit witness
+
+**Files:** modify `internal/host/movesphase1_harness_test.go`; create `internal/host/moveshome_target_test.go` (Task 1 created it; extend).
+
+**Harness option `intoHome`.** It mirrors `fromHome` (`h.src = ""`) for the target:
+- the source is placed in a named code that is not the home's name (use `ca`), with box `ca-box` and bucket `data-ca`, so no fixture name suggests home and the home's name never collides with the source (today's fixture hard-codes `ie-box` and `data-ie` in several places; parameterize them as `fromHome` parameterized the source's code);
+- the target is `home-box`, placement `""`, bucket `data-home`, AWS region `eu-west-1`; its edges file has `data_bucket` and no `placement`;
+- the roster names `home-box` in region `ie` and carries the fleet designation `home_region: ie`; the claim's op carries `home_region: ie`; the target's `moveCfg.ParkHomeRegion` is `ie`, as `armMovesParks` would set it;
+- the target's held-env composer sets **no** `CARLOS_REGION` (the current fixture's `env["CARLOS_REGION"] = "uk"` would hide Task 1's gap);
+- the start uses `BeginAdmittedMove(..., PlacementRegion(""), MoveAdmission{HomeRegion: "ie", ...})`, as the claim-mode door does, not the plain `BeginMove`.
+
+**Tests (each cites the path it drives):**
+- `TestMoveIntoHomeStagesTheHomeLane`: the source round writes `move.json` and the replica lane into `data-home` under `moves/<host>/<id>/`; it takes the lease `control/staging-leases/@home/<host>` and no other; `Touch` adds `@home` and `home-box`; `touched.regions` gains neither `""` nor `ie` from moves.
+- `TestMoveIntoHomeTargetChecksPass`: on `home-box`, T1 to T13 are all `ok`. T8 names the home by its name. T10 probes `data-ca`. T12 refuses inside a quiet window recorded under either `ie` or `@home`.
+- `TestMoveIntoHomeCommitsAndCloses` (through the real cut, flip, landing, probe and commit, as `TestMoveFromHomeClosesThroughTheSourcePark` does for part 1):
+ - an earlier home stay is seeded in `data-home` (a root generation and one named generation); the landing queues one `park-generation` per residue generation under `@home`, owner `region:@home`, and none for the install's own;
+ - the commit queues the source's location park under `ca`, the lane park under `@home`, and covers the source's predecessor; `quiet_after` gains `ca` and never `""`;
+ - the probe's admission records `home-box` with the home box's engine region, and its `PredecessorRegion` is `ca`;
+ - after the horizon, the home box's engine acknowledges the lane park, the source parks its location, and the record closes with `Region == ""` and `LastMove.Outcome == "done"`;
+ - the result can move out of home again: `ClaimMoveRosterPlaces` and the source round accept a second move `"" -> ca` (part 1's path).
+- `TestHomeTargetObligationsUseTheHomeToken`: over the whole of the previous test and Task 3's rollback test, every obligation that moves code queued for the target side names `@home` and owner `region:@home`; none names `ie` or `""`; every `op.intent.to` the claim compared was `@home`. This is Review Focus 1's pin.
+
+- [ ] Write the tests; fix only what they prove broken (expected: nothing outside Task 1); targeted runs; commit: `git commit -m "moves: into-home harness and commit witness (home part 2)"`.
+
+---
+
+### Task 3: Rollback, abort, loss and conversion with a home target
+
+**Files:** extend `internal/host/moveshome_target_test.go`; where a test must drive a console grant, add it to `internal/hostops/move_home_target_test.go` (create).
+
+**Tests:**
+- `TestMoveIntoHomeCleanRollback`: the probe fails before any write. `TargetReleased` names `@home` and matches `op.intent.to`; the cleaning park of `home-box`'s location and the move's lane park are queued under `@home`; the source reopens on `ca-box` with `holder.generation = src_gen`; the record ends `rolled_back`; nothing is parked in `data-ca` that the source still serves (J2/F4 through `restoring`).
+- `TestMoveIntoHomeDirtyReturn`: the probe writes, then fails. `home-box` seals its installation and writes the return lane into `data-ca` under `control/staging-leases/ca/<host>`; `QueueReturnLanePark` names `ca`; the source installs the return, and the pre-move generations park after the return (D6), not before.
+- `TestMoveIntoHomeAbortParksTheHomeLane`: abort before the flip. `Abort` queues the lane park under `@home`; the home box's moves engine runs it; `hostbox.Regional` on the home box (region `ie`, alias `ie`) acknowledges it after the horizon; a named box's runner refuses it; the record clears only after that (Plan 5 Task 1's rule).
+- `TestMoveIntoHomeDeclareLost` (hostops): a home target stopped mid-landing and declared lost through Plan 4 Task 10's door. The loss intent's `TargetRegion` is `@home`; the source is re-admitted with the loss; the record shows `loss_ref`. It reuses Plan 13's `TestPlan13FenceRecoveryHomeAndNamed` fixture rather than a new one.
+- `TestCommittedLandingIntoHomeConvertsOnTargetFence`: after the commit, `home-box` is fenced as terminated. `hostclaim.ConvertCommittedLanding` turns the claim into `relocating` with `intent.region = ie` (the roster name), `move_to_region = @home`, and keeps the lane park under `@home` and the source's finalization chores. Region HA reviews this test (Ask H1). It changes no region HA code.
+
+- [ ] Write the tests; any production fix they force is in moves' code only, and a failure that points into claim or region HA code becomes an ask on #236, not a patch; targeted runs; commit: `git commit -m "moves: into-home rollback, abort, loss and conversion witnesses (home part 2)"`.
+
+---
+
+### Task 4: The door admits a home target under host claims
+
+**Files:** modify `internal/console/apiinstancemove.go`, `internal/console/instancesplacement.go`, `internal/console/boxselect.go`; create `internal/console/apiinstancemove_home_test.go`; the copy record and `approved_moves_copy_test.go`.
+
+**Interfaces:**
+- `movePlacements(ctx, s release.Store) (caps map[string]placementCapability, published bool)`: `placements()` plus the home, folded under `""` from every edges file with no `placement`. Same reachability rule: no `eip`, no capability. Staging is `data_bucket != ""`. `published` keeps `placements()`'s meaning, so a home-only fleet still reads "publishes no armed regions". `placements()` and `armedPlacements()` are unchanged.
+- `(s *Server) stagingNames(caps) string`: `stagingCodes` with each code passed through `homeRegionOut`, so MV-N20's list names the home by its name.
+- `moveSelection` gains `TargetPlacement string`: the target's edges-file `placement`, as published.
+- `selectMoveBoxes` and `verifiedRoster` take the home name from one helper, `s.moveHomeName()`: `dbClaimHomeRegion()` with host claims, `cfg.HomeRegion` without. That is the name `homeRegionIn` already uses, so `eligibleBoxes` and the door agree when the console's home is the claim-mode fallback.
+
+**The Phase 1 request door, in order (`handleAPIInstanceMoveRequest`):**
+1. `to == ""` and not a host-claim console: refuse with MV-N510 (400) before any read or write. This replaces MV-N21 on this path.
+2. `to == rec.Region`: unchanged (MV-N16, filled through `homeRegionOut`).
+3. The manifest rule: a home target is allowed when some entry of `m.Regions` maps to `""` through `homeRegionIn`, or the list is empty. Named targets keep `slices.Contains`. MV-N2 fills `<to>` through `homeRegionOut`. Before writing this step, read the create door's rule (`instanceRegionAllowed` at `apiinstances.go:1268` and `regionchoices.go:23-41`). If create treats a home entry differently, follow `regionchoices.go`'s `homeRegionIn` mapping and record the difference in the task's report as a finding for the create door.
+4. Staging: `movePlacements` in place of `placements`. MV-N20 fills `<to>` and the list through `homeRegionOut` and `stagingNames`.
+5. `selectMoveBoxes` as today. MV-N23 fills `<to>` through `homeRegionOut`.
+6. New: `to == ""` and `sel.TargetPlacement != ""`: refuse with MV-N511 (409), naming the box. Before any claim read.
+7. Everything after (floor, claim, roster, `startClaimModeMove`, `BeginClaimMove`) is unchanged. `MatchesHome` and `ClaimMoveRosterPlaces` already refuse a home target without the designation (MV-N177).
+
+The legacy door (switch off) is not touched. Its em-dash refusal stays until Plan 6 Task 8 retires it.
+
+**Tests (`apiinstancemove_home_test.go`, using the claim test fixture of `apiinstancemove_claim_test.go`):**
+- `TestMoveDoorClaimModeAcceptsHomeTarget`: `--to ie` on a console whose home is `ie`, a roster with the designation, a placementless home box with a data bucket: 202. The claim is `moving` with `intent.to = @home` and `intent.home_region = ie`; the record's `Move.To` is `""`; the view's `target` is `ie`.
+- `TestMoveDoorPlainPathRefusesHomeTarget`: switch on, no host claims: 400 with MV-N510; the claim and the record are byte-identical before and after.
+- `TestMoveDoorHomeStagingFromItsEdgesFile`: home box without `data_bucket`: MV-N20 naming `ie`; with it: passes. A named-only list names no empty code.
+- `TestCreatePlacementsUnchangedByHomeFold`: `placements()` over a fleet with a placementless box returns the same map and `published` as before this task (Review Focus 3).
+- `TestMoveDoorHomeTargetMustPublishNoPlacement`: the only `ie` box sets `CARLOS_REGION=ie`: 409 with MV-N511; no claim write, no registration.
+- `TestMoveDoorHomeTargetNeedsTheDesignation`: the roster has no `home_region`: MV-N177; nothing registered.
+- `TestMoveDoorManifestNamesHome`: `regions: ["ie","uk"]` allows `--to ie`; `regions: ["uk"]` refuses with MV-N2 naming `ie`, never an empty name.
+- `TestMoveDoorFillsNameTheHome`: MV-N2, MV-N16, MV-N20 and MV-N23 never render an empty region name for a home target.
+- `TestLegacyMoveDoorStillRefusesHome`: switch off: the legacy sentence, byte for byte.
+- The lint (`TestPlan13NoDirectPlacementEngineComparison`) stays green.
+
+**Copy:** MV-N510 and MV-N511 pending. MV-N21 is withdrawn: its row is removed from the record with a note, as MV-N388's was, and from `movesCopyIDs`, in this commit.
+
+- [ ] Write the failing tests; implement; targeted runs plus the copy gate; commit: `git commit -m "console: the move door admits a home target under host claims (home part 2)"`.
+
+---
+
+### Task 5: Rehearsal runbook and index
+
+**Files:** modify `docs/superpowers/plans/2026-10-06-moves-phase1-rehearsal.md`, `docs/superpowers/plans/2026-10-06-moves-phase1-0-index.md`.
+
+- [ ] **P-0, the home item.** Part 2 merged and rolled (boxes, then consoles) is required for any run that moves into home. The rest of the item is unchanged: part 1, Plan 13, and Plan 13's order (readers, then the designation, then the flag). Replace the quoted MV-N21 sentence with "the door refuses moves into home without host claims (MV-N510)".
+- [ ] **P-0, new: one placementless box.** For each deployment, list `control/edges/` and record that exactly one edges file has no `placement`. S1 and T8 refuse a move into **or out of** home while two do (Ruling R2). On dev, `carlos-dev-ie-b` makes two. This also blocks Run 1 today, so it is not part 2's alone.
+- [ ] **P-2.** Every named region's `sibling_staging_arns` lists the home data bucket's ARN, and the home's lists every named data bucket. Record the home data bucket's name and check it is not the deployment bucket.
+- [ ] **Run 1b (new), dev, `uk` to `ie`, a commit into home.** Run 1's host, moved back after Run 1's quiet window (T12). Same checks as Run 1, with `<pr-ie> = home`. Additional checks: the lane is in the home data bucket under `moves/<host>/<move>/`; the claim's `touched.regions` holds `@home`; after the close, `parked/<inc>/<host>/` in the home bucket holds the residue of Run 1's stay, if any; `quiet_after` names `uk`. Blockers: Run 1 passed; part 2 rolled; the designation published on dev; P-0's one-placementless-box item.
+- [ ] **Runs 2 and 3.** Once part 2 is rolled, they run as written (`uk` to `ie`, into home). The out-of-home arrangement stays as the fallback while part 2 is not rolled.
+- [ ] **Run 4.** Unchanged: `ie` to `uk`, with `carlos-dev-uk` stopped. It never stops the home box. Its blocker becomes "Runs 1, 1b, 2 and 3 passed". It does not need moves into home itself.
+- [ ] **Run 6.** "Both parts merged and rolled" stays. The "dev rehearsal from home" blocker becomes "dev Runs 1 and 1b passed".
+- [ ] **Sources table.** Replace the MV-N21 line (`apiinstancemove.go:537-540`) and the `moves-home-parks` "parts 1 and 2" line with this plan and its merge commit.
+- [ ] **Index.** Add a row after Plan 7: "Home part 2: `2026-10-15-moves-home-region-part2.md`".
+- [ ] Commit: `git commit -m "docs: rehearsal and index for moves into home (home part 2)"`.
+
+---
+
+### Task 6: Gate and review
+
+- [ ] The full local gate once (Global Constraints), excluding the whole `internal/host` suite, which CI runs.
+- [ ] Astra (codex, from a committed brief) reviews Review Focus 1 to 5 against the branch. Commit its findings unedited beside this plan as `CODEX-PLAN-MOVES-HOME-PART2-R1.md`; fix and record dispositions here.
+- [ ] Post the branch, the asks and the rulings on #236.
+- [ ] Re-merge `main`, wait for CI, then Paul's go to merge (`amadan branch merge -squash`).
+
+## Copy rows (pending)
+
+To append to `2026-10-06-moves-phase1-copy.md` under a new heading "Moves into home (part 2)", each in its task's commit:
+
+| id | file | text | status |
+|---|---|---|---|
+| MV-N510 | internal/console/apiinstancemove.go | moves into the home region need host claims. this console runs without them | pending |
+| MV-N511 | internal/console/apiinstancemove.go | <box> sets CARLOS_REGION, so it cannot take a move into the home region | pending |
+| MV-N512 | internal/moves/envreport.go (a T3 kind inside MV-N129's list) | region-present | pending |
+
+Withdrawn in Task 4: MV-N21 ("moves to the home region are not supported yet. the home publishes no staging lane"). Fills that change but keep their approved text: MV-N2, MV-N16, MV-N20 and MV-N23 name the home by its name instead of the empty code.
+
+## Failure modes
+
+| # | failure | effect | guard |
+|---|---|---|---|
+| F1 | a moves call site hands the claim the home's roster name where `@home` is meant | most exact checks refuse (fail closed); `requireRetiredRegion` would allow a location park in the live home region | Task 2's `TestHomeTargetObligationsUseTheHomeToken`; the park view's live-set rule; Ask A1 hardening |
+| F2 | the staging lease keyed by the roster name | two writers on one lane | `stagingLeaseKey` takes record codes only; Task 2 asserts the key |
+| F3 | a box with `CARLOS_REGION=<home name>` chosen as a home target | the move stalls in `preparing` (no target report; the source finds no `targets[""]`) | MV-N511 at the door (Task 4) |
+| F4 | two placementless boxes (dev's `carlos-dev-ie-b`; any agent box without `CARLOS_REGION`) | the door accepts, then S1 or T8 refuses with M-C21 / MV-N166 | Ruling R2; runbook P-0 check |
+| F5 | T3 `region-missing` on a home target | every move into home waits at `preparing` | Task 1 |
+| F6 | a home box on a build without Task 1 | the same wait, with T3's reason in the target report; the operator aborts | roll boxes before consoles (Ruling R5) |
+| F7 | no designation, or the console's home name differs from it | MV-N177 for every claim-mode move; a home box never arms (T13) | Plan 13's rollout order; nothing new |
+| F8 | the IAM mesh lacks the home bucket | the source's lane round fails `AccessDenied`, logged; or T10 fails on the home box | runbook P-2 |
+| F9 | the home box is also the console's box, and it dies mid-landing | the console's move pass stops with it; box-side recovery and the durable records wait for the console's return | Ruling R7 |
+| F10 | the plain Phase 1 path writes `intent.to = ""` | `BeginMove` refuses with `ErrMalformed`, which the door would answer as a 502 | MV-N510 refuses first (Task 4) |
+
+## Rollout order
+
+1. **Plan 13 on every box and console** (on main since 2026-10-12; check each box reads `current` with `carlos system status`). Plan 13's own order still binds: every roster reader on a Plan 13 build, then publish the designation, then turn `CARLOS_HOST_CLAIM` on.
+2. **Part 2 merged** (dormant), released, and rolled **boxes first, then consoles**, so no door admits a home target before every home box has Task 1's T3 rule.
+3. **IAM:** the M17 mesh including the home bucket (P-2), applied by Paul with a scoped `tofu apply -target`.
+4. **Claim activation (#250)**, which publishes the signed designation. Until then a home box never arms and the door refuses claim-mode moves under a configured home name.
+5. **`CARLOS_MOVES_PHASE1`** per run, as the runbook says.
+
+Part 2 adds no switch of its own. A home target is reachable only when the designation exists, the console runs host claims, and the switch is on.
+
+## Rehearsal changes
+
+- Run 1 (`ie` to `uk`) is unchanged, but **today it is blocked on dev by `carlos-dev-ie-b`'s edges file** (S1's `oneBoxRefusal` counts every placementless file). That is a finding against part 1's runbook, raised here because part 2 meets it first. Ruling R2 resolves both.
+- Run 1b (new): `uk` to `ie`, a commit into home, Run 1's host moved back.
+- Runs 2 and 3 return to as written (into home) once part 2 is rolled.
+- Run 4 is unchanged and does not move into home. It gates on Runs 1, 1b, 2 and 3. Stopping the home box for a declare-lost would stop dev's console, which is why Run 4 stays out of home (Ruling R6).
+- Run 5 (flagship) may keep `uk` and `us`. Adding a home leg is optional and is Paul's call when Run 5 is scheduled.
+- Run 6's blockers are met by part 2 merged and rolled plus dev Runs 1 and 1b.
+
+## Rulings needed
+
+Only Paul can decide these. Each has a recommendation.
+
+- **R1. Home targets only under host claims.** The plain Phase 1 path (switch on, claims off) keeps refusing a home target (MV-N510), because it has no designation to resolve home against and its `BeginMove` would write `to = ""`. *Recommend: yes.* Phase 1 cannot land anything in production without claims anyway (its parks arm only with both flags).
+- **R2. Two placementless boxes.** The door counts eligible boxes (D15), but S1 and T8 count every edges file with that placement. On dev, `carlos-dev-ie-b` publishes no placement, so every move into or out of dev's home is refused at S1 or T8. Options:
+ - (a) keep the box rule, and take `carlos-dev-ie-b` out of `control/edges/` for the rehearsal window: stop it, delete its edges file (it rewrites the file when it boots), and record both in the runbook;
+ - (b) change S1 and T8 to count eligible boxes, as the door does. That is a moves design change: the box would need the roster and `boxchoice.Eligible`;
+ - (c) rehearse moves into home on the flagship only.
+ *Recommend (a).* The box rule is the safer one. A second placementless box reconciles every unregioned record, so after a landing into home both boxes would hold a row for the host (amadan #286's hazard), which is what T8 exists to refuse. It also unblocks Run 1 today.
+- **R3. `--to` vocabulary and `carlos move back`.** The door accepts the home's configured name only, as every other surface prints it; there is no `home` keyword, because a named region may be called `home` (Plan 13). `carlos move back` stays a follow-on, as spec §16 F2 lists it. *Recommend: yes to both.*
+- **R4. Copy.** Approve MV-N510 to MV-N512 and the withdrawal of MV-N21 (copy review). *Recommend: review with the branch, before merge.*
+- **R5. No protocol floor bump.** Task 1 changes the box's T3. A home box without it fails T3 and waits (fail closed), and the operator aborts. Bumping `moves.ProtocolVersion` to 2 would make the door refuse up front, but it would also refuse every move, to any region, until every box of both regions rolls. *Recommend: no bump; roll boxes before consoles*, as the release recipe already says.
+- **R6. Run 4 stays out of home** (`ie` to `uk`), and the runbook gains Run 1b. *Recommend: yes.*
+- **R7. A home target on the console's own box.** Where the console shares the home box, a landing into home puts the console on the move's target. If that box dies mid-landing, the console's move pass dies with it until the box or the console is restored. The records and the claim are durable, so nothing is lost, but recovery waits. *Recommend: accept, and note it in the runbook's Run 1b.* The alternative is refusing a home target whose box runs the console, which no edges field states today.
+
+## Asks
+
+None blocks this plan. Each is a confirmation unless it says otherwise. Post them on #236.
+
+**To platform-1e (the claim):**
+
+- **A1. The exact-region contract, and one optional hardening.** Moves' contract is: every region moves hands to `Abort`, `Revert`, `Commit`, `TargetReleased`, `QueueStagingPark`, `QueueResidueParks`, `QueueReturnLanePark` and `Touch` is a placement-derived engine region (`park.PlacementRegion` of a record code, so `@home` for home), never a roster name. Task 2 pins it. Please confirm the claim keeps its exact `intent.to` comparisons on that basis. Optional hardening, recommended: compare `requireRetiredRegion` (`internal/hostclaim/move.go:549`) through `regionname.SameRegion` under `op.intent.home_region`, so a roster-name caller can never read the live home as "not the target" (Review Focus 1).
+- **A2. The home regional runner.** Confirm `hostbox.Regional` on a home box acknowledges `region:@home` `park-replica` lane chores and `park-generation` residue chores queued by a landing into home (Plan 13 Review Focus 2). Task 3 runs it against the real runner.
+- **A3. No further claim gate.** Confirm that beyond Plan 13's designation nothing in the claim refuses a `moving` op with `intent.to = @home` (`BeginAdmittedMove` already start-guards both spellings).
+
+**To region HA (relocation):**
+
+- **H1. The committed-landing conversion into home.** Review Task 3's `TestCommittedLandingIntoHomeConvertsOnTargetFence`: `intent.region` is the roster name, `move_to_region` is `@home`, and the lane parks and the source's finalization chores are kept. No code change is expected.
+- **H2. The two-box model.** Moves into home stay one-box (D15, T8 and Ruling R2), so the two-box `internal/sim/hostlife` model needs no new scenario. Confirm, or name the scenario.
+- **H3. C8 on a home landing.** A landing into home publishes its prepared files manifest under the home bucket's `<location>/files/g-<op>/` (`moves.GenerationFilesPrefix`), and INV-30 protects the source's files until the commit. Confirm that relocation's env-by-row lookup and the prepared-authority reader make no placement assumption a placementless home box breaks.
+
+## Self-review
+
+- Every gap named in the brief has a task or a ruling: the lane (Q1, Task 4 fold, P-2), the ARNs (P-2), T1 to T13 (Task 1, Task 2), the landing (Task 2), rollback and return (Task 3), parks after the commit (Tasks 2 and 3), the alias in Touch, Commit and Release (Task 2's pin), `--to` (R3).
+- Nothing changes claim or region HA code. Anything a test finds there becomes an ask.
+- Copy rows are pending, have no em dashes, and are in the commit that writes them.