census: self-serve moves 1 Task 4 classifies the retirement's record writes and re-pins the root-read overlay
Record-write inventory: Server.retirementStepsLocked is a record-writer (N1, one WriteRecord of the tombstone of the exact bytes observed); retireRecordWithLifetimeLocked, retireStaleLocked and three provision listings are key-sites; deleteRead, importDeleteRule, finishSeedOnce, fenceRecord, deleteUnderRetiredSlot, handleAPIInstanceCreate and the cutover door are re-pinned; readDeletedRecord leaves the inventory (no write site). Root-read overlay: Store.ConvertRetirementKind added accepted-legacy and domains Reconcile re-pinned (the claims-off auto-purge removed), which moves the seal; the console, provision, release, domains and host envelopes re-pinned. All PROPOSED-self-serve-moves-1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 files changed,
+67
−8
docs/superpowers/notes/census-proposal-self-serve-moves-1.md+2 −0internal/provision/plan14_root_reads_test.go+4 −2internal/provision/self_serve_moves1_census_test.go+51 −4internal/provision/testdata/plan14-root-reads-self-serve-moves-1.tsv+10 −2
CI cancelled — superseded by a newer push — run details
CI log
=== gate === .amadan/test-gate.sh amadan: job cancelled — a newer push superseded it
diff --git a/docs/superpowers/notes/census-proposal-self-serve-moves-1.md b/docs/superpowers/notes/census-proposal-self-serve-moves-1.md| index c74906ef3..16102cca1 100644 |
| --- a/docs/superpowers/notes/census-proposal-self-serve-moves-1.md |
| +++ b/docs/superpowers/notes/census-proposal-self-serve-moves-1.md |
| @@ -19,3 +19,5 @@ Task 3 fix round 1 changes only door answers. `Server.handleAPIDomainAttach` sta |
| Task 5 adds the lazy migration: `internal/provision/lifetime_migration.go` (`ErrRecordMigrating`, `WithMigration`, the marker and final bodies, the updaters' wait) and `internal/console/lifetimes_migrate.go` (the protocol, its dispatcher, recovery and the pass behind `CARLOS_LIFETIMES_MIGRATE=1`). The record-write census reported three changed sites and five unlisted ones. `WriteRecord` stays the one record-primitive: it now refuses a body read with another migration's marker, a refusal only, and a create-only write is unaffected. `updateRecordSeeding` stays a record-writer and reads a marked record again every second for up to 30 seconds. `Server.fenceRecord` stays a record-writer; over a marker of a migration that admission proves is not pending, it rewrites the exact bytes under that marker's id. `Server.migrationMarkLocked` (step 1) and `Server.migrationFinishLocked` (step 3) are record-writers, each one `WriteRecord` by CAS under its own marker id with the sequence on. `Server.migrationStepsLocked` and `Server.migrateFieldlessRecords` are key-sites; the only bucket write in either is a `DeleteIfMatch` of a corrupt body on its observed ETag, after the copy. `Server.quarantineCopy` is nonrecord: one create-only Put under `control/quarantine/`. The root-read overlay re-pins `serve`, which also starts the migration pass, and the `internal/provision`, `internal/console` and `cmd/console` envelopes. The changed `serve` fingerprint moves the seal. No root read, class or registry field is added. This remains `PROPOSED-self-serve-moves-1`. |
| Task 5 fix round 1 adds no write site. `WriteRecord`, `Server.fenceRecord` and the adoption now read a record's marker through one helper, `provision.RecordMarker`: the value `DecodeRecord` reads. `updateRecordSeeding`'s wait ends when its context does. `Server.migrationMarkLocked` adopts a marker whose operation is gone (no slot) by CAS, writing under that marker's id. The pass becomes `Server.migratePreLifetimeRecords`, a key-site as before; it now also selects records that carry such a marker. The record-write inventory re-pins these units. The overlay re-pins the `internal/provision` and `internal/console` envelopes. No root read or legacy row changes, and the seal stands. This remains `PROPOSED-self-serve-moves-1`. |
| + |
| +Task 4 makes every claims-off removal of an instance record admitted on a retirement through a tombstone (`internal/console/lifetimes_retire.go`), moves the purge onto the console with every lifetime retired first (`lifetimes_purge.go`), and adds the box floor of the cutover (`lifetimes_floor.go`, `lifetimes-1` in `internal/host`'s edges file). The record-write census reported seven changed sites, one stale entry and six unlisted ones. One new record-writer: `Server.retirementStepsLocked`, whose only record write is N1, one `WriteRecord` of `TombstoneBody` of the exact bytes observed, by CAS from their ETag, sequence on; every removal is `DeleteIfMatch` on an observed ETag and every slot write is `WriteHostIncarnation` from the captured ETag. `Server.retireRecordWithLifetimeLocked` and `Server.retireStaleLocked` are key-sites (a conditional delete of a stale body, after `quarantineCopy` for a corrupt one). `Server.deleteUnderRetiredSlot` stays a key-site; each attempt is now a fresh observation that deletes only while the slot is still the key's at N, retired, so a second console's successor is never read as stale. `Server.deleteRead`, `Server.importDeleteRule` and `Server.finishSeedOnce` keep their legacy deletes before the cutover and call the retirement admitted on; `Server.readDeletedRecord` has no write site any more. `Server.fenceRecord`, `Server.handleAPIInstanceCreate` and `Server.handleAPILifetimesCutover` are re-pinned (the fence's own-tombstone test needs the incarnation, the sibling undo states its lifetime, the cutover door reads the box floor before the marker). Three provision key-sites are added: `RecordEvidenceJudged`, `ListRecordHosts`, `IsInstanceRecordKeyOf`. The root-read overlay adds `Store.ConvertRetirementKind` (accepted-legacy, one conditional SQLite update) and re-pins `internal/domains` `Reconcile`, whose claims-off 1d auto-purge is removed (the registry reads are unchanged); both move the seal (`c6f0b633…`). The `internal/console`, `internal/provision`, `internal/release`, `internal/domains` and `internal/host` envelopes are re-pinned. The SQLite writer is on `record_retirements`, which already has its `claimWriterReasons` entry. Everything stays `PROPOSED-self-serve-moves-1`. |
diff --git a/internal/provision/plan14_root_reads_test.go b/internal/provision/plan14_root_reads_test.go| index 078120ee4..08c7bdc99 100644 |
| --- a/internal/provision/plan14_root_reads_test.go |
| +++ b/internal/provision/plan14_root_reads_test.go |
| @@ -1270,8 +1270,10 @@ func TestPlan14RootReadCensus(t *testing.T) { |
| // units, which moves the seal; still rev3=PROPOSED-self-serve-moves-1. |
| // Task 3 (the create protocol) re-pins serve and Server.hostHolder and |
| // adds newLifetimeOpID, which moves it again. Task 5 (the lazy migration) |
| - // re-pins serve, which starts the migration pass. |
| - seal = "059b3cb0a336b314981b205d529d0205849751e7e0f1b1c4c10ede3430417797" |
| + // re-pins serve, which starts the migration pass. Task 4 (retirement) |
| + // adds Store.ConvertRetirementKind and re-pins domains Reconcile, whose |
| + // claims-off auto-purge is removed. |
| + seal = "c6f0b633c327af2dbccf080e3eac057b575e06df6cf120510f49f0058d513978" |
| errs := append(compareRootReads(got, inv), checkRootReadLegacy(inv, seal)...) |
| errs = append(errs, checkRootReadDeclarations(got, inv)...) |
| if len(errs) > 0 { |
diff --git a/internal/provision/self_serve_moves1_census_test.go b/internal/provision/self_serve_moves1_census_test.go| index db2dc8bc3..2d5625e6e 100644 |
| --- a/internal/provision/self_serve_moves1_census_test.go |
| +++ b/internal/provision/self_serve_moves1_census_test.go |
| @@ -113,6 +113,40 @@ package provision |
| // - lifetimes_migrate.go:Server.quarantineCopy: nonrecord; one create-only |
| // Put of control/quarantine/<account>/<app>/<host>.<unix nanos>.json; the |
| // record key is not touched. |
| +// |
| +// Task 4 (retirement through a tombstone), reviewed dispositions (all |
| +// PROPOSED): |
| +// - lifetimes_retire.go:Server.retirementStepsLocked: record-writer; the |
| +// retirement dispatcher's only record write is N1, one WriteRecord of |
| +// TombstoneBody(the exact bytes observed) by CAS from their ETag with the |
| +// sequence on; its removals are DeleteIfMatch on an observed ETag |
| +// (through deleteUnderRetiredSlot), never a plain delete; the slot |
| +// writes are WriteHostIncarnation (nonrecord) from the captured ETag. |
| +// - lifetimes_retire.go:Server.retireRecordWithLifetimeLocked: key-site; |
| +// builds the record key for its errors only; the writes are the |
| +// dispatcher's, the orphan retirement's and the migration's. |
| +// - lifetimes_retire.go:Server.retireStaleLocked: key-site; a stale or |
| +// corrupt body under no slot of this key: quarantineCopy, then |
| +// DeleteIfMatch on the observed ETag, no Put. |
| +// - lifetimes_create.go:Server.deleteUnderRetiredSlot: key-site as before; |
| +// each attempt is a fresh observation and deletes only while the slot is |
| +// still this key's at N, retired (a successor's body is never read as |
| +// stale). |
| +// - lifetimes_create.go:Server.fenceRecord: record-writer as before; its |
| +// own-tombstone test now needs the operation's incarnation. |
| +// - apiinstanceimport.go:Server.deleteRead, Server.importDeleteRule, |
| +// seedfinish.go:Server.finishSeedOnce: as before for a unit admitted |
| +// before the cutover (DeleteIfMatch on the read ETag); admitted on, the |
| +// removal is retireRecordWithLifetime with the read's expectation. No |
| +// raw Put. Server.readDeletedRecord has no write site any more: it is |
| +// the judge's (or the unjudged) observation. |
| +// - apiinstances.go:Server.handleAPIInstanceCreate: record-writer as |
| +// before; the sibling undo states the lifetime it made. |
| +// - lifetimes_cutover.go:Server.handleAPILifetimesCutover: nonrecord as |
| +// before; the box floor is read before the marker Put. |
| +// - lifetime_judge.go:RecordEvidenceJudged, ListRecordHosts, |
| +// IsInstanceRecordKeyOf: key-site; list or test the app's instance |
| +// record keys and judge them; no write. |
| func plan14SelfServeMoves1WriteCensusInventory() []censusEntry { |
| removed := []struct{ file, unit string }{ |
| {"internal/provision/provision.go", "GetRecordETag"}, |
| @@ -130,6 +164,10 @@ func plan14SelfServeMoves1WriteCensusInventory() []censusEntry { |
| {"internal/console/apiinstanceseed.go", "Server.beginFrom"}, |
| {"internal/console/apidomains.go", "Server.handleAPIDomainAttach"}, |
| {"internal/provision/record_sequence.go", "WriteRecord"}, |
| + {"internal/console/apiinstanceimport.go", "Server.deleteRead"}, |
| + {"internal/console/apiinstanceimport.go", "Server.importDeleteRule"}, |
| + {"internal/console/apiinstanceimport.go", "Server.readDeletedRecord"}, |
| + {"internal/console/seedfinish.go", "Server.finishSeedOnce"}, |
| } |
| added := []censusEntry{ |
| {"internal/provision/provision.go", "updateRecordSeeding", "record-writer", "key:RecordKey,key:WriteRecord", "0bd38721d7cc97f37dbe8f37803f89d3e6efdaf29f9d6542a1d1b4d8eb370a3e"}, |
| @@ -140,19 +178,19 @@ func plan14SelfServeMoves1WriteCensusInventory() []censusEntry { |
| {"internal/provision/lifetime_judge.go", "readAllRecordsJudged", "key-site", "key:ParseRecordKey,lit:instances", "e56e43bb89e7a013445033b390cd57bf6eda16a539f5a398d1dd26597fe30ca4"}, |
| {"internal/provision/lifetime.go", "GetRecordRaw", "key-site", "key:RecordKey", "1e893cadc5dedac4687a6877457254c8e07c328a91b2c5923ef87fd3c41ff1fc"}, |
| {"internal/provision/lifetime.go", "WriteHostIncarnation", "nonrecord", "sel:Put", "c5f2719a53447c0477706600081a9846444071f39b85759a463d1ee757dc760e"}, |
| - {"internal/console/lifetimes_cutover.go", "Server.handleAPILifetimesCutover", "nonrecord", "sel:Put", "90e15124c0c7fa2b3902bf68c54d418c16792fa29f88ea2ec906353fc9b82c64"}, |
| + {"internal/console/lifetimes_cutover.go", "Server.handleAPILifetimesCutover", "nonrecord", "sel:Put", "d591ec4ca15595057362a4b90754069dcb28595e75a9b39785f4401c09103ef1"}, |
| {"internal/console/apiinstanceimport.go", "Server.runImportUpload", "record-writer", "key:SetRecordSeed", "f602216e89e9a93c330afb5153894621918ab390655897c1dc9bd2435f5cab80"}, |
| {"internal/console/apiinstances.go", "Server.handleAPIInstanceList", "key-site", "lit:instances", "ac702aaa6da4c5a6ed7bb69427ba03ec3f2ee7753cce57c58349a978bbdcfadf"}, |
| {"internal/console/apiinstanceseed.go", "Server.runFrom", "record-writer", "key:SetRecordSeed", "0f0ed34b5a5c99cc7f8245f2e8d6284c300b4c7314b312af69f96d6d49f0d4c0"}, |
| {"internal/console/authcli.go", "Server.registerCLIRoutes", "key-site", "lit:instances,lit:sidecars", "59882a91226ccba287af507482bea1aba49d6cab94fd32de0f2d586276ae2f92"}, |
| {"internal/console/server.go", "NewServer", "key-site", "lit:instances", "737b2f91242d1a6750de07b43ea0c72bc0bc24365211e8a6abf7b3307126f5e8"}, |
| - {"internal/console/apiinstances.go", "Server.handleAPIInstanceCreate", "record-writer", "key:CreateRecord", "328f0b07e8b52250c5c2a58aa67d52c53cc2a51b2fd891836c061c6cff8ce2a7"}, |
| + {"internal/console/apiinstances.go", "Server.handleAPIInstanceCreate", "record-writer", "key:CreateRecord", "32e27e1366bea1802e9873170197daece43507bdbdccc25111ec6c1305c11f27"}, |
| {"internal/console/domainattach.go", "Server.attachDomainAs", "record-writer", "key:CreateRecord", "205df195585b26df17f51b5d9ac5006a308104612df794d91208a6a040bfaf59"}, |
| {"internal/console/apiinstanceseed.go", "Server.createSeedRecord", "record-writer", "key:CreateRecord", "a6fabf99b13e7e2302dbf2c30fb7c782f76f787141a5cc12580fde59805dfd4a"}, |
| {"internal/console/lifetimes_create.go", "Server.allocRecordLocked", "record-writer", "key:RecordKey,key:WriteRecord", "e04927e2e52a0362da469199c04735fa3bfd926c1c898e63b4370a8d79f46daa"}, |
| - {"internal/console/lifetimes_create.go", "Server.fenceRecord", "record-writer", "key:RecordKey,key:WriteRecord", "1a7395415a1c99a83cfa721e7b21c7bb2d890039f27fdf6461e59f1100dbc7c7"}, |
| + {"internal/console/lifetimes_create.go", "Server.fenceRecord", "record-writer", "key:RecordKey,key:WriteRecord", "efee3393b8d4a362fc395271671f59c9c75d6f7dc2f6970494725dbecb3275d8"}, |
| {"internal/console/lifetimes_create.go", "Server.allocCleanLocked", "key-site", "key:RecordKey", "035cf56d8f69517b66dc8ea6f9121d463e482d7dd05daf2b0c494aef1255f522"}, |
| - {"internal/console/lifetimes_create.go", "Server.deleteUnderRetiredSlot", "key-site", "key:RecordKey", "d0c8412a40e6f00d5db66e301fd108a7d5cddbfbe6dd80a93f02ac31f7cd24a0"}, |
| + {"internal/console/lifetimes_create.go", "Server.deleteUnderRetiredSlot", "key-site", "key:RecordKey", "16d160495d03f8ea606f2d4bb724dedcde6677cc4d5428ce76770a429c300109"}, |
| {"internal/console/apidomains.go", "Server.handleAPIDomainAttach", "key-site", "lit:instances", "44016e4665cafc4d6d36ca8b4b9d01213978b8ca5041a2e83d9b93a397866b3d"}, |
| {"internal/provision/record_sequence.go", "WriteRecord", "record-primitive", "key:IsRecordKey,key:WriteRecord,key:preparedRecordKey,sel:Put", "60bf5d78fd9b544d585192f2f474374fc5f44f648ea31cd39b0d571e5f63c16d"}, |
| {"internal/console/lifetimes_migrate.go", "Server.migrationMarkLocked", "record-writer", "key:RecordKey,key:WriteRecord", "337a2818254cda934193630720afe01ece59cf7ba64b94ec5a214f38c02f4b8f"}, |
| @@ -160,6 +198,15 @@ func plan14SelfServeMoves1WriteCensusInventory() []censusEntry { |
| {"internal/console/lifetimes_migrate.go", "Server.migrationStepsLocked", "key-site", "key:RecordKey", "094a3316195e4144a71c35a2c25392d5f71f6d4b22aeb6803ed852b93ff4cca6"}, |
| {"internal/console/lifetimes_migrate.go", "Server.migratePreLifetimeRecords", "key-site", "key:RecordKey", "815f90386e35dc4d99892b6593dd624262391986245c6ae8ba4980ee57ba62cf"}, |
| {"internal/console/lifetimes_migrate.go", "Server.quarantineCopy", "nonrecord", "sel:Put", "d4b7f4a8729b3e51789b5a53d8dd6cbc735f3a072314eafb02f92969a9818afb"}, |
| + {"internal/console/apiinstanceimport.go", "Server.deleteRead", "key-site", "key:RecordKey", "1b9be43c3bff269739301b24da159af790a63bb4dbe255a8affa0eec12fdd1ab"}, |
| + {"internal/console/apiinstanceimport.go", "Server.importDeleteRule", "record-writer", "key:SetRecordSeed", "173efd41a392c443cfd12036a15ff72bf61e5a32354bf5c692776d488e992834"}, |
| + {"internal/console/seedfinish.go", "Server.finishSeedOnce", "key-site", "key:RecordKey", "2c02710db39e4acc33737aa659e5492e4d2a4d186dae0f30fee21c738be2a0f9"}, |
| + {"internal/console/lifetimes_retire.go", "Server.retireRecordWithLifetimeLocked", "key-site", "key:RecordKey", "a62cf1b58fadff3e82dd1bf936d6a2aa03f93e3dfa27cd6a92269bc9c2b1f826"}, |
| + {"internal/console/lifetimes_retire.go", "Server.retireStaleLocked", "key-site", "key:RecordKey", "a1fd801aaff5c121e3b05dff4b81106ca45c9d9496f130a551ebcb23a5bd8e4c"}, |
| + {"internal/console/lifetimes_retire.go", "Server.retirementStepsLocked", "record-writer", "key:RecordKey,key:WriteRecord", "8998f80c7138d89f381620b95d5ef36bb60b00371d38c44271fe7e8d628f78c5"}, |
| + {"internal/provision/lifetime_judge.go", "IsInstanceRecordKeyOf", "key-site", "key:RecordsPrefix", "d08980ec2debf1e7c6ea71c80057a0b5a1e82d886ac7177fbd8a28e1362fcf99"}, |
| + {"internal/provision/lifetime_judge.go", "ListRecordHosts", "key-site", "key:RecordsPrefix", "e046fed7a0a5fdd03a4b8fc0d5ced7625b9f74f98fd0a5c81a5ab5c9e3067f16"}, |
| + {"internal/provision/lifetime_judge.go", "RecordEvidenceJudged", "key-site", "key:RecordsPrefix", "8f0f1fcf5fc6cfdadd83c0ccdaaf7098cfd78247465d7eaf129f75d294a85e58"}, |
| } |
| entries := plan14ClaimRosterBindingWriteCensusInventory() |
| for _, r := range removed { |
diff --git a/internal/provision/testdata/plan14-root-reads-self-serve-moves-1.tsv b/internal/provision/testdata/plan14-root-reads-self-serve-moves-1.tsv| index cdfa40780..782a32858 100644 |
| --- a/internal/provision/testdata/plan14-root-reads-self-serve-moves-1.tsv |
| +++ b/internal/provision/testdata/plan14-root-reads-self-serve-moves-1.tsv |
| @@ -1,5 +1,5 @@ |
| # Census overlay self-serve-moves-1, marked rev3=PROPOSED-self-serve-moves-1 (not an accepted ruling; docs/superpowers/notes/census-proposal-self-serve-moves-1.md). Task 1 adds the lifetime fields to provision.Record (incarnation, incarnation_migrating, move_seq, retired) and internal/provision/lifetime.go (the host incarnation slot, the lifetime verdict, the tombstone body, GetRecordRaw); GetRecordETag now hides a tombstone. Envelope only: no new root read, class or task, and the registry schema (@fields) is unchanged because Record is not a registry struct. internal/provision is re-pinned over the new code. The seal stands. |
| -@coverage internal/provision 21a263b96e4f195331f73706a0be19c528bff47ca51a08afbcde510d86704b42 |
| +@coverage internal/provision 2387e99b3501734492beb95ee4a53e30e32b6f063618e9a762016c886f7f170b |
| # Task 2 and fix round 1: rev3=PROPOSED-self-serve-moves-1 throughout; all dispositions below await the human census ruling. Console SQL and randomness run as carlos-console under console.service; no root decision is added. Existing legacy rows are re-frozen at this boundary, and the two constructors lose their own read sites to insertAppRow. |
| # The H3 removal syntax requires the census-ruling- prefix; PROPOSED in those tokens is deliberate and does not claim approval. |
| @legacy 296610cb0201ccb67b21152a50191b8b819f41e1d39fd43ca8b8d35cd75a2601 internal/console/lifetimes_store.go Store.BeginAllocation legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=console.service user carlos-console, J4 root-input: inserts one pending allocation in the console SQLite store, carrying the account, app and app lifetime; no bucket or root action file:Exec@132 7c7cb202595de014e2a549ebb001ae2c0afd800fc7959a6b5e145f5c1bc9c8ef |
| @@ -45,7 +45,7 @@ internal/console/store_gate.go claimSQLCensus legacy accepted-legacy accepted-le |
| @remove internal/console/tempstore.go Store.CreateTemporaryAppInRegion |
| @removed internal/console/tempstore.go Store.CreateTemporaryAppInRegion H3 census-ruling-PROPOSED-self-serve-moves-1;rev3=PROPOSED-self-serve-moves-1;basis=constructor remains declared but has no direct read; app insertion and lifetime minting moved to insertAppRow, classified above; proposed removal only |
| # Task 2 envelopes, rev3=PROPOSED-self-serve-moves-1: internal/console covers the lifetime store, app constructors, lifetime projection and table-scoped gate labels; internal/provision (above) adds only ErrLifetimeExhausted beyond Task 1. Registry fields are unchanged. |
| -@coverage internal/console 21d440a1f35465bf292338597a8a268d8e63b8b3ebd5dba28468fce47ae6fabb |
| +@coverage internal/console 3861bdf737af0797316bdb975085f083ec7400873f19a29a9e9cbe4bda27a27a |
| # Task 6a: rev3=PROPOSED-self-serve-moves-1; reviewed provision envelope now includes bounded record-then-slot observations, judged read/list/update gates and signed-counter exhaustion at slot read. No removal-loop, host or console change; registry fields and the legacy seal stand. |
| internal/provision/rootrecord.go IndexRecords authority B3,C rev3=PROPOSED-self-serve-moves-1;basis=retain every discovered candidate owner key per host for fresh lifetime judgement at Find; partial discovery still retries and no verdict or body is cached e44ac431865bf38baa4105f66c9cb23014cc3c7ffcd41d5385244cc76fc4c0b9 |
| internal/provision/rootrecord.go RecordIndex.Find authority B3,C rev3=PROPOSED-self-serve-moves-1;basis=observe each candidate through the context judge, refuse corruption and read failures, require one valid owner and validate its schema and shape; nil-judge duplicates retain permission refusal 760eed59cbd6a8ddab1098ce3a5f7a4272ecda81c17cc079dc135aba3a85a8f8 |
| @@ -68,3 +68,11 @@ internal/console/apex.go Server.hostHolder legacy accepted-legacy accepted-legac |
| @legacy 44be6376317c5819fc902e851b039330aff78a8f2ddc5338e95054d863151c02 internal/console/lifetimes.go newLifetimeOpID legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=console.service user carlos-console, J4 root-input: reads crypto/rand for an independent 32-hex lifetime operation id (allocations and retirements); randomness grants no root authority file:Read@71 34364098aef13cf16819336874c65fe5aa38350ec6557cb0ab67fbc3596a0df3 |
| internal/console/lifetimes.go newLifetimeOpID legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=console.service user carlos-console, J4 root-input: reads crypto/rand for an independent 32-hex lifetime operation id (allocations and retirements); randomness grants no root authority file:Read@71 34364098aef13cf16819336874c65fe5aa38350ec6557cb0ab67fbc3596a0df3 |
| # Task 5 (the lazy migration), rev3=PROPOSED-self-serve-moves-1: serve re-pinned in Task 0's rows above (it also starts the incarnation migration pass, behind CARLOS_LIFETIMES_MIGRATE=1); the internal/provision (the marker refusal in WriteRecord, the updaters' bounded wait, the marker and final bodies), internal/console (the migration protocol, its recovery and pass, the fence over another migration's marker, the flag) and cmd/console envelopes re-pinned. One changed legacy fingerprint moves the seal. No root read, class or registry field is added. Fix round 1 re-pins the internal/provision and internal/console envelopes (one marker helper, the context-bounded wait, adoption of a marker whose operation is gone, the idle cadence); no root read or legacy row changes and the seal stands. |
| +# Task 4 (retirement through a tombstone), rev3=PROPOSED-self-serve-moves-1: Store.ConvertRetirementKind added as accepted-legacy (one conditional SQLite update of a pending normal retirement); internal/domains Reconcile re-pinned (the claims-off 1d auto-purge removed; registry reads unchanged), which moves the seal; envelopes re-pinned: internal/console (retirement, purge with lifetimes, restore evidence, box floor), internal/provision (RetireExpectation, judged record evidence), internal/release (purge guards factored out, the sweep that keeps keys, the expired-trash listing), internal/domains and internal/host (lifetimes-1 published always). No root decision is added; boxes read no new root input. |
| +@legacy 87df2b9cf82f623b28c67dcb4c6b9b047dfa76ba61967cfacf8d925b7e88f806 internal/console/lifetimes_store.go Store.ConvertRetirementKind legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=console.service user carlos-console, J4 root-input: converts one pending normal SQLite retirement intent to kind cleanup with the corrupt body's ETag and refuses any other row file:Exec@215 400ffadd8d2210de9016fd288e8350307c7ecf7ba3f40dc08b9dacf63a6234b1 |
| +internal/console/lifetimes_store.go Store.ConvertRetirementKind legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=console.service user carlos-console, J4 root-input: converts one pending normal SQLite retirement intent to kind cleanup with the corrupt body's ETag and refuses any other row file:Exec@215 400ffadd8d2210de9016fd288e8350307c7ecf7ba3f40dc08b9dacf63a6234b1 |
| +@legacy 1fd9608bc83e53fa767adb28b116414434d5bd87a480b15181a12d3c763f95ec internal/domains/reconcile.go Reconcile legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), from its domains loop: the seeded-instances body (a trashed app's route kept while an import on its host is journaled, deleted only if the row is still the one listed); self-serve moves 1 Task 4 removes the claims-off 1d auto-purge, so a claims-off box destroys no app objects and a host-claim box only requests the claim's purge as before; the registry reads are unchanged registry:Account@5579,registry:Account@5775,registry:App@10116,registry:App@11452,registry:App@13691,registry:App@5380,registry:App@5528,registry:App@7191,registry:App@7248,registry:App@7449,registry:App@7662,registry:App@7900,registry:App@8090,registry:Canary@10060,registry:Canary@12738,registry:Canary@13582,registry:Channel@11507,registry:Channel@12715,registry:Channel@13613,registry:Channel@13700,registry:Channel@14003,registry:Host@10023,registry:Host@10702,registry:Host@13738,registry:Host@13823,registry:Host@13994,registry:Host@5650,registry:Host@5736,registry:Host@7298,registry:Host@7440,registry:Host@7653,registry:Host@7891,registry:Host@8081,registry:Kind@12381,registry:Platform@10044,registry:Platform@13567,whole:Route@10005,whole:Route@10111,whole:Route@10172,whole:Route@10378,whole:Route@10394,whole:Route@10520,whole:Route@10548,whole:Route@10714,whole:Route@10730,whole:Route@10738,whole:Route@11437,whole:Route@11490,whole:Route@11647,whole:Route@11663,whole:Route@12708,whole:Route@12778,whole:Route@12947,whole:Route@12963,whole:Route@12971,whole:Route@13522,whole:Route@13553,whole:Route@13686,whole:Route@13841,whole:Route@13855,whole:Route@13861,whole:Route@14033,whole:Route@14047,whole:Route@14053,whole:Route@14061,whole:Route@14070,whole:Route@5366,whole:Route@5380,whole:Route@5510,whole:Route@5528,whole:Route@5579,whole:Route@5650,whole:Route@5736,whole:Route@5775,whole:Route@7144,whole:Route@7176,whole:Route@7243,whole:Route@7469,whole:Route@7487,whole:Route@7497,whole:Route@7563,whole:Route@7680,whole:Route@7698,whole:Route@7708,whole:Route@7913,whole:Route@7931,whole:Route@7941,whole:Route@8119,whole:Route@8137,whole:Route@8147,whole:Route@8157,whole:Route@8166 9ee4958e2acd7313769f764102349ba0e6435c5dd895e9ac8e6c0f794734a7a4 |
| +internal/domains/reconcile.go Reconcile legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), from its domains loop: the seeded-instances body (a trashed app's route kept while an import on its host is journaled, deleted only if the row is still the one listed); self-serve moves 1 Task 4 removes the claims-off 1d auto-purge, so a claims-off box destroys no app objects and a host-claim box only requests the claim's purge as before; the registry reads are unchanged registry:Account@5579,registry:Account@5775,registry:App@10116,registry:App@11452,registry:App@13691,registry:App@5380,registry:App@5528,registry:App@7191,registry:App@7248,registry:App@7449,registry:App@7662,registry:App@7900,registry:App@8090,registry:Canary@10060,registry:Canary@12738,registry:Canary@13582,registry:Channel@11507,registry:Channel@12715,registry:Channel@13613,registry:Channel@13700,registry:Channel@14003,registry:Host@10023,registry:Host@10702,registry:Host@13738,registry:Host@13823,registry:Host@13994,registry:Host@5650,registry:Host@5736,registry:Host@7298,registry:Host@7440,registry:Host@7653,registry:Host@7891,registry:Host@8081,registry:Kind@12381,registry:Platform@10044,registry:Platform@13567,whole:Route@10005,whole:Route@10111,whole:Route@10172,whole:Route@10378,whole:Route@10394,whole:Route@10520,whole:Route@10548,whole:Route@10714,whole:Route@10730,whole:Route@10738,whole:Route@11437,whole:Route@11490,whole:Route@11647,whole:Route@11663,whole:Route@12708,whole:Route@12778,whole:Route@12947,whole:Route@12963,whole:Route@12971,whole:Route@13522,whole:Route@13553,whole:Route@13686,whole:Route@13841,whole:Route@13855,whole:Route@13861,whole:Route@14033,whole:Route@14047,whole:Route@14053,whole:Route@14061,whole:Route@14070,whole:Route@5366,whole:Route@5380,whole:Route@5510,whole:Route@5528,whole:Route@5579,whole:Route@5650,whole:Route@5736,whole:Route@5775,whole:Route@7144,whole:Route@7176,whole:Route@7243,whole:Route@7469,whole:Route@7487,whole:Route@7497,whole:Route@7563,whole:Route@7680,whole:Route@7698,whole:Route@7708,whole:Route@7913,whole:Route@7931,whole:Route@7941,whole:Route@8119,whole:Route@8137,whole:Route@8147,whole:Route@8157,whole:Route@8166 9ee4958e2acd7313769f764102349ba0e6435c5dd895e9ac8e6c0f794734a7a4 |
| +@coverage internal/domains f0f68ddee74e459f4416359b4b5d8c911d6c0850d70032bd7346c6b82f1a0885 |
| +@coverage internal/host 3970cbbb74fee62e932536f20cf4e04e6c02d5651b014531e6673982d2a5ed16 |
| +@coverage internal/release 99ef7ef9b58b82e6fb4b22a6e378a04d8fd9cccafe1f8726710b8181058ec065 |