plan: home part 2 rev 4, Astra round 3 dispositions
- Clean return: the predecessor and its region are the failed home target's last admission, in its recorded spelling (ie in the fixture); baseline and fresh-generation assertions kept. - The static provenance check is withdrawn: a runtime proof from clean claim state (every harmful wrong spelling is observable there) plus a golden call-site inventory that maps each site to its runtime witness and classifies nothing by shape. The inventory covers ReleaseFencedTarget, ReleaseLostTarget, their release structs and the loss-intent helpers; the reviewer's home_region counterexample is a failing fixture. - New TestMoveIntoHomeFencedTargetRelease witness. - R2(a)'s door confirmation is S-2, the move request; move status and S-1 run neither selection nor the floor check. Round 3 disposition table added.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+35
−17
docs/superpowers/plans/2026-10-15-moves-home-region-part2.md+35 −17
CI cancelled — superseded by a newer push — 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 amadan: job cancelled — a newer push superseded it
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| index 84ab18e09..3200b643e 100644 |
| --- a/docs/superpowers/plans/2026-10-15-moves-home-region-part2.md |
| +++ b/docs/superpowers/plans/2026-10-15-moves-home-region-part2.md |
| @@ -2,7 +2,7 @@ |
| > **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 3, 2026-10-15. Paul approved starting part 2 on 2026-10-15. Written against `main` at a5003aba. Tracking thread: amadan #236. Rev 1 (be29ccd0) and rev 2 (c139b80b) were reviewed by Astra, each NOT READY; the dispositions of both rounds are at the end. |
| +Rev 4, 2026-10-15. Paul approved starting part 2 on 2026-10-15. Written against `main` at a5003aba. Tracking thread: amadan #236. Revs 1 to 3 (be29ccd0, c139b80b, bdbfe3fd) were reviewed by Astra, each NOT READY; the dispositions of all three rounds are at the end. |
| **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, a pre-flip revert, 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"). |
| @@ -22,7 +22,7 @@ Everything else (the staging lane, the lease key, Touch, Commit, Revert, the rol |
| - **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. |
| -- **Supplied arguments versus retained state.** Every region a moves call site newly hands the claim for a home target is the placement-derived `@home`, never the roster name. Claim state the move finds already written (`touched.regions`, `quiet_after` keys, earlier chores, admissions, predecessor regions) may hold either spelling, and nothing in this plan rewrites, duplicates or canonicalizes it. The first rule is checked statically on the production call sites (Task 3's `TestMovesHomeRegionArgumentsAreDerived`), because `hostclaim.Update` receives an opaque closure after the arguments are bound and alias-aware replay hides the spelling in the resulting state. The second is checked at runtime on claim state, seeding both spellings: whatever spellings the claim held before a step are still there after it, nothing is rewritten, and no chore is duplicated (Review Focus 1). |
| +- **Supplied arguments versus retained state.** Every region a moves call site newly hands the claim for a home target is the placement-derived `@home`, never the roster name. Claim state the move finds already written (`touched.regions`, `quiet_after` keys, earlier chores, admissions, predecessor regions) may hold either spelling, and nothing in this plan rewrites, duplicates or canonicalizes it. The first rule is proved at runtime from clean claim state, where a wrong spelling cannot hide (Task 3's `TestHomeTargetFreshStateShowsOnlyTheHomeToken`), and the reviewed set of call sites is pinned by a static inventory that proves nothing about provenance (Task 3's `TestMovesHomeRegionCallSiteInventory`). The second is checked at runtime on claim state, seeding both spellings: whatever spellings the claim held before a step are still there after it, nothing is rewritten, and no chore is duplicated (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 production 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 decides how dev lives with that. |
| @@ -96,7 +96,7 @@ Everything else (the staging lane, the lease key, Touch, Commit, Revert, the rol |
| | `internal/host/movesrevert_test.go`, `internal/host/movescut_test.go` | the pre-flip revert fixture accepts a home target (Task 2) | |
| | `internal/host/moveshome_target_test.go` | new: the into-home witnesses (Tasks 1, 3 and 4) | |
| | `internal/hostops/move_home_target_test.go` | new: declare-lost and recovery grant witnesses for a home target (Task 4) | |
| -| `home_region_args_test.go` | new, repository root: the static check that every moves call site derives its region arguments (Task 3) | |
| +| `home_region_args_test.go` | new, repository root: the inventory of every call site that hands the claim a region on a move's path, each with its runtime witness (Task 3) | |
| | `internal/console/apiinstancemove.go` | the door's home-target rules and display fills (Task 5) | |
| | `internal/console/instancesplacement.go` | `movePlacements`, the move-only home fold (Task 5) | |
| | `internal/console/boxselect.go` | one home name for selection (Task 5) | |
| @@ -180,14 +180,20 @@ Fixture work only. No production code changes, and every existing test passes un |
| - 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). |
| - `TestMoveIntoHomeRestartedProbe`: the first probe attempt is admitted and the agent restarts before readiness. The restarted attempt is published fenced (`TestMovesProbeOwnersPublishARestartedAttemptFenced`'s shape) on `home-box`, its admission's predecessor is the first attempt's generation in `ie`, and the commit proceeds as above. |
| -- `TestMovesHomeRegionArgumentsAreDerived` (new file `home_region_args_test.go` at the repository root, package `main`, beside `home_region_comparison_test.go`, reusing its `plan13Expr` and `plan13Placement` helpers). This is the first half of Review Focus 1, checked statically. |
| - - **Scope.** Every non-test `.go` file under `internal/host`, `internal/hostops` and `internal/console`. The claim's own package and region HA's relocation code are out of scope: they are not moves call sites, and `ConvertCommittedLanding` already compares through `SameRegion`. |
| - - **Calls checked**, with the region parameter each takes: `hostclaim.Touch` (every element of the regions slice literal), `Abort` (2nd), `Revert` (3rd), `Commit` (2nd and 4th), `QueueLocationPark` (2nd), `QueueStagingPark` (2nd), `QueueResidueParks` (2nd), `QueueReturnLanePark` (2nd), `TargetReleased` (3rd), `BeginMove` and `BeginAdmittedMove` (5th), and `moves.StagingLeasePrefix` (1st). |
| - - **Allowed argument forms:** `cfg.parkRegion()` and `<x>.cfg().parkRegion()` (a box's own placement code mapped once; `@home` on a home box); `park.PlacementRegion(e)` or `regionname.PlacementRegion(e)` where `e` is a record code by `plan13Placement`'s classification; a variable whose single assignment in the same function is one of those; and `nil` for Touch's regions. `moves.StagingLeasePrefix`'s only allowed caller is `stagingLeaseKey`, whose argument is `park.PlacementRegion` of its parameter. |
| - - **Everything else fails** with the call's position and expression, unless it is listed in an explicit allowlist in the test with a one-line reason. Two forms are expected there: the console grants that pass a verified fence or roster binding already mapped by `MoveFenceRegions`, and the plain-path `BeginMove(..., to, ...)`, which Task 5 leaves reachable only for named targets because MV-N510 refuses `to == ""` first. Each entry names its file and function, so a new call site cannot hide behind an old entry. |
| - - **Lint witnesses**, as Plan 13's lint has them: a fixture with `hostclaim.Commit(id, from, src, rr.row.Region, ...)` and one with `hostclaim.Touch(id, []string{c.Op.Intent["home_region"]}, nil)` must fail the check; `hostclaim.Commit(id, park.PlacementRegion(l.rec.Move.From), src, cfg.parkRegion(), ...)` must pass. |
| - - **The runtime complement.** The values these forms produce for a home target are already pinned: `park.PlacementRegion("") == park.HomeRegion` (`TestHomeRegionIsReserved`), `cfg.parkRegion()` on the `intoHome` fixture is `@home` (asserted in `TestIntoHomeFixtureIsAHomeTarget`), and the staging lease the fake lease records is `control/staging-leases/@home/<host>` (`TestMoveIntoHomeStagesTheHomeLane`). `op.intent.to` is asserted to equal `@home` in the claim after the start CAS, which is the value every exact comparison reads. |
| - - **Why static, not an injection point.** `hostclaim.Update` (`store.go:63`) takes an opaque closure built after the arguments are bound, so a store wrapper sees only the resulting claim, and Plan 13's alias-aware replay can make an `ie` argument and an `@home` argument produce identical state. An injection point would mean a moves-side indirection over every transition factory in production code, on the claim's authority path (with census rows in `claim-authority-sites.txt`), to serve a test. The static check adds nothing to production, covers every call site including ones no test reaches, catches a future call site the day it is written, and follows the precedent of Plan 13's comparison lint. Its limit is that it proves the derivation, not the value, which is why the runtime complement above stays. |
| +- **The first half of Review Focus 1: supplied regions are `@home`.** Rev 3 proposed a static provenance check. Round 3 showed its classifier could not prove provenance (`to := c.Op.Intent["home_region"]; park.PlacementRegion(to)` passed while supplying `ie`), and a sound version needs dataflow across functions, parameters, struct fields decoded from signed intents, and closures. That is a project of its own, and a heuristic version gives false assurance. Rev 4 uses two narrower pieces instead: a runtime proof, and a static inventory that claims nothing about provenance. |
| + - **`TestHomeTargetFreshStateShowsOnlyTheHomeToken` (runtime, the proof).** Each into-home witness in Tasks 3 and 4 runs once from **clean** claim state: the start CAS writes `intent.to = @home` and `home_region = ie`, and nothing else in the claim names home (no `touched` entry, no quiet key, no chore). From clean state a wrong spelling cannot hide, because each harmful use shows up: |
| + - a chore queued with `ie` is a new obligation whose `Region` or `Owner` names `ie` (alias-aware replay absorbs a call only when an equivalent chore already exists, and none does); |
| + - a Touch with `ie` adds `ie` to `touched`; |
| + - a staging lease keyed with `ie` shows in the fake lease's recorded keys; |
| + - an exact comparison against `intent.to` (`Abort`, `Revert`, `TargetReleased`, `QueueStagingPark`, `ReleaseFencedTarget`, `ReleaseLostTarget`) refuses, and the witness fails. |
| + |
| + After each witness the test asserts that every obligation created for the target side has `Region == "@home"` and `Owner == "region:@home"`, that `touched` gained only `@home` and the target box, and that the lease keys are `control/staging-leases/@home/<host>` for the home lane. A second call with the wrong spelling after a correct first one would be absorbed, but by construction it neither duplicates nor rewrites (that is the retained-state rule below), so it is harmless. The one harmful absorbed case, `requireRetiredRegion` allowing a location park, would create a **new** obligation and is therefore visible. |
| + - **`TestMovesHomeRegionCallSiteInventory` (static, a pin, not a proof)** in `home_region_args_test.go` at the repository root. It lists every production call site that hands the claim a region on a move's path, and compares the list with a golden inventory in the test. Each inventory row is `{file, enclosing function, callee or composite type and field, argument expression text, witness}`. |
| + - **Sites:** in every non-test `.go` file under `internal/host`, `internal/hostops` and `internal/console`, every call to `hostclaim.Touch`, `Abort`, `Revert`, `Commit`, `QueueLocationPark`, `QueueStagingPark`, `QueueResidueParks`, `QueueReturnLanePark`, `TargetReleased`, `BeginMove`, `BeginAdmittedMove`, `ReleaseFencedTarget`, `ReleaseLostTarget` and `moves.StagingLeasePrefix`, and every composite literal of `hostclaim.FencedTargetRelease` and `hostclaim.LostTargetRelease` (fields `TargetRegion` and `SourceRegion`), plus each helper that builds the regions they carry: `moveLossRelease` (the `LostTargetRelease` literal), `claimLossIntent` (which copies `TargetRegion` from `op.intent.to`) and `recordLossIntent` (which sets `SourceRegion` from the record), all in `internal/hostops/move_loss_owner.go`. The intent read back from a signed loss record (`lossIntentOf`) is not a new derivation and is not listed. |
| + - **Witness column:** the runtime test that drives that site with a home target from clean state, or `named-only` with the guard that keeps a home target away. Two rows are expected to be `named-only`: the plain-path `BeginMove(..., to, ...)` (MV-N510 refuses `to == ""` first, Task 5), and any site Task 3 or 4 finds unreachable for a home target. Retained, validated intent is a narrow, named exception: `LostTargetRelease.TargetRegion` is `in.TargetRegion`, which `claimLossIntent` copies from `op.intent.to` and the loss record signs, so its witness is `TestMoveIntoHomeDeclareLost`, and the row says so. |
| + - **What fails:** a site not in the inventory; an inventoried site whose argument expression text changed; an inventory row whose site no longer exists. The failure message says to add or update the row and name a runtime witness. Fixtures: a new `hostclaim.Commit(id, from, src, rr.row.Region, ...)` site fails as unknown; `to := c.Op.Intent["home_region"]` followed by `hostclaim.QueueStagingPark(id, park.PlacementRegion(to), ...)` at a new site fails as unknown, and at an inventoried site fails as changed; a `FencedTargetRelease{TargetRegion: o.Claim.Op.Intent["home_region"], ...}` literal fails as changed; an unchanged tree passes. |
| + - **What it does not do:** it classifies nothing as safe by its shape. `plan13Placement` and `plan13Engine` are not used. The inventory's value is that a reviewer saw each site once and a runtime witness covers it, and that no new site appears without both. |
| + - **Why this trade.** The runtime proof covers exactly the paths a home target takes in the witnesses, with no heuristic. The inventory closes the gap a runtime proof leaves, new or edited call sites, by forcing a review and a witness rather than pretending to verify them. A moves-side injection point over the transition factories remains rejected: it adds production indirection on the claim's authority path to serve a test. |
| - `TestHomeTargetRetainedChoresKeepTheirSpelling`: with a residue chore and a lane chore already owed under `ie` (seeded), the landing's `QueueResidueParks(@home)` and the commit's `QueueStagingPark(@home)` leave the obligation list byte-identical (no second chore, no rewrite to `@home`); the same with them owed under `@home`. Both are acknowledged once by the home box's engine. This is the second half of Review Focus 1. |
| - [ ] Write the tests; fix only what they prove broken (expected: nothing outside Task 1); targeted runs; commit: `git commit -m "moves: commit into home through the production owners (home part 2)"`. |
| @@ -200,11 +206,12 @@ Fixture work only. No production code changes, and every existing test passes un |
| **Tests (production owners throughout):** |
| - `TestMoveIntoHomePreFlipRevert`: the cut stops the source on `ca-box` and fails before the flip (the shape of `TestCutDeadlinePassedReverts`). `Revert(id, ca-box, @home, &laneScope, ...)` queues the lane park with `@home`, owner `region:@home`; the source's revert probe re-admits on `ca-box` through `movesRecoveryOwners` (`TestRevertProbeAdmitsUncovered`'s shape) in region `ca`; `home-box`'s moves engine runs the lane park on `data-home`, and the home box's `hostbox.Regional` acknowledges it after the horizon. Nothing in `data-ca` is parked. |
| -- `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 with `@home`; the source reopens on `ca-box` through `movesRecoveryOwners`, asserted in two stages as production recovery works (`movesrecoveryowners.go:300`, and the existing clean-return test at `movesrecoveryowners_test.go:465`). Before the admission: after the clean `ReturnToSource`, `holder.generation` is `src_gen`, and the recovery owners' baseline plan (`r.baseline`) restores from `src_gen`. After the admission: `holder.generation` is the fresh generation the admission named (`fresh1` in that fixture's naming), not `src_gen`; the last admission has `Coverage == "clean-return"`, `WritesLost == nil` and no `AdditionalWritesLost`, its `PredecessorRegion` is `ca`, and its `Predecessor` is `src_gen`. The record ends `rolled_back`; nothing is parked in `data-ca` that the source still serves (J2/F4 through `restoring`). |
| +- `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 with `@home`; the source reopens on `ca-box` through `movesRecoveryOwners`, asserted in two stages as production recovery works (`movesrecoveryowners.go:300`, and the existing clean-return test at `movesrecoveryowners_test.go:465`). Before the admission: after the clean `ReturnToSource`, `holder.generation` is `src_gen`, and the recovery owners' baseline plan (`r.baseline`) restores from `src_gen`. After the admission: `holder.generation` is the fresh generation the admission named (`fresh1` in that fixture's naming), not `src_gen`; the last admission has `Coverage == "clean-return"`, `WritesLost == nil` and no `AdditionalWritesLost`, and its `Region` is `ca`. Its `Predecessor` and `PredecessorRegion` are the previous last admission's (`hostclaim/generation.go:117` takes both from it, not from the restore baseline): the failed home target's admitted generation and its region in the spelling that admission recorded, which is `ie` in the fixture, not `@home` (the existing named-target shape is `movesrecoveryowners_test.go:446`). 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 through the recovery owners, establishing its files from the return's manifest (C8), and the pre-move generations park after the return (D6), not before. |
| - `TestMoveIntoHomeAbortParksTheHomeLane`: abort before the cut. `Abort` queues the lane park with `@home`; `home-box`'s moves engine runs it; `hostbox.Regional` on `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). This is Ask A2's witness. |
| - `TestHomeRegionalAcknowledgesBothSpellings`: the real `hostbox.Regional` on `home-box` acknowledges a lane `park-replica` and a residue `park-generation` owed under `@home`, and the same owed under `ie`, each exactly once; a `ca` box's runner acknowledges none of the four. Also Ask A2's witness. |
| -- `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 through `AdmitWriterWithLoss`; the record shows `loss_ref`. It reuses Plan 13's `TestPlan13FenceRecoveryHomeAndNamed` fixture rather than a new one. |
| +- `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 through `AdmitWriterWithLoss`; the record shows `loss_ref`. It reuses Plan 13's `TestPlan13FenceRecoveryHomeAndNamed` fixture rather than a new one. `ReleaseLostTarget` must succeed with `TargetRegion == @home` against `intent.to == @home`. |
| +- `TestMoveIntoHomeFencedTargetRelease` (hostops): a home target terminated after it released, from clean claim state. `MoveRecoveryGrant.ReleaseFencedTarget` builds `FencedTargetRelease` with `TargetRegion: park.PlacementRegion(m.To)` (`@home`) and `SourceRegion` `ca`; `hostclaim.ReleaseFencedTarget` accepts it against `intent.to`; the location and lane parks it queues name `@home`. The witness for the inventory's `FencedTargetRelease` row. |
| - `TestCommittedLandingIntoHomeConvertsOnTargetFence`: after the commit, `home-box` is fenced as terminated. `hostclaim.ConvertCommittedLanding` turns the claim into `relocating` with `intent.region = ie` (the roster name) and `move_to_region = @home`, and keeps the lane park and the source's finalization chores in their retained spelling. This is Ask H1's witness. 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 revert, rollback, abort, loss and conversion witnesses (home part 2)"`. |
| @@ -290,7 +297,7 @@ Withdrawn in Task 5: MV-N21 ("moves to the home region are not supported yet. th |
| | # | failure | effect | guard | |
| |---|---|---|---| |
| -| F1 | a moves call site supplies 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 3's static `TestMovesHomeRegionArgumentsAreDerived`; the park view's live-set rule; Ask A1 hardening | |
| +| F1 | a moves call site supplies 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 3's `TestHomeTargetFreshStateShowsOnlyTheHomeToken` (runtime, from clean state) and `TestMovesHomeRegionCallSiteInventory` (every site reviewed and witnessed); 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 3 asserts the key | |
| | F3 | a replay canonicalizes or duplicates a chore already owed under `ie` | a second park of the same work, or a rewritten obligation the regional runner no longer matches | Plan 13's alias-aware queue; Task 3's `TestHomeTargetRetainedChoresKeepTheirSpelling` | |
| | F4 | a box with `CARLOS_REGION=<home name>` | as a home target the move would stall in `preparing` (no target report; the source finds no `targets[""]`) | MV-N511 at the door, before the capability check (Task 5) | |
| @@ -336,7 +343,7 @@ Only Paul can decide these. Each has a recommendation. |
| 1. stop `carlos-dev-ie-b` (the instance, or at least its agent and console units, so it neither writes status nor serves); |
| 2. delete `control/edges/carlos-dev-ie-b.json` from the deployment bucket; |
| 3. wait until its last `status/boxes/carlos-dev-ie-b.json` is more than 15 minutes old by its `generated_at`; |
| - 4. before **each** run, verify the fleet's evidence is complete: every box with a status snapshot fresher than 15 minutes has an edges file, every edges file's box has a status snapshot, and exactly one edges file has no `placement`. Then confirm with the door: `carlos move status` on a rehearsal host, or the run's own S-1, shows no "could not all be read" and no MV-N5; |
| + 4. before **each** run, verify the fleet's evidence is complete: every box with a status snapshot fresher than 15 minutes has an edges file, every edges file's box has a status snapshot, and exactly one edges file has no `placement`. The door's own confirmation is the run's **S-2**, the move request itself. Only a move request runs `selectMoveBoxes` and the floor check: `carlos move status` (`handleAPIInstanceMoveStatus`) reads the record and claim only, and S-1 only wakes the app, so neither confirms anything here. If S-2 answers "the fleet's edges files could not all be read" or MV-N5, the window is not ready. Both refusals come before any claim read or write, so nothing was started: fix the evidence and repeat S-2; |
| 5. after the window, start the box again. Its edges pass rewrites the file on boot. No move touching home runs until the window is reopened by steps 1 to 4. |
| It also takes #286's two-home-box hazard out of the window, since rehearsal apps then wake on one box only. Cost: an operator procedure with a 15-minute wait per window, and dev loses its second home box while it lasts. |
| @@ -356,7 +363,7 @@ None blocks this plan. Each names the witness that answers it; please review the |
| **To platform-1e (the claim):** |
| -- **A1. The exact-region contract, and one optional hardening.** Moves' contract: every region moves supplies 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; retained claim state keeps whatever spelling it has. Witnesses: `TestMovesHomeRegionArgumentsAreDerived` (static, over every moves call site) and `TestHomeTargetRetainedChoresKeepTheirSpelling` (runtime, Task 3). 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). |
| +- **A1. The exact-region contract, and one optional hardening.** Moves' contract: every region moves supplies 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; retained claim state keeps whatever spelling it has. Witnesses: `TestHomeTargetFreshStateShowsOnlyTheHomeToken` (runtime, from clean state), `TestMovesHomeRegionCallSiteInventory` (every call site, including `ReleaseFencedTarget` and `ReleaseLostTarget`, mapped to its runtime witness) and `TestHomeTargetRetainedChoresKeepTheirSpelling` (runtime, Task 3). 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.** Witnesses: `TestMoveIntoHomeAbortParksTheHomeLane`, `TestMoveIntoHomePreFlipRevert` and `TestHomeRegionalAcknowledgesBothSpellings` (Task 4) run the real `hostbox.Regional` on a home box against `@home` and `ie` lane and residue chores. Please review them. |
| - **A3. No further claim gate.** Witness: `TestMoveDoorClaimModeAcceptsHomeTarget` (Task 5) and `TestMoveIntoHomeCommitsAndCloses` (Task 3) drive a `moving` op with `intent.to = @home` from the start CAS to the close. Please confirm nothing else in the claim should refuse it. |
| @@ -371,7 +378,7 @@ None blocks this plan. Each names the witness that answers it; please review the |
| - Every gap named in the brief has a task or a ruling: the lane (Q1, Task 5 fold, P-2), the ARNs (P-2), T1 to T13 (Tasks 1 and 3), the landing (Task 3), revert, rollback and return (Task 4), parks after the commit (Tasks 3 and 4), the alias in Touch, Commit and Release (Task 3's two pins), `--to` (R3). |
| - Nothing changes claim or region HA code. Anything a test finds there becomes an ask. |
| - Every witness on a path where `ie` meets `@home` runs through the production owners. |
| -- Supplied arguments are proved statically, retained state at runtime; no assertion requires exactly one spelling of home in claim state. |
| +- Supplied arguments are proved at runtime from clean state, and the call sites are pinned by an inventory that claims no provenance; retained state is proved at runtime from seeded state. No assertion requires exactly one spelling of home in claim state, and no heuristic classifier is used as proof. |
| - Copy rows are pending, have no em dashes, and are in the commit that writes them. |
| ## Review round 1 (Astra, on be29ccd0): dispositions (rev 2) |
| @@ -397,3 +404,14 @@ Verdict NOT READY: round 1's #3 and #4 addressed, #1 and #2 partial, two new P2s |
| | 2 | P2 (round 1 #1, partial) the argument-recording test had no interception point: `hostclaim.Update` (`store.go:63`) takes an opaque closure, and alias-aware replay hides the spelling | Replaced by the static `TestMovesHomeRegionArgumentsAreDerived` over every production call site of the transition factories and `moves.StagingLeasePrefix` in `internal/host`, `internal/hostops` and `internal/console`, with allowed argument forms, a named allowlist, and failing and passing fixtures. Static was chosen over a moves-side injection point because an injection point would add production indirection on the claim's authority path to serve a test, while the static check adds nothing to production, covers call sites no test reaches and catches new ones. Its derivation-only limit is covered by the runtime pins listed with it. Global Constraints, F1 and A1 updated. | |
| | 3 | P2 (new) the clean-rollback assertion `holder.generation = src_gen` conflicted with production recovery, which restores from `src_gen` and admits a fresh generation (`movesrecoveryowners.go:300`; `movesrecoveryowners_test.go:465` expects `fresh1`) | `TestMoveIntoHomeCleanRollback` asserts in two stages: `src_gen` after the clean return and as the restore baseline; after the admission, the fresh generation, `clean-return` coverage, no writes lost, predecessor `src_gen` in `ca`. | |
| | 4 | P2 (new) R2(a) was incomplete: deleting the edges file while the box's status snapshot is fresh makes `ReadLiveSnapshot` (`snapshot.go:168`) incomplete and `selectMoveBoxes` refuses; a retained file still affects S1, T8 and the floor check | R2(a) is now five steps: stop the box, delete its edges file, wait until its status snapshot is more than 15 minutes old (`status.BoxStale`, 3 × 5 minutes), verify complete fleet evidence and one placementless file before each run, restart after the window. The ruling explains both readers and the MV-N5 effect of a retained file. Task 6's P-0 item, F5 and the runbook copy carry the same procedure. | |
| + |
| +## Review round 3 (Astra, on bdbfe3fd): dispositions (rev 4) |
| + |
| +Verdict NOT READY: the spelling, interception and generation items addressed; four P2s left. All four fixed in rev 4. On the static check, rev 4 takes the narrower option the coordinator offered rather than attempting provenance. |
| + |
| +| # | finding | rev 4 | |
| +|---|---|---| |
| +| 1 | P2 the clean-return predecessor: `AdmitWriter` takes the predecessor and its region from the last admission, the failed home target's (`hostclaim/generation.go:117`; `movesrecoveryowners_test.go:446`), not `src_gen` in `ca` | `TestMoveIntoHomeCleanRollback` keeps the baseline (`src_gen`) and fresh-generation assertions and now asserts `Predecessor` and `PredecessorRegion` are the target's last admitted generation and its region in its recorded spelling (`ie` in the fixture). Round 2's row 3 is superseded on this point. | |
| +| 2 | P2 the static check missed `ReleaseFencedTarget` and `ReleaseLostTarget`, whose regions arrive through `FencedTargetRelease` (`move_fence_release.go:130`) and `LostTargetRelease` (`move_loss_owner.go:732`) and are compared exactly with `intent.to` | Both factories, both composite literals' `TargetRegion` and `SourceRegion` fields, and the helpers that build them (`moveLossRelease`, `claimLossIntent`, `recordLossIntent`) are in the inventory. `LostTargetRelease.TargetRegion` is a named exception for retained, signed intent, with `TestMoveIntoHomeDeclareLost` as its witness. New `TestMoveIntoHomeFencedTargetRelease` witnesses the fenced path. A changed `FencedTargetRelease` literal is a failing fixture. | |
| +| 3 | P2 `plan13Placement` cannot prove provenance: `to := c.Op.Intent["home_region"]; park.PlacementRegion(to)` passed while supplying `ie` | The static provenance check is withdrawn. Sound provenance needs dataflow across functions, parameters, signed-intent fields and closures; a heuristic gives false assurance. Replaced by `TestHomeTargetFreshStateShowsOnlyTheHomeToken`, a runtime proof from clean claim state, where every harmful wrong spelling is observable (a new obligation, a `touched` entry, a lease key, or an exact refusal), plus `TestMovesHomeRegionCallSiteInventory`, a golden inventory of every site with its runtime witness that classifies nothing by shape. The reviewer's counterexample is a failing fixture (unknown site, or changed expression at a known one). No heuristic classifier is used anywhere as proof. | |
| +| 4 | P2 R2(a)'s confirmation: move status (`apiinstancemove.go:325`) runs neither selection nor the floor check, and S-1 only wakes the app | Step 4 keeps the evidence checks and names S-2, the move request, as the door's confirmation; both of its possible refusals precede any claim read or write, so a failed confirmation starts nothing. | |