carlos / platform Public

self-serve moves: the target's landing hold lists the custom domain, one hold validity test for rank and the e2e seam (Task 7 review round 1)

The holding page witness asserts the target's landing hold lists the
explicit custom domain in every round once the target's row for it has
been stamped pointing. rank.go's holdLive is the one validity test, used
by rank and by E2ERemoteCandidates. A comment on candidates corrected.
Census: the internal/edge envelope re-pinned; no unit moves, the seal is
unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev d04ba6b49b9323d7073a29c3b4cb33c446ba0aef parent 408279c
6 files changed, +34 −8
  • docs/superpowers/notes/census-proposal-self-serve-moves-3.md +4 −0
  • internal/e2e/selfserve/holding_test.go +14 −3
  • internal/e2e/selfserve/holding_world_test.go +7 −2
  • internal/edge/e2e_bridge.go +1 −1
  • internal/edge/rank.go +6 −1
  • internal/provision/testdata/plan14-root-reads-self-serve-moves-3.tsv +2 −1

CI failed — run details

CI log
=== gate ===
sigwho: pid 2 ppid 1 pgid 0 sid 0; child pid 3
.amadan/test-gate.sh
gate: 2026-10-24T06:26:22Z on aarch64, 32 cpus, 61432 MB available, go1.26.8 linux/arm64
gate: +0s start launchctx
gate: +0s start vet
gate: +0s start gofmt
gate: +1s start rest
gate: +19s start internal_console@0
gate: +19s start internal_console@1
gate: +19s start internal_console@2
gate: +19s start internal_console@3
gate: +19s start internal_console@4
gate: +19s start internal_console@5
gate: +19s start internal_console@6
gate: +19s start internal_console@7
gate: +19s waiting for internal_console's shards before the next split package
gate: +188s start root@0
gate: +188s start root@1
gate: +188s start root@2
gate: +188s waiting for root's shards before the next split package

