carlos / platform Public

domains: an unknown label keeps its alias only after the name's precedence checks pass (final review 2, N1)

F3's unknown-label branch marked the existing alias desired and moved on
before the name validity, exact-claim, local-route and deployment-route
checks, so an exact claim on another app (primary on another box) or a
route collision no longer removed the alias. The branch now runs after
those checks and the already-desired check, and a kept row counts
against the per-box cap. Census: deriveInstanceAliases re-frozen (the
seal moves) and the internal/domains envelope refreshed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev e8087b49c4358a0cc99b17f3fb842b1f7c52f384 parent a232dc7
5 files changed, +76 −16
  • docs/superpowers/notes/census-proposal-self-serve-moves-1.md +1 −1
  • internal/domains/aliases.go +17 −10
  • internal/domains/instancecatchall_judged_test.go +50 −0
  • internal/provision/plan14_root_reads_test.go +4 −2
  • internal/provision/testdata/plan14-root-reads-self-serve-moves-1.tsv +4 −3

CI failed — run details

CI log
=== gate ===
.amadan/test-gate.sh

amadan: job timed out after 30m0s

amadan: job failed at step gate — its output is above, not at the tail of this log
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 1112e4aa6..82224cc49 100644
--- a/docs/superpowers/notes/census-proposal-self-serve-moves-1.md
+++ b/docs/superpowers/notes/census-proposal-self-serve-moves-1.md
@@ -44,6 +44,6 @@ Task 9 fix round 1 corrects Task 3's create door. When a delayed create's SQLite
Final review fix round. F1 changes the cutover door: it skips the box floor only once a validated marker body has been read or written by the door, never on the gate's state alone. A failed marker read still closes admission. `Server.handleAPILifetimesCutover` stays nonrecord and is re-pinned in place in the record-write inventory. F2 narrows the create's orphan rule: a live slot of another owner is retired only when no record exists under that owner's key, and a present body of any verdict refuses the create and is left untouched. `Server.planCreateLocked` is not a census unit, so only the envelope moves. F3 judges the catch-all label counts. `internal/domains` cannot import `internal/provision`, so it declares an `InstanceObserver` interface and its own context key, and `provision.WithJudge` records the same judge there (nil records none). `domains.InstanceLabelCountsJudged` counts only what the judge vouches for and reports a label with an unjudgeable record as unknown; with no observer it is `InstanceLabelCounts`. `ReconcileAliases` and `deriveInstanceAliases` (accepted legacy, rev3=J1) are re-frozen with reviewed bases: a stale body no longer makes a label shared, and an unknown label keeps its existing alias row and derives none, which adds four read sites on that row (`registry:Account`, `registry:Alias`, `registry:App` and the whole `RouteAlias`). That moves the seal. In the record-write inventory, `InstanceLabelCounts` leaves and `instanceHosts`, the key listing it now shares with the judged counter, takes its place as a key-site. `Server.catchallInstanceName` counts through the judged counter with the request's judge. The `internal/domains` and `internal/provision` envelopes are refreshed in place. F5 makes the migration pass report the migrations it attempted rather than the candidates it listed, so a candidate a pending operation blocks leaves the pass on its ten-minute idle cadence. `Server.migratePreLifetimeRecords` stays a key-site and is re-pinned in place. F6 changes a host test only. F7 bounds two in-process maps: the hostname exclusion is now refcounted, so an entry goes when its last holder or waiter is done, and the hourly lifetime log throttle prunes keys older than two hours when it logs a line. Neither reads or writes the bucket. The `internal/console` envelope is refreshed in place after each finding. No root read, class or task is added.
-Final review fix round 2. R1 closes the own-key half of F2. A create over a live slot of its own key with a present corrupt or stale body no longer takes the orphan retirement, which deleted the bytes with no copy. It now takes Task 4's cleanup: `Server.retireStaleLocked` copies a corrupt body to `control/quarantine/` first, then a cleanup retirement retires the slot before the body is deleted on its ETag. The create then classifies again. A failure before the cleanup row, the copy included, touches nothing and answers pending. `Server.planCreateLocked` is not a census unit and `Server.retireStaleLocked` is unchanged, so only the `internal/console` envelope moves.
+Final review fix round 2. R1 closes the own-key half of F2. A create over a live slot of its own key with a present corrupt or stale body no longer takes the orphan retirement, which deleted the bytes with no copy. It now takes Task 4's cleanup: `Server.retireStaleLocked` copies a corrupt body to `control/quarantine/` first, then a cleanup retirement retires the slot before the body is deleted on its ETag. The create then classifies again. A failure before the cleanup row, the copy included, touches nothing and answers pending. `Server.planCreateLocked` is not a census unit and `Server.retireStaleLocked` is unchanged, so only the `internal/console` envelope moves. N1 corrects F3's unknown-label keep in `deriveInstanceAliases`. The existing row is now kept only after the derived name has passed every check a derived name answers to: its validity, an exact claim, a local real route, a deployment route, an alias already desired and the per-box cap. An exact claim or a route collision therefore removes it again. The unit is re-frozen with a reviewed basis. Against rev3=J1 it now adds three read sites on the kept row (`registry:Account`, `registry:App` and the whole `RouteAlias`); the row's `Alias` is no longer read. That moves the seal, and the `internal/domains` envelope is refreshed in place. No class or task is added.
Taken together, the rows marked `PROPOSED-self-serve-moves-1` are the census of one change. Claims-off instance records gain a lifetime: the host incarnation slot, written only through `WriteHostIncarnation` by the console's create, retirement and migration protocols. Every claims-off consumer judges a record against its slot before it acts on it. Every record write stays on `WriteRecord` with the sequence discipline. The per-host `move_seq` and each row's `(incarnation, serving_seq)` pair order the publications an edge folds. Each row is one of five kinds: a write site added or re-pinned in the record-write inventory (each through `WriteRecord`, a `DeleteIfMatch` on an observed ETag, or a Put of a control key that is not a record); a read made judged at its existing class; a console SQLite unit or a legacy fingerprint with a reviewed basis; the `@fields` schema row, which pins the registry fields Task 7 adds (`Route.Incarnation`, `Route.ServingSeq`, and the remote request's `Pair` and `ExpectPair`); or a source envelope refreshed over the new code. No row adds a raw record write, a root-read class or a task. The two registry read sites added in Task 8 are named in its paragraph. These rows are one proposal, for Paul to rule on once, together, after the plan's final review. Until then every row stays PROPOSED, and a green census means only that the rows match the code, not that they are accepted.
diff --git a/internal/domains/aliases.go b/internal/domains/aliases.go
index ba8be39d2..46557e30c 100644
--- a/internal/domains/aliases.go
+++ b/internal/domains/aliases.go
@@ -183,16 +183,6 @@ func deriveInstanceAliases(claims []Claim, listed map[string]bool, routes []regi
sayInstanceCatchallOnce(c.Host, "label "+label+" is shared by "+strconv.Itoa(hostsOf[label])+" instances of "+c.App+" (its instance domain was changed); "+label+"."+parent+" serves none of them until one is deleted")
continue
}
- if unknownOf[label] {
- // A record under this label could not be judged: whether
- // the label is shared is unknown, so its existing row is
- // kept as it is this pass and no new one is derived.
- if a, ok := have[label+"."+parent]; ok && a.Account == c.Account && a.App == c.App {
- desired[a.Alias] = true
- }
- sayInstanceCatchallOnce(c.Host, "a record of label "+label+" could not be judged; its name is kept as it is until it can be")
- continue
- }
name := label + "." + parent
if n, ok := NormalizeAliasHost(name); !ok || n != name {
continue // too long once joined to parent
@@ -205,6 +195,23 @@ func deriveInstanceAliases(claims []Claim, listed map[string]bool, routes []regi
if _, taken := byHost[name]; taken || deploymentRoutes[name] || desired[name] {
continue
}
+ if unknownOf[label] {
+ // A record under this label could not be judged: whether
+ // the label is shared is unknown, so its existing row is
+ // kept as it is this pass and no new one is derived. Only
+ // the count is uncertain: the name, an exact claim and the
+ // routes above outrank it as they outrank any derived name.
+ if a, ok := have[name]; ok && a.Account == c.Account && a.App == c.App {
+ if derived >= maxInstanceAliases {
+ sayInstanceCatchallOnce(c.Host, "this box is at its cap of "+strconv.Itoa(maxInstanceAliases)+" derived names; the rest of the app's instances here serve on their own hosts only")
+ break
+ }
+ derived++
+ desired[name] = true
+ }
+ sayInstanceCatchallOnce(c.Host, "a record of label "+label+" could not be judged; its name is kept as it is until it can be")
+ continue
+ }
if derived >= maxInstanceAliases {
sayInstanceCatchallOnce(c.Host, "this box is at its cap of "+strconv.Itoa(maxInstanceAliases)+" derived names; the rest of the app's instances here serve on their own hosts only")
break
diff --git a/internal/domains/instancecatchall_judged_test.go b/internal/domains/instancecatchall_judged_test.go
index bcbe2a8ee..a3308f01d 100644
--- a/internal/domains/instancecatchall_judged_test.go
+++ b/internal/domains/instancecatchall_judged_test.go
@@ -4,6 +4,7 @@ import (
"context"
"testing"
+ "github.com/carlosframework/platform/internal/registry"
"github.com/carlosframework/platform/internal/release"
)
@@ -137,3 +138,52 @@ func TestInstanceCatchallJudgesTheLabelCount(t *testing.T) {
}
})
}
+
+// Keeping an unknown label's existing row never outranks the precedence
+// every derived name answers to: an exact claim on the name, a local real
+// route or a deployment route still removes it (final review 2, N1).
+func TestInstanceCatchallUnknownLabelKeepsPrecedence(t *testing.T) {
+ const name = "team.shop.example.com"
+ for _, c := range []struct {
+ what string
+ arrange func(t *testing.T, s release.Store, reg *registry.Registry) map[string]bool
+ kept bool
+ }{
+ {"an exact claim on another app, primary on another box", func(t *testing.T, s release.Store, _ *registry.Registry) map[string]bool {
+ putClaim(t, s, Claim{Host: name, Account: "bab", App: "other", Route: "x.remote.example.net"})
+ return nil
+ }, false},
+ {"a deployment route", func(t *testing.T, _ release.Store, _ *registry.Registry) map[string]bool {
+ return map[string]bool{name: true}
+ }, false},
+ {"a local real route", func(t *testing.T, _ release.Store, reg *registry.Registry) map[string]bool {
+ addRoute(t, reg, name, "bab", "other")
+ return nil
+ }, false},
+ {"no disqualifier", func(*testing.T, release.Store, *registry.Registry) map[string]bool { return nil }, true},
+ } {
+ t.Run(c.what, func(t *testing.T) {
+ s := shopCatchall(t)
+ putRecordKey(t, s, "bab", "shop", "team.new.example.com")
+ reg := aliasRegWith(t)
+ addInstance(t, reg, "team.new.example.com", "team", "bab", "shop")
+ if err := ReconcileAliases(context.Background(), s, reg, aliasNow(), nil, nil); err != nil {
+ t.Fatal(err)
+ }
+ if aliasMap(t, reg)[name].Host != "team.new.example.com" {
+ t.Fatal("precondition: the name derives")
+ }
+ putRecordKey(t, s, "bab", "shop", "team.old.example.com")
+ deploymentRoutes := c.arrange(t, s, reg)
+ o := &fakeObserver{verdicts: map[string]InstanceVerdict{"team.old.example.com": InstanceUnknown}}
+ if err := ReconcileAliases(WithInstanceObserver(context.Background(), o), s, reg, aliasNow(), deploymentRoutes, nil); err != nil {
+ t.Fatal(err)
+ }
+ a, ok := aliasMap(t, reg)[name]
+ kept := ok && a.App == "shop" && a.Host == "team.new.example.com"
+ if kept != c.kept {
+ t.Fatalf("derived alias kept = %v (%+v), want %v", kept, a, c.kept)
+ }
+ })
+ }
+}
diff --git a/internal/provision/plan14_root_reads_test.go b/internal/provision/plan14_root_reads_test.go
index ad15ac310..f8d72b2e0 100644
--- a/internal/provision/plan14_root_reads_test.go
+++ b/internal/provision/plan14_root_reads_test.go
@@ -1289,8 +1289,10 @@ func TestPlan14RootReadCensus(t *testing.T) {
// takes the box's lifetimes switch, and moves it once more. The final
// review's fix round (F3) re-freezes ReconcileAliases and
// deriveInstanceAliases, whose catch-all label counts are judged, and
- // moves it again.
- seal = "09fc7839a7111d1e945ac07f37a1b28659634149b90537ae4b533af1d98de290"
+ // moves it again. Fix round 2 (N1) re-freezes deriveInstanceAliases,
+ // whose unknown-label keep now follows the name's precedence checks,
+ // and moves it once more.
+ seal = "e3beb6d4a83363991ddd2d6e856aebc8d3ca69c4cb02f6b1a30449f104224dd0"
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-self-serve-moves-1.tsv b/internal/provision/testdata/plan14-root-reads-self-serve-moves-1.tsv
index 4896fbd56..90f813f53 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
@@ -73,7 +73,7 @@ internal/console/lifetimes.go newLifetimeOpID legacy accepted-legacy accepted-le
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 78f7cb6c185da532240d402d3444b9750b9a81f86f1d204d26851309299e3e41
+@coverage internal/domains 5bbd26617e88096314b413305c6ae152da49244ebbe1cc90f15a6e01ef7a229d
@coverage internal/host c520fb14e1584aebc16285652da59f50b945dc2fc9159919d4c5b3d7ff628169
@coverage internal/release 99ef7ef9b58b82e6fb4b22a6e378a04d8fd9cccafe1f8726710b8181058ec065
# Task 6b (consumers observe the lifetime: the provision reconcile and import journal, the host wiring and readers), rev3=PROPOSED-self-serve-moves-1: every changed unit re-pinned at its class and task with a reviewed basis; legacy units keep accepted-legacy and take a new frozen fingerprint (the seal moves); the four units with no read left re-pinned at their declarations; seedrollback.go journalRecordJudged added as accepted-legacy beside journalRecordByKey. All rows await the human census ruling.
@@ -197,8 +197,9 @@ internal/host/edgesfile.go edgesFileLoop legacy accepted-legacy accepted-legacy;
# Final review fix round F3 (catch-all label counts judged), rev3=PROPOSED-self-serve-moves-1: ReconcileAliases (accepted legacy) now hands deriveInstanceAliases a judged counter (domains.InstanceLabelCountsJudged with the context's observer, which provision.WithJudge records beside the judge; nil is today's key count); its read sites are unchanged, offsets moved. deriveInstanceAliases (accepted legacy) skips stale bodies in the shared-label count and, for a label with a record that cannot be judged, keeps its existing alias row (four new sites on that row: registry:Account, registry:Alias, registry:App and the whole RouteAlias) and derives none. Both are re-frozen with reviewed bases, which moves the seal. The internal/console (catchallInstanceName judged), internal/domains and internal/provision (ObserveInstance, InstanceObserver, WithJudge) envelopes are refreshed in place. No class or task is added; registry fields stand.
@legacy bfee05191142ea2c7985d11be04b944c38dccb6e6eed9f5eb14e3fd5f788047f internal/domains/aliases.go ReconcileAliases legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=root-route; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), from its fast-converge and instances loops: rev3=J1's body, which now counts the catch-all's labels through domains.InstanceLabelCountsJudged with the pass context's observer (provision.WithLifetimes on a claims-off box; none on a claims-on box, which is today's key count); registry read sites unchanged, offsets moved registry:Account@15249,registry:Account@15262,registry:Alias@14864,registry:Alias@14904,registry:Alias@14974,registry:App@11952,registry:App@12152,registry:App@12308,registry:App@12509,registry:App@15275,registry:App@15284,registry:App@2026,registry:App@2222,registry:App@5823,registry:App@6022,registry:Host@15234,registry:Host@15523,registry:Host@15576,registry:Host@15648,registry:Host@16160,registry:Host@16252,registry:Host@16311,registry:Host@16392,registry:Host@406,registry:Prefix@16168,registry:Prefix@16266,registry:Prefix@16319,registry:Prefix@16400,registry:Status@8686,whole:Route@11921,whole:Route@11996,whole:Route@12143,whole:Route@12205,whole:Route@12348,whole:Route@12504,whole:Route@13400,whole:Route@1369,whole:Route@14469,whole:Route@14477,whole:Route@2066,whole:Route@2217,whole:Route@2273,whole:Route@359,whole:Route@388,whole:Route@399,whole:Route@417,whole:Route@5169,whole:Route@5867,whole:Route@6013,whole:Route@8016,whole:Route@8468,whole:Route@8630,whole:RouteAlias@14485,whole:RouteAlias@14839,whole:RoutePath@10213,whole:RoutePath@16053,whole:RoutePath@16095,whole:RoutePath@16209,whole:RoutePath@16239,whole:WildcardDomain@12720,whole:WildcardDomain@15164,whole:WildcardDomain@15213,whole:WildcardDomain@15376,whole:WildcardDomain@15482,whole:WildcardDomain@15511 f0cb08a90be8c8d6c97c24be3cf73720abb54cb8444793fa25ba982e9525e9f9
internal/domains/aliases.go ReconcileAliases legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=root-route; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), from its fast-converge and instances loops: rev3=J1's body, which now counts the catch-all's labels through domains.InstanceLabelCountsJudged with the pass context's observer (provision.WithLifetimes on a claims-off box; none on a claims-on box, which is today's key count); registry read sites unchanged, offsets moved registry:Account@15249,registry:Account@15262,registry:Alias@14864,registry:Alias@14904,registry:Alias@14974,registry:App@11952,registry:App@12152,registry:App@12308,registry:App@12509,registry:App@15275,registry:App@15284,registry:App@2026,registry:App@2222,registry:App@5823,registry:App@6022,registry:Host@15234,registry:Host@15523,registry:Host@15576,registry:Host@15648,registry:Host@16160,registry:Host@16252,registry:Host@16311,registry:Host@16392,registry:Host@406,registry:Prefix@16168,registry:Prefix@16266,registry:Prefix@16319,registry:Prefix@16400,registry:Status@8686,whole:Route@11921,whole:Route@11996,whole:Route@12143,whole:Route@12205,whole:Route@12348,whole:Route@12504,whole:Route@13400,whole:Route@1369,whole:Route@14469,whole:Route@14477,whole:Route@2066,whole:Route@2217,whole:Route@2273,whole:Route@359,whole:Route@388,whole:Route@399,whole:Route@417,whole:Route@5169,whole:Route@5867,whole:Route@6013,whole:Route@8016,whole:Route@8468,whole:Route@8630,whole:RouteAlias@14485,whole:RouteAlias@14839,whole:RoutePath@10213,whole:RoutePath@16053,whole:RoutePath@16095,whole:RoutePath@16209,whole:RoutePath@16239,whole:WildcardDomain@12720,whole:WildcardDomain@15164,whole:WildcardDomain@15213,whole:WildcardDomain@15376,whole:WildcardDomain@15482,whole:WildcardDomain@15511 f0cb08a90be8c8d6c97c24be3cf73720abb54cb8444793fa25ba982e9525e9f9
-@legacy a37ea03438815852c187e4b5e8d83641253f23e8cbd48898abd4e2c72820c65e internal/domains/aliases.go deriveInstanceAliases legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=root-route; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): rev3=J1's body; a stale body under a retired lifetime no longer makes a label shared, and a label with a record that cannot be judged keeps its existing alias row of the catch-all's own account and app (reading that row's Account, App and Alias) and derives no new one; a report-only conservative keep, never a new route registry:Account@2163,registry:Account@2950,registry:Account@3913,registry:Alias@2225,registry:Alias@2293,registry:Alias@2337,registry:Alias@3006,registry:Alias@557,registry:App@1686,registry:App@2189,registry:App@2976,registry:App@3939,registry:Host@1843,registry:Host@3892,registry:Host@3902,registry:Host@4098,registry:Provisioned@1636,registry:Replica@1672,registry:Slug@1775,whole:Route@1620,whole:Route@1726,whole:Route@3502,whole:RouteAlias@2143,whole:RouteAlias@2920,whole:RouteAlias@3874,whole:RouteAlias@509,whole:RouteAlias@539,whole:RouteAlias@552,whole:RouteAlias@568 888a5a32dbbcd9619b0bf513c0dc746686ad7c4e5681bf82248022e8f13b2512
-internal/domains/aliases.go deriveInstanceAliases legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=root-route; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): rev3=J1's body; a stale body under a retired lifetime no longer makes a label shared, and a label with a record that cannot be judged keeps its existing alias row of the catch-all's own account and app (reading that row's Account, App and Alias) and derives no new one; a report-only conservative keep, never a new route registry:Account@2163,registry:Account@2950,registry:Account@3913,registry:Alias@2225,registry:Alias@2293,registry:Alias@2337,registry:Alias@3006,registry:Alias@557,registry:App@1686,registry:App@2189,registry:App@2976,registry:App@3939,registry:Host@1843,registry:Host@3892,registry:Host@3902,registry:Host@4098,registry:Provisioned@1636,registry:Replica@1672,registry:Slug@1775,whole:Route@1620,whole:Route@1726,whole:Route@3502,whole:RouteAlias@2143,whole:RouteAlias@2920,whole:RouteAlias@3874,whole:RouteAlias@509,whole:RouteAlias@539,whole:RouteAlias@552,whole:RouteAlias@568 888a5a32dbbcd9619b0bf513c0dc746686ad7c4e5681bf82248022e8f13b2512
# Final review fix round F5, rev3=PROPOSED-self-serve-moves-1: the migration pass reports the migrations it attempted, not the candidates it listed, so a blocked candidate leaves it on the idle cadence; no read site added. The internal/console envelope is refreshed in place above; no root read, class, legacy row or seal changes.
# Final review fix round F7, rev3=PROPOSED-self-serve-moves-1: the hostname exclusion becomes a refcounted keyedLocks (an entry goes when its last holder or waiter is done) and the hourly lifetime log throttle prunes keys older than two hours when it logs. In-process state only: no read site, class, legacy row or seal changes; the internal/console envelope is refreshed in place above.
# Final review fix round 2, R1, rev3=PROPOSED-self-serve-moves-1: a create over a live slot of its own key with a present corrupt or stale body cleans it up through retireStaleLocked (the corrupt bytes quarantined, then a cleanup retirement) instead of the orphan retirement; no read site added. The internal/console envelope is refreshed in place above; no root read, class, legacy row or seal changes.
+# Final review fix round 2, N1, rev3=PROPOSED-self-serve-moves-1: deriveInstanceAliases (accepted legacy) keeps an unknown label's existing alias row only after the name's validity, an exact claim (listed), a local real route, a deployment route and an alias already desired have all let it through, and counts a kept row against the per-box cap. Its F3 row is replaced: against rev3=J1 it now adds three read sites on the kept row (registry:Account, registry:App and the whole RouteAlias; the row's Alias is no longer read, the name being the derived one). Re-frozen with a reviewed basis, which moves the seal; the internal/domains envelope is refreshed in place above.
+@legacy 05d668731b3a15c47627f2b255a6119f54db0898a57908786fd6308dd274e73a internal/domains/aliases.go deriveInstanceAliases legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=root-route; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): rev3=J1's body; a stale body under a retired lifetime no longer makes a label shared, and a label with a record that cannot be judged keeps its existing alias row of the catch-all's own account and app (reading that row's Account and App) only once the derived name has passed every precedence check a derived name answers to (validity, an exact claim, a local real route, a deployment route, the per-box cap), and derives no new one; a report-only conservative keep, never a new route registry:Account@2163,registry:Account@3481,registry:Account@4292,registry:Alias@2225,registry:Alias@2293,registry:Alias@2337,registry:Alias@557,registry:App@1686,registry:App@2189,registry:App@3507,registry:App@4318,registry:Host@1843,registry:Host@4271,registry:Host@4281,registry:Host@4477,registry:Provisioned@1636,registry:Replica@1672,registry:Slug@1775,whole:Route@1620,whole:Route@1726,whole:Route@3023,whole:RouteAlias@2143,whole:RouteAlias@3463,whole:RouteAlias@4253,whole:RouteAlias@509,whole:RouteAlias@539,whole:RouteAlias@552,whole:RouteAlias@568 cd9fb37bb13b5c6512a469bc47966ddb4e1d7ac0811c9b10147c24117ce7d8de
+internal/domains/aliases.go deriveInstanceAliases legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-1;basis=root-route; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): rev3=J1's body; a stale body under a retired lifetime no longer makes a label shared, and a label with a record that cannot be judged keeps its existing alias row of the catch-all's own account and app (reading that row's Account and App) only once the derived name has passed every precedence check a derived name answers to (validity, an exact claim, a local real route, a deployment route, the per-box cap), and derives no new one; a report-only conservative keep, never a new route registry:Account@2163,registry:Account@3481,registry:Account@4292,registry:Alias@2225,registry:Alias@2293,registry:Alias@2337,registry:Alias@557,registry:App@1686,registry:App@2189,registry:App@3507,registry:App@4318,registry:Host@1843,registry:Host@4271,registry:Host@4281,registry:Host@4477,registry:Provisioned@1636,registry:Replica@1672,registry:Slug@1775,whole:Route@1620,whole:Route@1726,whole:Route@3023,whole:RouteAlias@2143,whole:RouteAlias@3463,whole:RouteAlias@4253,whole:RouteAlias@509,whole:RouteAlias@539,whole:RouteAlias@552,whole:RouteAlias@568 cd9fb37bb13b5c6512a469bc47966ddb4e1d7ac0811c9b10147c24117ce7d8de