census-ruling-moves-offline-precopy (round 2)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 files changed,
+143
−39
docs/superpowers/notes/census-proposal-moves-offline-precopy.md+116 −23internal/provision/moves_offline_precopy_census_test.go+9 −3internal/provision/plan14_root_reads_test.go+4 −3internal/provision/testdata/plan14-root-reads-moves-offline-precopy.tsv+14 −10
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 105.835s
? github.com/carlosframework/platform/cmd/changelog [no test files]
ok github.com/carlosframework/platform/cmd/console 2.842s
ok github.com/carlosframework/platform/cmd/moveprobe 93.337s
ok github.com/carlosframework/platform/cmd/zddprobe 0.707s
ok github.com/carlosframework/platform/internal/activator 251.050s
ok github.com/carlosframework/platform/internal/agentsock 0.020s
ok github.com/carlosframework/platform/internal/alerting 0.004s
ok github.com/carlosframework/platform/internal/analytics 0.025s
ok github.com/carlosframework/platform/internal/appconfig 2.480s
ok github.com/carlosframework/platform/internal/apperr 0.089s
ok github.com/carlosframework/platform/internal/applog 0.214s
ok github.com/carlosframework/platform/internal/awsinv 0.007s
ok github.com/carlosframework/platform/internal/boxchoice 0.005s
ok github.com/carlosframework/platform/internal/boxid 0.797s
? 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.012s
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.719s
ok github.com/carlosframework/platform/internal/changelog 0.358s
ok github.com/carlosframework/platform/internal/claimactivation 0.863s
ok github.com/carlosframework/platform/internal/clamd 0.061s
? github.com/carlosframework/platform/internal/cliflag [no test files]
ok github.com/carlosframework/platform/internal/console 444.143s
? 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.275s
ok github.com/carlosframework/platform/internal/dbdoor/dbdoortest 0.009s
ok github.com/carlosframework/platform/internal/dbverify 0.005s
ok github.com/carlosframework/platform/internal/dnsrec 0.003s
ok github.com/carlosframework/platform/internal/docsite 0.009s
ok github.com/carlosframework/platform/internal/domains 2.461s
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 45.108s
? github.com/carlosframework/platform/internal/edgeproof [no test files]
ok github.com/carlosframework/platform/internal/edgesfile 0.008s
ok github.com/carlosframework/platform/internal/fleetapi 0.134s
ok github.com/carlosframework/platform/internal/gate 1.665s
ok github.com/carlosframework/platform/internal/genselect 0.016s
ok github.com/carlosframework/platform/internal/geo 0.016s
ok github.com/carlosframework/platform/internal/geoip 0.030s
ok github.com/carlosframework/platform/internal/historyreadback 0.155s
ok github.com/carlosframework/platform/internal/host 194.052s
ok github.com/carlosframework/platform/internal/hostactors 6.235s
ok github.com/carlosframework/platform/internal/hostactors/awsmembership 0.004s
ok github.com/carlosframework/platform/internal/hostbox 2.649s
ok github.com/carlosframework/platform/internal/hostclaim 0.559s
ok github.com/carlosframework/platform/internal/hostenv 0.004s
ok github.com/carlosframework/platform/internal/hostevidence 0.005s
ok github.com/carlosframework/platform/internal/hostexec 4.836s
ok github.com/carlosframework/platform/internal/hostfence 0.031s
ok github.com/carlosframework/platform/internal/hostfiles 10.506s
ok github.com/carlosframework/platform/internal/hostfloor 0.015s
ok github.com/carlosframework/platform/internal/hostguard 0.996s
ok github.com/carlosframework/platform/internal/hostops 1.636s
? github.com/carlosframework/platform/internal/hostops/fencerelease [no test files]
ok github.com/carlosframework/platform/internal/hostops/internal/fencerelease 0.002s
ok github.com/carlosframework/platform/internal/hostquarantine 0.004s
ok github.com/carlosframework/platform/internal/hostrelocate 0.456s
ok github.com/carlosframework/platform/internal/hostresolve 0.143s
ok github.com/carlosframework/platform/internal/hostwrite 0.018s
ok github.com/carlosframework/platform/internal/infraview 0.017s
ok github.com/carlosframework/platform/internal/instancectl 5.245s
ok github.com/carlosframework/platform/internal/instanceexec 2.740s
ok github.com/carlosframework/platform/internal/instancefs 0.020s
ok github.com/carlosframework/platform/internal/instancekey 0.015s
ok github.com/carlosframework/platform/internal/instanceupdates 0.021s
ok github.com/carlosframework/platform/internal/layout 1.598s
ok github.com/carlosframework/platform/internal/lbhealth 0.002s
ok github.com/carlosframework/platform/internal/lease 10.090s
ok github.com/carlosframework/platform/internal/lease/leasetest 0.380s
ok github.com/carlosframework/platform/internal/ledger 0.011s
ok github.com/carlosframework/platform/internal/mail 0.173s
ok github.com/carlosframework/platform/internal/maintenance 0.084s
ok github.com/carlosframework/platform/internal/maintenanceexec 5.524s
ok github.com/carlosframework/platform/internal/maintenanceguard 0.065s
ok github.com/carlosframework/platform/internal/metrics 0.005s
ok github.com/carlosframework/platform/internal/moves 21.262s
ok github.com/carlosframework/platform/internal/moves/archive 0.795s
ok github.com/carlosframework/platform/internal/objstore 0.211s
ok github.com/carlosframework/platform/internal/ops 0.183s
ok github.com/carlosframework/platform/internal/park 0.212s
ok github.com/carlosframework/platform/internal/plans 0.005s
ok github.com/carlosframework/platform/internal/privatefile 0.004s
ok github.com/carlosframework/platform/internal/provision 32.642s
ok github.com/carlosframework/platform/internal/publicrelease 0.008s
? github.com/carlosframework/platform/internal/regionname [no test files]
ok github.com/carlosframework/platform/internal/registry 5.432s
ok github.com/carlosframework/platform/internal/relay 7.238s
ok github.com/carlosframework/platform/internal/release 24.030s
ok github.com/carlosframework/platform/internal/rollout 3.722s
ok github.com/carlosframework/platform/internal/rolloutwords 0.004s
ok github.com/carlosframework/platform/internal/rootaws 0.007s
ok github.com/carlosframework/platform/internal/rootparticipation 0.058s
ok github.com/carlosframework/platform/internal/rootstate 0.026s
ok github.com/carlosframework/platform/internal/runs 0.584s
ok github.com/carlosframework/platform/internal/s3compat 0.005s
ok github.com/carlosframework/platform/internal/safefile 0.004s
ok github.com/carlosframework/platform/internal/schedule 2.564s
ok github.com/carlosframework/platform/internal/seeds 0.010s
ok github.com/carlosframework/platform/internal/sim/hostlife 9.834s
ok github.com/carlosframework/platform/internal/sim/litestreamfacts 4.123s
ok github.com/carlosframework/platform/internal/status 0.063s
ok github.com/carlosframework/platform/internal/steering 0.006s
ok github.com/carlosframework/platform/internal/stopevidence 0.291s
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.004s
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.005s
ok github.com/carlosframework/platform/internal/version 0.002s
ok github.com/carlosframework/platform/internal/vet 1.554s
=== 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: 49873058 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.024s
=== RUN TestT4StorageProbeMinio
2026/10/21 13:41:25 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18E08F2F5ABC9408, 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.01s)
PASS
ok github.com/carlosframework/platform/internal/host 0.022s
minio contract: PASS
diff --git a/docs/superpowers/notes/census-proposal-moves-offline-precopy.md b/docs/superpowers/notes/census-proposal-moves-offline-precopy.md| index 285840b0d..f61fc041e 100644 |
| --- a/docs/superpowers/notes/census-proposal-moves-offline-precopy.md |
| +++ b/docs/superpowers/notes/census-proposal-moves-offline-precopy.md |
| @@ -4,8 +4,10 @@ Status: RULED. census-ruling-moves-offline-precopy, by the coordinator as census |
| owner for this branch, 2026-10-21: accepted as proposed. Every row carries |
| `rev3=census-ruling-moves-offline-precopy`. |
| -The branch is `moves-offline-precopy`, from main 3d444a1b, ruled at 21cd69a4 |
| -(after Astra's round 1 fixes, 692d41cf). It does two things. It runs a mirror |
| +The branch is `moves-offline-precopy`, from main 3d444a1b. It was ruled at |
| +21cd69a4 (after Astra's round 1 fixes, 692d41cf), then re-ruled at 981294cf |
| +(round 2, 0a6bb375) merged with main f550afa2 (see "Round 2 and the merge of |
| +main" below). It does two things. It runs a mirror |
| round's copies and deletes side by side in `lease.MirrorPrefixKeep`. And it |
| adds `carlos move offline stage`, which pre-copies the replica while the |
| instance keeps serving, as a new record state, offline-staging. |
| @@ -13,10 +15,10 @@ instance keeps serving, as a new record state, offline-staging. |
| The ruling adds: |
| - `internal/provision/testdata/plan14-root-reads-moves-offline-precopy.tsv`, |
| - loaded last in `TestPlan14RootReadCensus`, after scan-demand-revival, once |
| - scan-demand-revival's seal has been checked; |
| + loaded last in `TestPlan14RootReadCensus`, after design-plans-and-caps, once |
| + design-plans-and-caps' seal has been checked; |
| - `internal/provision/moves_offline_precopy_census_test.go`, the record-write |
| - (9B8) overlay on scan-demand-revival's inventory, which |
| + (9B8) overlay on design-plans-and-caps' inventory, which |
| `TestPlan9B8RecordWriteCensus` now reads; |
| - one line in `internal/console/testdata/claim-routes.txt`. |
| @@ -45,24 +47,25 @@ stager the stage door pinned on the record (`move.stager`). On that one box it |
| reads only the object store: |
| - its own stager report (`OfflineReportKey`); |
| -- the fleet's edges files, for the target's coordinates (`offlineTarget`, the |
| - same helper the seal uses); |
| - this box's receipts object. |
| It then: |
| -- deletes `moves/<host>/` in the target's data bucket. It refuses a bare |
| - `moves/`, and never deletes in this box's own bucket. `offlineSealRevert` |
| +- deletes `moves/<host>/` in the staging bucket the stage door fixed on the |
| + record (`move.stage_bucket`), through a mirror for `move.stage_region` |
| + (round 2). It refuses a bare `moves/`, a missing bucket and this box's own |
| + bucket, and in those cases acknowledges nothing. `offlineSealRevert` |
| already deletes the same prefix the same way; |
| - clears `move-receipts/<host>.json` in `cfg.OwnBucket`, the same bucket the |
| stage round writes them to (`tombstoneAt`); |
| - writes its stager report as reverted. |
| -It reads no local file. The host comes from the record and the target from |
| -the edges files: the operator names only a region code, and the tenant |
| -controls none of these paths. |
| +It reads no local file. The host comes from the record. The stored bucket and |
| +region come from the target box's edges file at stage time, written to the |
| +record by the console through `SetRecordMove`. The operator names only a |
| +region code, and the tenant controls none of these paths. |
| -### Envelopes re-pinned (at 21cd69a4) |
| +### Envelopes re-pinned (at 21cd69a4; superseded by the round 2 table below) |
| None of these changes adds a read site. Every changed production file was |
| read for this ruling. |
| @@ -114,30 +117,120 @@ the same one-move lock. That is not a new write site. |
| - **Tests.** Its claim-refusal fixture and its `svcroutes_test.go` exemption |
| match the six sibling offline doors exactly. |
| +## Round 2 and the merge of main |
| + |
| +### The merge (d5b020ba) |
| + |
| +Main (f550afa2) added two overlays, run-lifecycle-logs-325 and |
| +design-plans-and-caps, and a 9B8 inventory, `plansCapsWriteCensusInventory`. |
| +They touch none of this branch's units. The merge keeps both of main's |
| +overlays and loads this branch's last, after design-plans-and-caps, whose seal |
| +(`4f5e0ed6…df17`) is checked first. This branch's 9B8 overlay now sits on |
| +`plansCapsWriteCensusInventory`. |
| + |
| +Three envelopes (`.`, internal/console, internal/host) and registerCLIRoutes |
| +are changed by both sides. Because this branch's overlay loads last, it pins |
| +them on the merged tree. |
| + |
| +### Round 2 (0a6bb375): what changed, and the census reading |
| + |
| +- **The stage door fixes the staging destination on the record:** |
| + `MoveState.StageBucket` and `StageRegion`, from the one target box's edges |
| + file. The door refuses a source box's own bucket (MV-O191). |
| + `provision.OfflineStage` takes a `StageTarget` and refuses an empty stager |
| + or bucket. These are record fields written through the typed |
| + `SetRecordMove` (`offlineBegin`, `offlineApply`), so there is no new write |
| + site. |
| +- **The stager re-reads the record** before a round, and once before its |
| + delete phase (`stageDeleteGate`). `provision.GetRecord` is an object-store |
| + read, not a local file, and the scan finds no root-read unit in |
| + `movesoffline_stage.go`. A move that has left staging starts no round and |
| + deletes nothing. |
| +- **The stager acknowledges it has stopped** (`offlineStagerStopped`). It |
| + writes its own stager report through `writeOfflineReport`, an existing |
| + nonrecord site, and is called from `offlineSourceStep` in stopping through |
| + landed. |
| +- **offlineUnstage deletes from the stored destination:** `moves/<host>/` in |
| + `move.stage_bucket`, through a mirror for `move.stage_region`. It refuses, |
| + and acknowledges nothing, when no bucket is stored or the stored bucket is |
| + this box's own. It reads only the object store. |
| +- **offlineTakeSeal** gains one refusal before its mirror: a staged move |
| + seals only into the stored bucket and region. This is a comparison of |
| + record and edges-file fields. Its 16 read sites are unchanged, each shifted |
| + by 487 bytes. Its Puts (nonrecord, under the move's `moves/@offline/` |
| + prefix) are unchanged. |
| +- **The console:** |
| + - Start and seal refuse when the pinned stager is missing from the fleet |
| + (MV-O190), and stage, start and seal refuse changed coordinates (MV-O192). |
| + - Seal waits for a fresh acknowledgement from the stager (M-C10, or MV-O178 |
| + when it is stale). |
| + - These checks read only the fleet and the report evidence the doors |
| + already read. |
| +- **internal/edgesfile:** `PlacementView` gains `DataBucketRegion`, a JSON |
| + field. No read site. |
| + |
| +### Rows and sites changed by round 2 and the merge |
| + |
| +| census | unit or envelope | ruling | |
| +|---|---|---| |
| +| Plan 14 | `internal/host/movesoffline_seal.go` `movesWorker.offlineTakeSeal` | re-frozen at J1, census-ruling-moves-offline's disposition; digest `f606873f…cdaa` | |
| +| Plan 14 | `movesWorker.offlineSourceRevert` | basis updated: offlineUnstage now uses the stored destination; digest and sites unchanged | |
| +| Plan 14 | envelopes `.`, internal/console, internal/edgesfile, internal/host, internal/provision | re-pinned on the merged tree; internal/lease and internal/moves unchanged since round 1 | |
| +| 9B8 | `movesWorker.offlineTakeSeal` | nonrecord (census-ruling-moves-offline's), sel:Put; digest `f606873f…cdaa` | |
| +| 9B8 | `Server.registerCLIRoutes` | key-site, pinned on the merged tree; digest `a0aff01b…2e87` | |
| + |
| +| envelope | hash | |
| +|---|---| |
| +| `.` | `649bb6a5…eabd` | |
| +| `internal/console` | `7bdd3caa…81c9` | |
| +| `internal/edgesfile` | `71692438…811e` | |
| +| `internal/host` | `d58c8e60…e219` | |
| +| `internal/lease` | `980f38c4…62a14` | |
| +| `internal/moves` | `33c7b507…e071` | |
| +| `internal/provision` | `210b1740…34dc` | |
| + |
| ## The seal |
| -The two accepted-legacy rows add frozen declarations, so the legacy seal moves |
| -from `a21dba12…f262` (main, after scan-demand-revival) to |
| -`965fda6e58a16662833fcfe5435e9f45b525eb1abdd1f1f1715d611cb699bc81`. A removal |
| -is not in the seal. The test checks scan-demand-revival's seal before it loads |
| -this overlay. The seal was read from a temporary `t.Logf` of |
| +Three accepted-legacy rows add frozen declarations (offlineSourceRevert, |
| +offlineBegin and offlineTakeSeal), so the legacy seal moves from |
| +`4f5e0ed6…df17` (main, after design-plans-and-caps) to |
| +`940ed1bba8d911e0f57af83ecac253c77ba5e14dad590258e0ee03ec98ccb818`. A removal |
| +is not in the seal. The test checks design-plans-and-caps' seal before it |
| +loads this overlay. Each seal was read from a temporary `t.Logf` of |
| `rootReadLegacySeal(inv)`, which was then removed. |
| +Earlier seals of this overlay: |
| + |
| +- `965fda6e…c81`, on its own after scan-demand-revival; |
| +- `8ef09f41…1a4d`, after the merge, before round 2. |
| + |
| ## Ruling (the coordinator, 2026-10-21): census-ruling-moves-offline-precopy, ACCEPTED as proposed |
| 1. offlineSourceRevert and offlineUnstage: ACCEPTED. Object-store reads only, |
| - on the pinned stager only; there is no root read of an operator- or |
| - tenant-controlled path. |
| + on the pinned stager only, deleting only in the staging destination fixed |
| + on the record; there is no root read of an operator- or tenant-controlled |
| + path. |
| 2. offlineBegin: ACCEPTED (J4, as OfflineStart). OfflineStart is retired by |
| the H3 removal, since it is behaviour-identical. |
| 3. offlineBegin's `file:Open@198` is `rec.ActiveRun.Open()`: ACCEPTED. |
| -4. The six envelopes: ACCEPTED, re-pinned at 21cd69a4. |
| +4. The envelopes: ACCEPTED, re-pinned on the merged tree (981294cf with main |
| + f550afa2), internal/edgesfile included. |
| 5. MirrorPrefixKeep: ACCEPTED at versioned-transport. Its record writes still |
| go through the book. |
| 6. registerCLIRoutes: ACCEPTED at key-site. |
| 7. The stage route: ACCEPTED. It is operator-only, refused with MV-O20 on |
| claims consoles, and has its fixture. |
| +8. offlineTakeSeal (round 2): ACCEPTED, re-frozen at J1 and nonrecord in |
| + 9B8. It adds one refusal and no read or write. |
| +9. The round 2 record fields and reads (`StageBucket`, `StageRegion`, the |
| + record re-reads, the stop acknowledgement): ACCEPTED. The fields go through |
| + `SetRecordMove`, the reads go to the object store, and the report write |
| + goes through `writeOfflineReport`. |
| +10. The merge with main f550afa2: ACCEPTED. Both overlays are kept, this |
| + branch's is loaded last, and the seal is recomputed. |
| + |
| The first verification was at 25c0db26. It was re-verified at 21cd69a4 for the |
| -round 1 fixes: the stager pin, cleanup by `staged_at`, and the receipts |
| -preload. |
| +round 1 fixes (the stager pin, cleanup by `staged_at`, the receipts preload), |
| +then at 981294cf merged with main f550afa2 for the round 2 fixes (the stager |
| +in the seal barrier, the fixed staging destination, the record re-reads). |
diff --git a/internal/provision/moves_offline_precopy_census_test.go b/internal/provision/moves_offline_precopy_census_test.go| index d65857ffe..cb47a8312 100644 |
| --- a/internal/provision/moves_offline_precopy_census_test.go |
| +++ b/internal/provision/moves_offline_precopy_census_test.go |
| @@ -6,9 +6,14 @@ package provision |
| // coordinator, as census owner for this branch (2026-10-21), accepted as |
| // classified (docs/superpowers/notes/census-proposal-moves-offline-precopy.md). |
| // |
| -// Two sites change and keep their class; no site is added. |
| +// Three sites change and keep their class; no site is added. |
| // registerCLIRoutes gains the stage door's route line beside the six |
| -// offline doors (key-site, main's). MirrorPrefixKeep plans its skips first |
| +// offline doors (key-site, main's), pinned on the merged tree with |
| +// design-plans-and-caps' two account plan doors. offlineTakeSeal |
| +// (nonrecord, census-ruling-moves-offline's) gains one refusal before its |
| +// mirror after Astra's round 2: a staged move seals only into the staging |
| +// bucket and region fixed on the record; its Puts and their keys under the |
| +// move's moves/@offline/ prefix are unchanged. MirrorPrefixKeep plans its skips first |
| // and then runs the copies and, after every copy has landed, the deletes on |
| // up to DefaultMirrorWorkers goroutines; it still writes only the |
| // destination prefix (Copy or CopyVersioned, Delete) and the receipts |
| @@ -18,8 +23,9 @@ package provision |
| // start whenever the round copies anything, so set and drop touch memory |
| // only and no request is made under the mutex; the write set is unchanged. |
| var movesOfflinePrecopyWriteCensusOverlay = []censusEntry{ |
| - {"internal/console/authcli.go", "Server.registerCLIRoutes", "key-site", "lit:instances,lit:sidecars", "2aee959d5c58a81b47f10629f6954b3d0b6d6860f999d9fe9eead9155f12c459"}, |
| + {"internal/console/authcli.go", "Server.registerCLIRoutes", "key-site", "lit:instances,lit:sidecars", "a0aff01b7e2f4bb6fd23e8b54d41d90f1cd4171822f9defb9bd16cb2a08e2e87"}, |
| {"internal/lease/mirror.go", "MirrorPrefixKeep", "versioned-transport", "sel:CopyVersioned", "dff4d03fa4e56219c5a3e08862f24ad2a6bce7a7e0df806571fa52e8fb29fb19"}, |
| + {"internal/host/movesoffline_seal.go", "movesWorker.offlineTakeSeal", "nonrecord", "sel:Put", "f606873fb09e8644d449a36ae64cecbb84b2f83791d4ebec4cb491d3d3f7cdaa"}, |
| } |
| // movesOfflinePrecopyWriteCensusInventory is design-plans-and-caps' inventory |
diff --git a/internal/provision/plan14_root_reads_test.go b/internal/provision/plan14_root_reads_test.go| index f4e65c2ed..4fbe08f89 100644 |
| --- a/internal/provision/plan14_root_reads_test.go |
| +++ b/internal/provision/plan14_root_reads_test.go |
| @@ -1070,15 +1070,16 @@ func TestPlan14RootReadCensus(t *testing.T) { |
| // (docs/superpowers/notes/census-proposal-moves-offline-precopy.md). |
| // offlineSourceRevert is re-frozen at its disposition, offlineBegin |
| // (OfflineStart's body) is new accepted legacy, and OfflineStart is |
| - // retired by an H3 census-ruling removal. Two frozen declarations are |
| - // added, so the seal moves; design-plans-and-caps' is checked first. |
| + // retired by an H3 census-ruling removal; offlineTakeSeal is re-frozen |
| + // for Astra's round 2. Three frozen declarations are added, so the seal |
| + // moves; design-plans-and-caps' is checked first. |
| if errs := checkRootReadLegacy(inv, seal); len(errs) != 0 { |
| t.Fatal(errs) |
| } |
| if err = loadRootReadInventory(filepath.Join(root, "internal/provision/testdata/plan14-root-reads-moves-offline-precopy.tsv"), &inv, true); err != nil { |
| t.Fatal(err) |
| } |
| - seal = "8ef09f416d7a7acbb5f92791feb5e3c69bd3ef86cb3a72610faa136dd1941a4d" |
| + seal = "940ed1bba8d911e0f57af83ecac253c77ba5e14dad590258e0ee03ec98ccb818" |
| errs := append(compareRootReads(got, inv), checkRootReadLegacy(inv, seal)...) |
| errs = append(errs, checkRootReadDeclarations(got, inv)...) |
| if len(errs) > 0 { |
diff --git a/internal/provision/testdata/plan14-root-reads-moves-offline-precopy.tsv b/internal/provision/testdata/plan14-root-reads-moves-offline-precopy.tsv| index a58345c27..4688b7ec8 100644 |
| --- a/internal/provision/testdata/plan14-root-reads-moves-offline-precopy.tsv |
| +++ b/internal/provision/testdata/plan14-root-reads-moves-offline-precopy.tsv |
| @@ -1,18 +1,22 @@ |
| -# Census overlay moves-offline-precopy (parallel copies in lease.MirrorPrefix and the carlos move offline stage door, an offline-staging record state), loaded LAST, after scan-demand-revival. RULED as census-ruling-moves-offline-precopy (the coordinator, as census owner for this branch, 2026-10-21), accepted as proposed: every row is rev3=census-ruling-moves-offline-precopy. The ruling, with each unit's executing identity: docs/superpowers/notes/census-proposal-moves-offline-precopy.md. |
| +# Census overlay moves-offline-precopy (parallel copies in lease.MirrorPrefix and the carlos move offline stage door, an offline-staging record state), loaded LAST, after design-plans-and-caps. RULED as census-ruling-moves-offline-precopy (the coordinator, as census owner for this branch, 2026-10-21), accepted as proposed, re-ruled for Astra's rounds 1 and 2 and the merge of main f550afa2: every row is rev3=census-ruling-moves-offline-precopy. The ruling, with each unit's executing identity: docs/superpowers/notes/census-proposal-moves-offline-precopy.md. |
| # Every unit here runs in the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos) or the console (user carlos-console) and makes no root decision, so each stays accepted legacy at the disposition census-ruling-moves-offline gave it or its sibling (J1 root-route for registry and route reads, J4 root-input for file reads). |
| -# movesWorker.offlineSourceRevert re-frozen with its new digest: it calls offlineUnstage, which reads only the object store; its read sites are unchanged and one offset moved. offlineBegin is new: OfflineStart's body, moved unchanged with the state as a parameter; its one site is rec.ActiveRun.Open(), a method, not a file read. OfflineStart is retired by an H3 census-ruling removal (the carlos-run getJSON form); a removal is not in the seal. Two frozen declarations are added, so the seal moves. |
| -# Round 1 (Astra P2s, 692d41cf): the stage door pins the stager on the record (MoveState.Stager, written through SetRecordMove like every other move field); offlineUnstage cleans whenever staged_at is set, on the pinned stager only; the console finish of a staged move waits for that stager's reverted report; MirrorPrefixKeep reads the receipts book before its workers start. No unit's read sites change; offlineSourceRevert's basis names offlineUnstage's reads as they now are; the envelopes below are pinned at 21cd69a4. |
| -# Envelopes re-pinned: . (move.go: the stage subcommand, its status and abort lines; no read), internal/console (the stage door, offlineBeginChecks, the status view; no read site but offlineClaimEvidence's, unchanged), internal/host (movesoffline_stage.go, new, reads only the object store; edgesfile.go publishes offline-stage-1; the box-side stager election is gone, only the pinned box stages or cleans; offlineRound's staging branch), internal/lease (mirror.go: the round's copies and deletes run side by side; forEachParallel), internal/moves (the stager role, staged phase, report fields, OfflineStager) and internal/provision (offline_move.go: OfflineStage, which needs a stager, OfflineRestage, OfflineStartStaged; provision.go: MoveState.StagedAt and MoveState.Stager). |
| -@legacy 20c1c784429a572d5bd14513c5905d569e06ab0c4007922bf3383816b61636a9 internal/host/movesoffline.go movesWorker.offlineSourceRevert legacy accepted-legacy accepted-legacy;rev3=census-ruling-moves-offline-precopy;basis=root-route (J1, census-ruling-moves-offline's disposition); the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), on abort: census-ruling-moves-offline's body (reads the row's hold and releases only this move's hold, under reconcileMu), now calling offlineUnstage before it reports reverted. offlineUnstage acts only for a move carrying staged_at and only on the stager the stage door pinned on the record (move.stager); it reads only the object store (its own stager report, the fleet's edges files for the target's coordinates, this box's receipts object) and deletes the target's moves/<host>/ staging prefix (never in this box's own bucket) and this box's move-receipts/<host>.json, then writes its stager report reverted; it reads no local file and makes no root decision. Read sites unchanged; one offset moved (whole:Route@701 to @843) registry:HoldOp@562,whole:Route@549,whole:Route@843 b917ac2d1976eec14839ed65e3e562327d54af956e86f5218ed011731182aa1b |
| -internal/host/movesoffline.go movesWorker.offlineSourceRevert legacy accepted-legacy accepted-legacy;rev3=census-ruling-moves-offline-precopy;basis=root-route (J1, census-ruling-moves-offline's disposition); the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), on abort: census-ruling-moves-offline's body (reads the row's hold and releases only this move's hold, under reconcileMu), now calling offlineUnstage before it reports reverted. offlineUnstage acts only for a move carrying staged_at and only on the stager the stage door pinned on the record (move.stager); it reads only the object store (its own stager report, the fleet's edges files for the target's coordinates, this box's receipts object) and deletes the target's moves/<host>/ staging prefix (never in this box's own bucket) and this box's move-receipts/<host>.json, then writes its stager report reverted; it reads no local file and makes no root decision. Read sites unchanged; one offset moved (whole:Route@701 to @843) registry:HoldOp@562,whole:Route@549,whole:Route@843 b917ac2d1976eec14839ed65e3e562327d54af956e86f5218ed011731182aa1b |
| +# movesWorker.offlineSourceRevert re-frozen with its new digest: it calls offlineUnstage, which reads only the object store; its read sites are unchanged and one offset moved. offlineBegin is new: OfflineStart's body, moved unchanged with the state as a parameter; its one site is rec.ActiveRun.Open(), a method, not a file read. OfflineStart is retired by an H3 census-ruling removal (the carlos-run getJSON form); a removal is not in the seal. |
| +# Round 1 (Astra, 692d41cf): the stage door pins the stager on the record (MoveState.Stager, written through SetRecordMove like every other move field); offlineUnstage cleans whenever staged_at is set, on the pinned stager only; the console's finish of a staged move waits for that stager's reverted report; MirrorPrefixKeep reads the receipts book before its workers start. |
| +# Round 2 (Astra, 0a6bb375): the stage door also fixes the staging destination on the record (MoveState.StageBucket, StageRegion, from the one target box's edges file, refusing a source box's own bucket, MV-O191); the stage round, the seal's hand-over (offlineTakeSeal, re-frozen here) and an abort's cleanup use only those; the stager re-reads the record (provision.GetRecord, the object store) before a round and before its delete phase (stageDeleteGate) and acknowledges it has stopped (offlineStagerStopped, its own stager report through writeOfflineReport); the console's start and seal doors wait for that acknowledgement and refuse a missing stager (MV-O190) or changed coordinates (MV-O192). No new root read or record write. Three frozen declarations in all, so the seal moves. |
| +# Envelopes re-pinned on the merged tree (main f550afa2 with this branch): . (move.go: the stage subcommand, its status and abort lines; no read), internal/console (the stage door, offlineBeginChecks, the stager pin and destination, the seal and start barriers, the finish gate, the status view; no read site but offlineClaimEvidence's, unchanged), internal/edgesfile (PlacementView reads data_bucket_region; no read site), internal/host (movesoffline_stage.go reads only the object store; edgesfile.go publishes offline-stage-1; the box-side stager election is gone, only the pinned box stages or cleans; offlineRound's staging branch), internal/lease (mirror.go: the round's copies and deletes run side by side; forEachParallel; the book read up front), internal/moves (the stager role, staged phase, report fields, OfflineStager) and internal/provision (offline_move.go: OfflineStage, which needs a StageTarget, OfflineRestage, OfflineStartStaged; provision.go: MoveState.StagedAt, Stager, StageBucket, StageRegion). |
| +@legacy e7c1242684b2da24edf4c9f56545d1208bd8433562aa494a911dda42e55d3452 internal/host/movesoffline.go movesWorker.offlineSourceRevert legacy accepted-legacy accepted-legacy;rev3=census-ruling-moves-offline-precopy;basis=root-route (J1, census-ruling-moves-offline's disposition); the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), on abort: census-ruling-moves-offline's body (reads the row's hold and releases only this move's hold, under reconcileMu), now calling offlineUnstage before it reports reverted. offlineUnstage acts only for a move carrying staged_at and only on the stager the stage door pinned on the record (move.stager); it reads only the object store (its own stager report, this box's receipts object) and deletes moves/<host>/ in the staging bucket and region the stage fixed on the record (move.stage_bucket, move.stage_region; it refuses a missing one or this box's own bucket and then acknowledges nothing) and this box's move-receipts/<host>.json, then writes its stager report reverted; it reads no local file and makes no root decision. Read sites unchanged; one offset moved (whole:Route@701 to @843) registry:HoldOp@562,whole:Route@549,whole:Route@843 b917ac2d1976eec14839ed65e3e562327d54af956e86f5218ed011731182aa1b |
| +internal/host/movesoffline.go movesWorker.offlineSourceRevert legacy accepted-legacy accepted-legacy;rev3=census-ruling-moves-offline-precopy;basis=root-route (J1, census-ruling-moves-offline's disposition); the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), on abort: census-ruling-moves-offline's body (reads the row's hold and releases only this move's hold, under reconcileMu), now calling offlineUnstage before it reports reverted. offlineUnstage acts only for a move carrying staged_at and only on the stager the stage door pinned on the record (move.stager); it reads only the object store (its own stager report, this box's receipts object) and deletes moves/<host>/ in the staging bucket and region the stage fixed on the record (move.stage_bucket, move.stage_region; it refuses a missing one or this box's own bucket and then acknowledges nothing) and this box's move-receipts/<host>.json, then writes its stager report reverted; it reads no local file and makes no root decision. Read sites unchanged; one offset moved (whole:Route@701 to @843) registry:HoldOp@562,whole:Route@549,whole:Route@843 b917ac2d1976eec14839ed65e3e562327d54af956e86f5218ed011731182aa1b |
| +@legacy 06eb20ca59fc8172dfa9ef5bc6872987974b44f08202417705566816ecaeaf9f internal/host/movesoffline_seal.go movesWorker.offlineTakeSeal legacy accepted-legacy accepted-legacy;rev3=census-ruling-moves-offline-precopy;basis=root-route (J1, census-ruling-moves-offline's disposition); the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): census-ruling-moves-offline's body (seal steps 1 to 9 from the row: database path, next due, replication rung and timer rows, read for the seal) with one refusal before the mirror: a staged move (staged_at set) is sealed only into the staging bucket and region the stage fixed on the record (move.stage_bucket, move.stage_region), a comparison of record and edges-file fields that reads and writes nothing new. Read sites unchanged; every offset after the check moved by 487 bytes registry:DBPath@2621,registry:NextDue@12050,registry:NextDue@12962,registry:Replication@11955,registry:Replication@12937,whole:Route@10690,whole:Route@1713,whole:Route@2682,whole:Route@3463,whole:Route@5452,whole:Route@8226,whole:Timer@9377,whole:Timer@9442,whole:Timer@9448,whole:Timer@9707,whole:Timer@9806 f606873fb09e8644d449a36ae64cecbb84b2f83791d4ebec4cb491d3d3f7cdaa |
| +internal/host/movesoffline_seal.go movesWorker.offlineTakeSeal legacy accepted-legacy accepted-legacy;rev3=census-ruling-moves-offline-precopy;basis=root-route (J1, census-ruling-moves-offline's disposition); the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): census-ruling-moves-offline's body (seal steps 1 to 9 from the row: database path, next due, replication rung and timer rows, read for the seal) with one refusal before the mirror: a staged move (staged_at set) is sealed only into the staging bucket and region the stage fixed on the record (move.stage_bucket, move.stage_region), a comparison of record and edges-file fields that reads and writes nothing new. Read sites unchanged; every offset after the check moved by 487 bytes registry:DBPath@2621,registry:NextDue@12050,registry:NextDue@12962,registry:Replication@11955,registry:Replication@12937,whole:Route@10690,whole:Route@1713,whole:Route@2682,whole:Route@3463,whole:Route@5452,whole:Route@8226,whole:Timer@9377,whole:Timer@9442,whole:Timer@9448,whole:Timer@9707,whole:Timer@9806 f606873fb09e8644d449a36ae64cecbb84b2f83791d4ebec4cb491d3d3f7cdaa |
| @legacy 5e6a7aa9d23e5559c9b93f3a5c038e019a9a5d3bbcfbcf9229725ce7682b936a internal/provision/offline_move.go offlineBegin legacy accepted-legacy accepted-legacy;rev3=census-ruling-moves-offline-precopy;basis=root-input (J4, as OfflineStart); the console (cmd/console serve under console.service, user carlos-console): new, OfflineStart's body moved unchanged with the state as a parameter (offline-stopping for OfflineStart, behaviour-identical; offline-staging plus staged_at for OfflineStage), the record transition the start and stage doors apply through SetRecordMove; its one site is rec.ActiveRun.Open(), a method on the record's run state (RunState.Open), not a file read file:Open@198 66e0216314538687d102a4cee1089a19896c7693260f748a046a5ff16e76dc1e |
| internal/provision/offline_move.go offlineBegin legacy accepted-legacy accepted-legacy;rev3=census-ruling-moves-offline-precopy;basis=root-input (J4, as OfflineStart); the console (cmd/console serve under console.service, user carlos-console): new, OfflineStart's body moved unchanged with the state as a parameter (offline-stopping for OfflineStart, behaviour-identical; offline-staging plus staged_at for OfflineStage), the record transition the start and stage doors apply through SetRecordMove; its one site is rec.ActiveRun.Open(), a method on the record's run state (RunState.Open), not a file read file:Open@198 66e0216314538687d102a4cee1089a19896c7693260f748a046a5ff16e76dc1e |
| # OfflineStart retired (H3, the carlos-run form). A removal is not in the seal. |
| @remove internal/provision/offline_move.go OfflineStart |
| @removed internal/provision/offline_move.go OfflineStart H3 census-ruling-moves-offline-precopy: still declared, and reads nothing now: its body and its one site (rec.ActiveRun.Open(), a method, not a file read) moved unchanged into offlineBegin, an accepted-legacy row in this overlay; OfflineStart calls offlineBegin with offline-stopping and is behaviour-identical. It runs in the console as carlos-console. |
| -@coverage . 44fc0f3ea061670389aae27fb0ef47397adecba16951a173a4b0bbbe728a8bdd |
| -@coverage internal/console 6ae90250ebff821c8e64d0e64827860ddf80213177a86dc9cba6db9ec68592d6 |
| -@coverage internal/host e9234db89d1fc6b9a966c8a0c66b983c4e4bb18a7c8222ccbf91a46318c98f47 |
| +@coverage . 649bb6a5f474312600edb213fb76a1a6444c6ff37a39412d1bbb04eeed49eabd |
| +@coverage internal/console 7bdd3caafb3a474a1bb3797c26c5a38e76b11ca7f0a46cd9c3a6af8ca62781c9 |
| +@coverage internal/edgesfile 716924380656f85e428541c170e8c5bab9f0ad9c8abe931488f7a44e7953811e |
| +@coverage internal/host d58c8e606d61557dce896f82fc41c06969d99fd1e097b863aa986e0fa416e219 |
| @coverage internal/lease 980f38c4804ae1485c0c0df77bade8990b1d0248c0f44e41e0194c7731562a14 |
| @coverage internal/moves 33c7b507f13b4f4081c3bdb0a84e31d875e2cf1be61b480a7ca856193125e071 |
| -@coverage internal/provision 8c86869568a559329a0d8dcbc1df5cac18b4bcabd5ca3b4f403949ebd56f4b64 |
| +@coverage internal/provision 210b174030fa650ef7345999643ef7e98add1a24378802cc134f9dea64d234dc |