amadan: step gate failed: signal: terminated

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-3.md b/docs/superpowers/notes/census-proposal-self-serve-moves-3.md
index 20fbcb6f1..43e181f9f 100644
--- a/docs/superpowers/notes/census-proposal-self-serve-moves-3.md
+++ b/docs/superpowers/notes/census-proposal-self-serve-moves-3.md
@@ -151,3 +151,7 @@ The envelopes the plan changes, each re-pinned in the overlay's `@coverage` rows
`internal/steering` is not an envelope here. Its only change is Task 4's test file, and the census reads no test file.
The registry field is `route_aliases.explicit` (`RouteAlias.Explicit`), tracked as `Explicit` in the overlay's `@fields` row. `TestPlan9B8RecordWriteCensus` takes `plan14SelfServeMoves3WriteCensusInventory`, which adds and removes nothing in this plan, and stays green.
+
+### Task 7 review round 1
+
+`edge/rank.go` gains `holdLive`: a remote hold is believed while it is less than `holdingValidity` old. `rank` and the e2e seam's `E2ERemoteCandidates` both use it, so the two cannot disagree on the boundary. `rank.go` reads no row and is not a census unit. No unit's fingerprint moves, and the seal stays `e070316b…`. The `internal/edge` envelope is re-pinned. No root read, class or task is added.
diff --git a/internal/e2e/selfserve/holding_test.go b/internal/e2e/selfserve/holding_test.go
index f5143bb8c..9ad77dfc1 100644
--- a/internal/e2e/selfserve/holding_test.go
+++ b/internal/e2e/selfserve/holding_test.go
@@ -87,7 +87,7 @@ func TestHoldingPageOnAThirdEdgeAndACustomDomain(t *testing.T) {
w.requireApp("before the move, the third edge's "+name, w.ask(w.third, name), src, http.StatusOK)
}
row := w.toCut()
- var before, holding, opened, failing int
+ var before, holding, opened, failing, targetListed int
copySeen := map[string]bool{}
w.drive(300, "done", row.ID, func(r *console.SelfServeMove) {
started := holding > 0 || w.held(src)
@@ -117,6 +117,17 @@ func TestHoldingPageOnAThirdEdgeAndACustomDomain(t *testing.T) {
}
case started:
holding++
+ // The target's landing hold lists the domain too, from the
+ // first publication made after its row for the domain could be
+ // stamped pointing (the alias pass makes the row in the tick
+ // after the landing row appears; the DNS stamp comes a round
+ // later, as the health pass would).
+ if w.published(tgt, host.E2EHost).held && w.tgtAliasPointing {
+ if !w.published(tgt, customDomain).held {
+ t.Fatalf("%s: the target's landing hold does not list %s", r.Phase, customDomain)
+ }
+ targetListed++
+ }
for _, name := range names {
copySeen[w.requirePage(r.Phase+": the third edge's "+name, w.ask(w.third, name))] = true
if w.held(src) {
@@ -147,8 +158,8 @@ func TestHoldingPageOnAThirdEdgeAndACustomDomain(t *testing.T) {
}
}
}
- if before == 0 || holding == 0 || opened == 0 || failing < 2 {
- t.Fatalf("rounds: %d before the start, %d holding, %d open (%d failing)", before, holding, opened, failing)
+ if before == 0 || holding == 0 || opened == 0 || failing < 2 || targetListed == 0 {
+ t.Fatalf("rounds: %d before the start, %d holding (%d with the target's hold listing the domain), %d open (%d failing)", before, holding, targetListed, opened, failing)
}
if !copySeen["MV-O259"] {
t.Fatalf("the page never named the account with an estimate: %v", copySeen)
diff --git a/internal/e2e/selfserve/holding_world_test.go b/internal/e2e/selfserve/holding_world_test.go
index e69f4bb8b..435de27e2 100644
--- a/internal/e2e/selfserve/holding_world_test.go
+++ b/internal/e2e/selfserve/holding_world_test.go
@@ -282,6 +282,10 @@ type holdWorld struct {
// thirdReg is the third edge's own registry (empty unless a witness
// gives it a route).
thirdReg *registry.Registry
+ // tgtAliasPointing is whether the target box had a row for the custom
+ // domain, stamped pointing, when this round's tick began: the round's
+ // publication can list the domain only then (round).
+ tgtAliasPointing bool
}
// newHoldWorld builds the job's world, the two boxes' edges and the third
@@ -418,6 +422,7 @@ func (w *holdWorld) pollThird() error {
func (w *holdWorld) round(id string, observe func(r *console.SelfServeMove)) {
w.t.Helper()
w.pointAliases()
+ w.tgtAliasPointing = w.aliasRow(host.E2ETargetBox, customDomain) != nil
w.boxes()
w.converge()
r := w.row(id)
@@ -747,8 +752,8 @@ func (w *holdWorld) aliasRow(box, name string) *registry.RouteAlias {
return nil
}
-// candidates is the third edge's admitted remote candidates for name, as
-// a string for a failure message.
+// candidates is be's admitted remote candidates for name
+// (describeCandidates renders them for a failure message).
func (w *holdWorld) candidates(be *boxEdge, name string) []edge.E2ECandidate {
return edge.E2ERemoteCandidates(be.e, name)
}
diff --git a/internal/edge/e2e_bridge.go b/internal/edge/e2e_bridge.go
index 52f5c10c1..1aa1c8103 100644
--- a/internal/edge/e2e_bridge.go
+++ b/internal/edge/e2e_bridge.go
@@ -90,7 +90,7 @@ func E2ERemoteCandidates(e *Edge, name string) []E2ECandidate {
x.Type = "ready"
case candHolding:
x.Type = "holding"
- x.Live = now.Sub(c.fetchedAt) < holdingValidity
+ x.Live = holdLive(c.fetchedAt, now)
default:
x.Type = "cert"
}
diff --git a/internal/edge/rank.go b/internal/edge/rank.go
index 1fba14b3a..dea812b4b 100644
--- a/internal/edge/rank.go
+++ b/internal/edge/rank.go
@@ -26,6 +26,11 @@ import (
// box's own view says so.
const holdingValidity = 5 * time.Minute
+// holdLive is whether a remote holding candidate fetched at fetchedAt is
+// still believed at now: strictly less than holdingValidity old (at
+// exactly 5 m 0 s it is expired).
+func holdLive(fetchedAt, now time.Time) bool { return now.Sub(fetchedAt) < holdingValidity }
+
type candKind uint8
const (
@@ -149,7 +154,7 @@ func (c candidate) entry() homeEntry {
func rank(name string, cands []candidate, now time.Time) decision {
live := make([]candidate, 0, len(cands))
for _, c := range cands {
- if c.kind == candHolding && !c.local && now.Sub(c.fetchedAt) >= holdingValidity {
+ if c.kind == candHolding && !c.local && !holdLive(c.fetchedAt, now) {
continue
}
live = append(live, c)
diff --git a/internal/provision/testdata/plan14-root-reads-self-serve-moves-3.tsv b/internal/provision/testdata/plan14-root-reads-self-serve-moves-3.tsv
index 9d3140fdc..39fe809e7 100644
--- a/internal/provision/testdata/plan14-root-reads-self-serve-moves-3.tsv
+++ b/internal/provision/testdata/plan14-root-reads-self-serve-moves-3.tsv
@@ -8,6 +8,7 @@
# Task 6 (probe mode), rev3=PROPOSED-self-serve-moves-3: a probe (X-Carlos-Probe: local) is refused in backhaulTo before the key and the cap (503 "not served here", no dial), and a probe served locally is answered under servedByWriter (servedby.go, new; reads no row) and kept out of the response cache. Edge.ServeHTTP is re-pinned in place (read sites unchanged, offsets moved). The console's health probe asks in probe mode and requires X-Carlos-Served-By to be the pinned target's box id: Server.probeTarget, accepted legacy since self-serve moves 2 Task 8, is re-pinned here (read site unchanged). Both re-pins move the seal; the internal/edge and internal/console envelopes are re-pinned. No root read, class or task is added.
# Task 6 review round 1, rev3=PROPOSED-self-serve-moves-3: the two "not served here" bodies (the probe refusal and homeMap.staleHopRefusal) share one constant, notServedHere in servedby.go, and ServeHTTP gains a comment on why a probe may be served from the local catch-all. Edge.ServeHTTP is re-pinned in place (read sites unchanged, offsets moved), which moves the seal; the internal/edge envelope is re-pinned. No root read, class or task is added.
# Task 7 (the end-to-end witnesses), rev3=PROPOSED-self-serve-moves-3: tests in internal/e2e/selfserve, plus two seams. internal/edge/e2e_bridge.go (new, //go:build e2e, so no production binary carries it) arms an Edge's home map without its loop, runs one poll, sets the map's clock, points the backhaul dial at loopback listeners and lists a name's admitted candidates: it reads no row, and the census's name match over the inactive file is kept clear of tracked field names (E2ECandidate.Type, not Kind). internal/host/e2e_bridge.go gains a per-box published address, the box edge's hold subscription (renewed at every agent restart), an opt-in alias pass in each tick (domains.ReconcileAliases, already accepted legacy, over the deployment route fold the witness hands in, so the bridge adds no edges-file read site to internal/edgesfile's audit) and a pair-less publication through the same writer (publishErr with lifetimes off): no unit with a read site moves. The internal/edge and internal/host envelopes are re-pinned; no root read, class or task is added, and the seal is unchanged.
+# Task 7 review round 1, rev3=PROPOSED-self-serve-moves-3: rank.go gains holdLive (a remote hold is believed while it is less than holdingValidity old), used by rank and by the e2e seam's Live, so the two cannot disagree on the boundary. rank.go reads no row and is no census unit; no unit moves and the seal is unchanged. The internal/edge envelope is re-pinned.
@legacy 652c416a0cd27a153fa259d76ab20538480e2c3afd98cbec6af083902b17f5ff internal/domains/aliases.go ReconcileAliases legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-3;basis=root-route; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), from its fast-converge and instances loops: self-serve moves 1's body (rev3=J1, the catch-all's labels counted through domains.InstanceLabelCountsJudged), which now writes each alias row's provenance: an exact claim on the row's own name upserts it explicit (every pass, so a legacy row is upgraded on the first), and the synthetic "*.<host>" catch-all row not explicit; registry read sites unchanged, offsets moved; a report the edges file lists holding aliases by, not a decision registry:Account@15605,registry:Account@15618,registry:Alias@15220,registry:Alias@15260,registry:Alias@15330,registry:App@12165,registry:App@12365,registry:App@12521,registry:App@12722,registry:App@15631,registry:App@15640,registry:App@2026,registry:App@2222,registry:App@6036,registry:App@6235,registry:Host@15590,registry:Host@15879,registry:Host@15932,registry:Host@16004,registry:Host@16516,registry:Host@16608,registry:Host@16667,registry:Host@16748,registry:Host@406,registry:Prefix@16524,registry:Prefix@16622,registry:Prefix@16675,registry:Prefix@16756,registry:Status@8899,whole:Route@12134,whole:Route@12209,whole:Route@12356,whole:Route@12418,whole:Route@12561,whole:Route@12717,whole:Route@13613,whole:Route@1369,whole:Route@14825,whole:Route@14833,whole:Route@2066,whole:Route@2217,whole:Route@2273,whole:Route@359,whole:Route@388,whole:Route@399,whole:Route@417,whole:Route@5382,whole:Route@6080,whole:Route@6226,whole:Route@8229,whole:Route@8681,whole:Route@8843,whole:RouteAlias@14841,whole:RouteAlias@15195,whole:RoutePath@10426,whole:RoutePath@16409,whole:RoutePath@16451,whole:RoutePath@16565,whole:RoutePath@16595,whole:WildcardDomain@12933,whole:WildcardDomain@15520,whole:WildcardDomain@15569,whole:WildcardDomain@15732,whole:WildcardDomain@15838,whole:WildcardDomain@15867 edef8a1bf06cab5666a52ec19840c54f02913ddc67a32da7f6197db1606556a4
internal/domains/aliases.go ReconcileAliases legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-3;basis=root-route; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos), from its fast-converge and instances loops: self-serve moves 1's body (rev3=J1, the catch-all's labels counted through domains.InstanceLabelCountsJudged), which now writes each alias row's provenance: an exact claim on the row's own name upserts it explicit (every pass, so a legacy row is upgraded on the first), and the synthetic "*.<host>" catch-all row not explicit; registry read sites unchanged, offsets moved; a report the edges file lists holding aliases by, not a decision registry:Account@15605,registry:Account@15618,registry:Alias@15220,registry:Alias@15260,registry:Alias@15330,registry:App@12165,registry:App@12365,registry:App@12521,registry:App@12722,registry:App@15631,registry:App@15640,registry:App@2026,registry:App@2222,registry:App@6036,registry:App@6235,registry:Host@15590,registry:Host@15879,registry:Host@15932,registry:Host@16004,registry:Host@16516,registry:Host@16608,registry:Host@16667,registry:Host@16748,registry:Host@406,registry:Prefix@16524,registry:Prefix@16622,registry:Prefix@16675,registry:Prefix@16756,registry:Status@8899,whole:Route@12134,whole:Route@12209,whole:Route@12356,whole:Route@12418,whole:Route@12561,whole:Route@12717,whole:Route@13613,whole:Route@1369,whole:Route@14825,whole:Route@14833,whole:Route@2066,whole:Route@2217,whole:Route@2273,whole:Route@359,whole:Route@388,whole:Route@399,whole:Route@417,whole:Route@5382,whole:Route@6080,whole:Route@6226,whole:Route@8229,whole:Route@8681,whole:Route@8843,whole:RouteAlias@14841,whole:RouteAlias@15195,whole:RoutePath@10426,whole:RoutePath@16409,whole:RoutePath@16451,whole:RoutePath@16565,whole:RoutePath@16595,whole:WildcardDomain@12933,whole:WildcardDomain@15520,whole:WildcardDomain@15569,whole:WildcardDomain@15732,whole:WildcardDomain@15838,whole:WildcardDomain@15867 edef8a1bf06cab5666a52ec19840c54f02913ddc67a32da7f6197db1606556a4
@legacy 887eab39c9584891268b9afedcd81c995849a97545258b3eacc506b5c0165b23 internal/domains/aliases.go deriveInstanceAliases legacy accepted-legacy accepted-legacy;rev3=PROPOSED-self-serve-moves-3;basis=root-route; the agent (/opt/carlos/carlos agent, carlos-edge.service, user carlos): self-serve moves 1's body, whose already-the-row-we-want skip now also compares the existing row's provenance (registry:Explicit, one new site): a derived name left explicit by a detached exact claim on the same target and owner is rewritten not explicit, and both keep-as-it-is paths (a listing failure, an unjudged label) hand the kept row to keepDerived; the other registry read sites unchanged, offsets moved; no new route registry:Account@2163,registry:Account@3516,registry:Account@4587,registry:Alias@2225,registry:Alias@2293,registry:Alias@2337,registry:Alias@557,registry:App@1686,registry:App@2189,registry:App@3542,registry:App@4613,registry:Explicit@4632,registry:Host@1843,registry:Host@4566,registry:Host@4576,registry:Host@4787,registry:Provisioned@1636,registry:Replica@1672,registry:Slug@1775,whole:Route@1620,whole:Route@1726,whole:Route@3058,whole:RouteAlias@2143,whole:RouteAlias@2377,whole:RouteAlias@3498,whole:RouteAlias@3867,whole:RouteAlias@4548,whole:RouteAlias@509,whole:RouteAlias@539,whole:RouteAlias@552,whole:RouteAlias@568 42d5a40cccb38c31f306b49c00fde7482e4ee0b3cbf6a6a2dfbaac06592ef883
@@ -47,7 +48,7 @@ internal/console/selfserve_health.go Server.probeTarget legacy accepted-legacy a
@fields A,Account,Accounts,AddedAt,Addr,Addrs,Alias,Aliases,Alive,AllowAbsent,App,Archives,Args,At,Attempts,B,Backing,Bucket,BuildState,Callback,CallbackError,CallbackFailed,Canary,Caps,CertExpiresAt,Changed,Channel,CheckedAt,ClaimIncarnation,ClaimOwner,ClaimOwnership,ClaimRowID,ClaimStamp,Class,Contents,CreatedAt,DBPath,DNSCheckedAt,DNSStatus,Deadline,Demand,Digest,DoneBefore,Due,DueAt,Env,EnvBefore,Environment,Error,ErrorKind,ExcludeHosts,ExpectGood,ExpectOp,ExpectPair,Expected,Explicit,F,Failed,FenceGen,Fleet,FleetBox,FleetBoxes,Fleets,From,FromDB,FromOp,FromSock,Gate,GoodDemand,GoodDigest,GoodVersion,Hash,Health,Held,Hibernate,HoldOp,Host,Hosts,ID,Id,IdValue,Idle,IdleSeconds,ImportGate,Incarnation,Journal,Keep,Kind,Label,LastAt,LastError,LastMs,LastStatus,Limit,MaxRun,MaxRunSeconds,Method,Ms,Name,Next,NextAt,NextDue,NextGood,NextValue,Now,Number,Number64,Observed,ObservedValue,Old,On,Op,Original,Owner,Ownership,P,Pair,Path,Paths,Platform,Pool,Prefix,Prev,PrevVersion,Provisioned,RecordKey,Region,Registration,Replica,Replicas,Replication,Retirement,Route,Routes,Row,Rows,Seed,SeedID,SeedSource,ServingSeq,ServingVersion,Slug,Socket,Spec,Sqid,State,Status,StatusNamed,Steering,StringMap,T,TValue,Tags,Target,Targets,Text,Timer,Timers,Times,To,ToDB,ToOp,ToSock,TokenHash,Tunnel,Unit,UpdateSettings,Ver,Version,W,WakeIncarnation,Wildcards,closed,conn,connect,ctx,d,dec,done,enc,full,input,mu,output,path,remote,sql,wait
@coverage internal/console bc88b0e12e2a48b9a22951b01cf4e10f65e475079bce2a6cf076942ac1808ef6
@coverage internal/domains 0cf7748c97e4caa7d0daa73e251fdd2f2f03e425321599bf046292b0a86ebde8
-@coverage internal/edge 9da3d71f792b907f50fb8a8c57384ede585bf652ec82e9631741916272753efd
+@coverage internal/edge 26e86fdbe8c1d78bb0c6e3a1268694d77ccc72f08fee93b1f26c0a06636f20d7
@coverage internal/edgesfile ee82e43c7d6363297f63abcde9c3e828a53d377573649f0d26a9853056aad4be
@coverage internal/host 30ad675ecba1fc67bc34028c91c4da4e8b83ffa730f6e172fdd73ab7f7fa40f9
@coverage internal/registry ae19eaec5c4dde2c400fcb2fc6afd23c6b129e77306d6916fe55b2091b0fb5ed