carlos / platform Public

edge: the ranking pinned by witnesses, a differential test against the fold and a small-model property test

Plan 3 Task 3. alias_test.go: the moving instance's stale alias loses to
its hold while a legacy alias wins (Review Focus 3), a repointed alias is
B's in all six orders fresh and retained and falls to another target's
derived entry when detached, a holding alias never beats a ready of
another target, a stamped ready is never suppressed. rank_property_test.go:
invariants (a)-(n) over every admissible set of the 72-candidate model
(504,206 sets), the holding-only sorted fold in every input order (148,980
sets), the local ready's suppressibility, and Edge.resolve against today's
local-first-then-foldHomes dispatch over 415,872 no-live-hold resolutions.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev b7dce7becd670202cb786887eda388f5af01d297 parent e239b8a
2 files changed, +1071 −8
  • internal/edge/alias_test.go +169 −8
  • internal/edge/rank_property_test.go +902 −0
diff --git a/internal/edge/alias_test.go b/internal/edge/alias_test.go
index 6d450f2b2..6ab4d9c7f 100644
--- a/internal/edge/alias_test.go
+++ b/internal/edge/alias_test.go
@@ -1,11 +1,13 @@
package edge
import (
+ "fmt"
"maps"
"net/http"
"net/http/httptest"
"slices"
"testing"
+ "time"
"github.com/carlosframework/platform/internal/registry"
)
@@ -611,16 +613,16 @@ func lhold(target string, alias bool, inc, seq uint64, move string) candidate {
hold: &holdingView{Host: target, Account: "bab", App: "shop", MoveID: move, Incarnation: inc, ServingSeq: seq}}
}
-// permutations is every order of cs (cs is small).
-func permutations(cs []candidate) [][]candidate {
- if len(cs) <= 1 {
- return [][]candidate{slices.Clone(cs)}
+// permutations is every order of xs (xs is small).
+func permutations[T any](xs []T) [][]T {
+ if len(xs) <= 1 {
+ return [][]T{slices.Clone(xs)}
}
- var out [][]candidate
- for i := range cs {
- rest := append(slices.Clone(cs[:i]), cs[i+1:]...)
+ var out [][]T
+ for i := range xs {
+ rest := append(slices.Clone(xs[:i]), xs[i+1:]...)
for _, p := range permutations(rest) {
- out = append(out, append([]candidate{cs[i]}, p...))
+ out = append(out, append([]T{xs[i]}, p...))
}
}
return out
@@ -660,3 +662,162 @@ func TestTwoHoldsForOneAlias(t *testing.T) {
})
}
}
+
+// publisher is one other box's edges file for the alias witnesses, fetched
+// at fetched.
+type publisher struct {
+ box string
+ hosts map[string]edgesHostView
+ moves []holdingView
+ fetched time.Time
+}
+
+// rankPublished ranks name over pubs published in that order (the first is
+// the first file key in sorted order), through buildCandidates' real
+// admission, as an edge labelled zed sees them at rankNow.
+func rankPublished(name string, pubs []publisher) decision {
+ files := map[string]edgesFileView{}
+ for i, p := range pubs {
+ f := file(p.box, p.box+"-ip", p.hosts)
+ f.OfflineMoves, f.fetchedAt = p.moves, p.fetched
+ files[fmt.Sprintf("control/edges/%d-%s.json", i, p.box)] = f
+ }
+ return rank(name, buildCandidates(files, "zed", false)[name], rankNow)
+}
+
+// retained is a fetch time a carried-forward parse keeps: ready entries are
+// believed however old their file is; only holds expire.
+var retained = rankNow.Add(-10 * time.Minute)
+
+// aliasTo is a ready alias publication of rankAlias pointing at target ("" a
+// legacy publication that names none).
+func aliasTo(target string, inc, seq uint64, stamp int64) map[string]edgesHostView {
+ return map[string]edgesHostView{rankAlias: {Role: "home", Alias: true, TargetHost: target, Incarnation: inc, ServingSeq: seq, Stamp: stamp}}
+}
+
+// heldWith is the source box's holding entry for rankHost at (inc, seq),
+// listing aliases.
+func heldWith(move string, inc, seq uint64, aliases ...string) []holdingView {
+ return []holdingView{{Host: rankHost, Account: "bab", App: "shop", Aliases: aliases, MoveID: move, Incarnation: inc, ServingSeq: seq}}
+}
+
+// TestAliasOfTheMovingInstanceLosesToItsHold is Review Focus 3. The moving
+// instance's stale ready alias publication (its pair lower than the hold's)
+// is suppressed by the hold, which then answers the alias with the page, in
+// either file order and whether the stale file is fresh or retained. A
+// legacy alias publication naming no target_host is a different target: no
+// hold reaches it, so it wins, alone or beside the suppressed stale one, in
+// every order.
+func TestAliasOfTheMovingInstanceLosesToItsHold(t *testing.T) {
+ for _, staleAt := range []time.Time{rankNow, retained} {
+ stale := publisher{box: "annie", hosts: aliasTo(rankHost, 1, 0, 0), fetched: staleAt}
+ source := publisher{box: "betty", moves: heldWith("mv_betty", 1, 1, rankAlias), fetched: rankNow}
+ for _, p := range permutations([]publisher{stale, source}) {
+ wantHolding(t, rankPublished(rankAlias, p), "mv_betty", "the moving instance's stale alias loses to its hold")
+ wantHolding(t, rankPublished(rankHost, p), "mv_betty", "the hold answers its own host too")
+ }
+ legacy := publisher{box: "carol", hosts: aliasTo("", 1, 0, 0), fetched: staleAt}
+ for _, p := range permutations([]publisher{legacy, source}) {
+ wantRemote(t, rankPublished(rankAlias, p), "carol", "a legacy alias publication is a different target")
+ }
+ for _, p := range permutations([]publisher{stale, legacy, source}) {
+ wantRemote(t, rankPublished(rankAlias, p), "carol", "the stale alias is suppressed and the legacy one survives")
+ }
+ }
+}
+
+// TestAliasRepointedDuringAMove: the alias was the moving instance A's and
+// is now B's (otherHost). A's stale ready alias publication and A's hold,
+// still listing the alias, carry pairs higher than B's and unrelated to
+// them; B's publication wins in all six file orders, whether the ready
+// files are fresh or retained: A's stale one is suppressed by A's hold, and
+// a surviving ready of a target no hold names beats every hold. Detached
+// (the hold lists the alias no longer, or a fresh hold still does) and
+// derived for another target, the alias falls to that target's derived,
+// pairless entry.
+func TestAliasRepointedDuringAMove(t *testing.T) {
+ for _, staleAt := range []time.Time{rankNow, retained} {
+ for _, bAt := range []time.Time{rankNow, retained} {
+ stale := publisher{box: "annie", hosts: aliasTo(rankHost, 2, 0, 0), fetched: staleAt}
+ source := publisher{box: "betty", moves: heldWith("mv_betty", 2, 1, rankAlias), fetched: rankNow}
+ b := publisher{box: "carol", hosts: aliasTo(otherHost, 1, 0, 0), fetched: bAt}
+ orders := permutations([]publisher{stale, source, b})
+ if len(orders) != 6 {
+ t.Fatalf("%d orders, want 6", len(orders))
+ }
+ for _, p := range orders {
+ wantRemote(t, rankPublished(rankAlias, p), "carol", "the repointed alias is B's in every order")
+ }
+ }
+ }
+ for _, at := range []time.Time{rankNow, retained} {
+ derived := publisher{box: "carol", hosts: aliasTo(otherHost, 0, 0, 0), fetched: at}
+ for _, source := range []publisher{
+ {box: "betty", moves: heldWith("mv_betty", 2, 1), fetched: rankNow},
+ {box: "betty", moves: heldWith("mv_betty", 2, 1, rankAlias), fetched: rankNow},
+ } {
+ for _, p := range permutations([]publisher{source, derived}) {
+ wantRemote(t, rankPublished(rankAlias, p), "carol", "detached, the alias falls to the other target's derived entry")
+ }
+ }
+ }
+}
+
+// TestHoldingAliasNeverBeatsAReadyRouteOfAnotherTarget: a holding alias of
+// the moving instance, at any pair, never takes the alias from a ready
+// candidate of another target (a real route of the name itself, an alias
+// of another instance, a legacy alias naming none, this box's own), stamped
+// or not and at the lowest pair, in either order.
+func TestHoldingAliasNeverBeatsAReadyRouteOfAnotherTarget(t *testing.T) {
+ up := &upstream{}
+ readies := []candidate{
+ rready(0, "annie", rankAlias, false, 0, 0, 0),
+ rready(0, "annie", otherHost, true, 0, 0, 0),
+ rready(0, "annie", "", true, 0, 0, 0),
+ rready(0, "annie", otherHost, true, 0, 0, 3),
+ rready(2, "annie", rankAlias, false, 0, 0, 0),
+ {kind: candReady, local: true, order: -1, targetHost: rankAlias, up: up},
+ {kind: candReady, local: true, order: -1, alias: true, targetHost: otherHost, up: up},
+ }
+ for _, hold := range []candidate{rhold(1, "betty", rankHost, true, 9, 9), lhold(rankHost, true, 9, 9, "mv_local")} {
+ for _, r := range readies {
+ for _, p := range permutations([]candidate{hold, r}) {
+ d := rank(rankAlias, p, rankNow)
+ if r.local {
+ if d.kind != decLocal {
+ t.Fatalf("local ready %+v against hold = %v, want decLocal", r, d.kind)
+ }
+ continue
+ }
+ wantRemote(t, d, "annie", "a ready of another target beats the holding alias")
+ }
+ }
+ }
+}
+
+// TestStampedCandidateIsNeverSuppressed: a stamped ready candidate (a
+// claims-on box's publication; holds are never stamped) of the moving
+// target survives every hold of that target, real or alias, local or
+// remote, at any higher pair, even at (0, 0) itself, and then the ready
+// stage decides as the fold does: the stamp beats a surviving unstamped
+// ready of a higher pair.
+func TestStampedCandidateIsNeverSuppressed(t *testing.T) {
+ for _, alias := range []bool{false, true} {
+ stamped := rready(1, "annie", rankHost, alias, 0, 0, 4)
+ holds := []candidate{
+ rhold(0, "betty", rankHost, false, 2, 2), rhold(2, "carol", rankHost, true, 2, 2), lhold(rankHost, alias, 2, 2, "mv_local"),
+ }
+ for _, h := range holds {
+ for _, p := range permutations([]candidate{stamped, h}) {
+ wantRemote(t, rank(rankHost, p, rankNow), "annie", "a stamped ready is never suppressed")
+ }
+ }
+ for _, p := range permutations(append([]candidate{stamped}, holds...)) {
+ wantRemote(t, rank(rankHost, p, rankNow), "annie", "nor by every hold together")
+ }
+ newer := rready(3, "dora", rankHost, alias, 2, 2, 0)
+ for _, p := range permutations([]candidate{stamped, newer, holds[0]}) {
+ wantRemote(t, rank(rankHost, p, rankNow), "annie", "beside an equal-pair unstamped survivor, the stamp wins the fold")
+ }
+ }
+}
diff --git a/internal/edge/rank_property_test.go b/internal/edge/rank_property_test.go
new file mode 100644
index 000000000..07401bb3d
--- /dev/null
+++ b/internal/edge/rank_property_test.go
@@ -0,0 +1,902 @@
+package edge
+
+// The ranking over its small model (self-serve moves plan 3 Task 3, Review
+// Focus 2): every candidate set of up to four candidates, two targets,
+// pairs up to 2, stamps 0 or 1, fresh or expired holds, local or remote.
+//
+// The model, and what it leaves out on purpose:
+//
+// - The name is modelName. A real candidate (a route, a held row) is a
+// lifetime of the name itself, so its target is always modelName; an
+// alias candidate's target is its primary, modelPrimary, or "" for a
+// legacy ready alias publication that names none. Those are the two
+// targets. (A real candidate of another target cannot exist: a file
+// publishes a name once, and a held row's entry is keyed by its host.)
+// - Pairs are modelPairs, ascending: (1,0) < (1,1) < (2,0). The spec
+// below compares a pair's index, never the fields rank compares, so the
+// lexicographic order is pinned too ((1,1) is below (2,0) although its
+// serving_seq is higher).
+// - Remote candidates sit in one of two files (order 0 or 1); a file
+// publishes a name once, so it carries at most one ready candidate, and
+// the box has at most one table entry and one hold for the name.
+// - Only a remote ready candidate is ever stamped. Local ready candidates
+// always carry stamp 0 (localReady), so a hold CAN suppress this box's
+// own ready candidate, and invariant (b) never protects a claims-on
+// box's own stamped route locally. That is intended: local first makes
+// stamps moot on the box itself, and a claims-on box publishes no holds.
+// TestLocalReadyIsUnstamped pins it.
+// - Expiry is rank's alone here: a remote hold fetched 4 m 59 s ago is
+// fresh and one fetched 5 m ago is expired (the clock that sets
+// fetchedAt is Task 5's). A ready candidate is believed whatever its
+// file's age.
+// - The classes are fixed marks (platform on a real candidate in the
+// first file or local, wildcard on a ready candidate in the second), so
+// varying a pair never changes them.
+
+import (
+ "fmt"
+ "reflect"
+ "slices"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/carlosframework/platform/internal/registry"
+)
+
+var modelPairs = [][2]uint64{{1, 0}, {1, 1}, {2, 0}}
+
+const (
+ modelName = "x.example.com"
+ modelPrimary = "app.example.net"
+)
+
+// mc is one candidate of the small model.
+type mc struct {
+ kind candKind
+ local bool
+ order int
+ alias bool
+ target string
+ pair int
+ stamp int64
+ expired bool
+}
+
+func (m mc) String() string {
+ var b strings.Builder
+ if m.local {
+ b.WriteString("local ")
+ } else {
+ fmt.Fprintf(&b, "file%d ", m.order)
+ }
+ if m.kind == candHolding {
+ b.WriteString("hold ")
+ } else {
+ b.WriteString("ready ")
+ }
+ if m.alias {
+ fmt.Fprintf(&b, "alias->%q ", m.target)
+ } else {
+ b.WriteString("real ")
+ }
+ fmt.Fprintf(&b, "%v", modelPairs[m.pair])
+ if m.stamp != 0 {
+ fmt.Fprintf(&b, " stamp %d", m.stamp)
+ }
+ if m.expired {
+ b.WriteString(" expired")
+ }
+ return b.String()
+}
+
+// build is the candidate m stands for, the i-th of its set: its app names
+// it, so the winner of any decision is identifiable.
+func (m mc) build(i int) candidate {
+ c := candidate{kind: m.kind, local: m.local, order: m.order, alias: m.alias, targetHost: m.target,
+ incarnation: modelPairs[m.pair][0], servingSeq: modelPairs[m.pair][1], stamp: m.stamp,
+ account: "acct", app: fmt.Sprintf("c%d", i), fetchedAt: rankNow.Add(-holdingValidity + time.Second),
+ platform: !m.alias && m.order <= 0, wildcard: m.kind == candReady && m.order == 1}
+ if !m.local {
+ c.box = fmt.Sprintf("box%d", m.order)
+ c.eip = c.box + "-ip"
+ }
+ if m.expired {
+ c.fetchedAt = rankNow.Add(-holdingValidity)
+ }
+ switch {
+ case m.kind == candHolding:
+ c.hold = &holdingView{Host: m.target, Account: c.account, App: c.app, MoveID: "mv_" + c.app,
+ Incarnation: c.incarnation, ServingSeq: c.servingSeq}
+ case m.local:
+ up := upstream{alias: m.alias, route: registry.Route{Host: m.target, App: c.app}}
+ c.up = &up
+ c.table = map[string]upstream{modelName: up}
+ }
+ return c
+}
+
+func (m mc) live() bool { return !(m.kind == candHolding && !m.local && m.expired) }
+
+// modelAlphabet is every candidate of the model: 72 of them.
+func modelAlphabet() []mc {
+ var out []mc
+ for p := range modelPairs {
+ out = append(out,
+ mc{kind: candReady, local: true, order: -1, target: modelName, pair: p},
+ mc{kind: candReady, local: true, order: -1, alias: true, target: modelPrimary, pair: p},
+ mc{kind: candHolding, local: true, order: -1, target: modelName, pair: p},
+ mc{kind: candHolding, local: true, order: -1, alias: true, target: modelPrimary, pair: p})
+ for order := 0; order < 2; order++ {
+ for stamp := int64(0); stamp < 2; stamp++ {
+ out = append(out,
+ mc{kind: candReady, order: order, target: modelName, pair: p, stamp: stamp},
+ mc{kind: candReady, order: order, alias: true, target: modelPrimary, pair: p, stamp: stamp},
+ mc{kind: candReady, order: order, alias: true, target: "", pair: p, stamp: stamp})
+ }
+ for _, expired := range []bool{false, true} {
+ out = append(out,
+ mc{kind: candHolding, order: order, target: modelName, pair: p, expired: expired},
+ mc{kind: candHolding, order: order, alias: true, target: modelPrimary, pair: p, expired: expired})
+ }
+ }
+ }
+ return out
+}
+
+// admissible is the model's shape rule: at most one table entry and one
+// hold of this box's own, and at most one ready candidate per file.
+func admissible(set []mc) bool {
+ localReady, localHold := 0, 0
+ readyIn := map[int]int{}
+ for _, m := range set {
+ switch {
+ case m.local && m.kind == candReady:
+ localReady++
+ case m.local:
+ localHold++
+ case m.kind == candReady:
+ readyIn[m.order]++
+ }
+ }
+ if localReady > 1 || localHold > 1 {
+ return false
+ }
+ for _, n := range readyIn {
+ if n > 1 {
+ return false
+ }
+ }
+ return true
+}
+
+// eachSubset calls fn with every subset of alphabet of 1 to max members,
+// in alphabet order.
+func eachSubset(alphabet []mc, max int, fn func([]mc)) {
+ var set []mc
+ var rec func(start int)
+ rec = func(start int) {
+ if len(set) > 0 {
+ fn(set)
+ }
+ if len(set) == max {
+ return
+ }
+ for i := start; i < len(alphabet); i++ {
+ set = append(set, alphabet[i])
+ rec(i + 1)
+ set = set[:len(set)-1]
+ }
+ }
+ rec(0)
+}
+
+func buildSet(set []mc) []candidate {
+ cs := make([]candidate, len(set))
+ for i, m := range set {
+ cs[i] = m.build(i)
+ }
+ return cs
+}
+
+// tablePtr is a table's identity.
+func tablePtr(m map[string]upstream) uintptr { return reflect.ValueOf(m).Pointer() }
+
+// sameDecision compares two decisions whole: the winner by identity (the
+// upstream, the table, the hold) and every field the request path reads.
+func sameDecision(a, b decision) bool {
+ return a.kind == b.kind && a.up == b.up && tablePtr(a.table) == tablePtr(b.table) && a.hold == b.hold &&
+ a.eip == b.eip && a.box == b.box && a.account == b.account && a.app == b.app && a.stamp == b.stamp &&
+ a.platform == b.platform && a.wildcard == b.wildcard
+}
+
+// sameWinner is sameDecision without the classes.
+func sameWinner(a, b decision) bool {
+ a.platform, a.wildcard, b.platform, b.wildcard = false, false, false, false
+ return sameDecision(a, b)
+}
+
+func describe(set []mc) string {
+ parts := make([]string, len(set))
+ for i, m := range set {
+ parts[i] = fmt.Sprintf("[%d] %v", i, m)
+ }
+ return strings.Join(parts, "; ")
+}
+
+func describeDecision(d decision) string {
+ switch d.kind {
+ case decLocal:
+ return "local " + d.up.route.App
+ case decRemote:
+ return fmt.Sprintf("remote %s at %s", d.app, d.box)
+ case decHolding:
+ return "holding " + d.hold.App
+ }
+ return "none"
+}
+
+// specSuppressed is invariant (d) and (b) as the plan states them: a live
+// hold removes exactly the unstamped ready candidates sharing its
+// non-empty target with a lower pair.
+func specSuppressed(set []mc, i int) bool {
+ c := set[i]
+ if c.kind != candReady || c.target == "" || c.stamp != 0 {
+ return false
+ }
+ for _, h := range set {
+ if h.kind == candHolding && h.live() && h.target == c.target && c.pair < h.pair {
+ return true
+ }
+ }
+ return false
+}
+
+// specHoldWinner is the holding fold's answer stated without folding
+// (invariant (n)): a real hold if there is any, else an alias; of that
+// kind, the target of the first by (order, target); of that kind and
+// target, the highest pair, the first on a tie. -1 when no hold is live.
+func specHoldWinner(set []mc) int {
+ anyReal := false
+ for _, h := range set {
+ if h.kind == candHolding && h.live() && !h.alias {
+ anyReal = true
+ }
+ }
+ first := -1
+ for i, h := range set {
+ if h.kind != candHolding || !h.live() || h.alias == anyReal {
+ continue
+ }
+ if first < 0 || h.order < set[first].order || (h.order == set[first].order && h.target < set[first].target) {
+ first = i
+ }
+ }
+ if first < 0 {
+ return -1
+ }
+ win := first
+ for i, h := range set {
+ if h.kind != candHolding || !h.live() || h.alias == anyReal || h.target != set[first].target {
+ continue
+ }
+ w := set[win]
+ if h.pair > w.pair || (h.pair == w.pair && h.order < w.order) {
+ win = i
+ }
+ }
+ return win
+}
+
+// foldOracle is foldHomes over the remote ready candidates idx of set,
+// each published in its own file: the winning candidate's index, or -1.
+func foldOracle(set []mc, cs []candidate, idx []int) int {
+ files := map[string]edgesFileView{}
+ for _, i := range idx {
+ c := cs[i]
+ h := edgesHostView{Role: edgeRoleHome, Alias: c.alias, Platform: c.platform, Wildcard: c.wildcard,
+ Account: c.account, App: c.app, Stamp: c.stamp, Incarnation: c.incarnation, ServingSeq: c.servingSeq}
+ if c.alias {
+ h.TargetHost = c.targetHost
+ }
+ files[fmt.Sprintf("control/edges/%d.json", set[i].order)] = file(c.box, c.eip, map[string]edgesHostView{modelName: h})
+ }
+ hosts, _ := foldHomes(files, "zed", false)
+ w, ok := hosts[modelName]
+ if !ok || !w.dial {
+ return -1
+ }
+ for _, i := range idx {
+ if cs[i].app == w.app {
+ return i
+ }
+ }
+ return -1
+}
+
+// TestRankingProperties runs every candidate set of the small model
+// through rank and asserts the scoped invariants: (f) an expired remote
+// hold neither suppresses nor decides (the answer is the one without it);
+// (d) and (b) suppression removes exactly the spec's candidates, never a
+// stamped one; (l) a surviving local ready candidate wins; (a) the remote
+// survivors are decided by foldHomes; (h) a real survivor beats an alias
+// one; (c) and (e) any ready survivor beats every hold; (n) the holding
+// winner is the sorted fold's and the decision is the same in reverse and
+// rotated input order; (g) a candidate whose target no other live
+// candidate shares (or is empty) decides the same at every pair; (j) the
+// classes are OR'd over the live candidates and everything else is the
+// winner's, and an alias candidate never contributes platform.
+func TestRankingProperties(t *testing.T) {
+ alphabet := modelAlphabet()
+ if len(alphabet) != 72 {
+ t.Fatalf("alphabet = %d candidates, want 72", len(alphabet))
+ }
+ sets, failures := 0, 0
+ fail := func(set []mc, format string, args ...any) {
+ t.Helper()
+ failures++
+ t.Errorf("%s\n set: %s", fmt.Sprintf(format, args...), describe(set))
+ if failures >= 10 {
+ t.FailNow()
+ }
+ }
+ eachSubset(alphabet, 4, func(set []mc) {
+ if !admissible(set) {
+ return
+ }
+ sets++
+ cs := buildSet(set)
+ d := rank(modelName, cs, rankNow)
+
+ // (f): the answer is the answer without the expired holds.
+ var liveCs []candidate
+ for i, m := range set {
+ if m.live() {
+ liveCs = append(liveCs, cs[i])
+ }
+ }
+ if dl := rank(modelName, liveCs, rankNow); !sameDecision(d, dl) {
+ fail(set, "(f) with the expired holds %s, without %s", describeDecision(d), describeDecision(dl))
+ }
+
+ // (j): classes OR'd over the live candidates.
+ platform, wildcard := false, false
+ for _, c := range liveCs {
+ if c.alias && c.platform {
+ fail(set, "(j) model fixture: an alias carries platform")
+ }
+ platform = platform || c.platform
+ wildcard = wildcard || c.wildcard
+ }
+ if d.platform != platform || d.wildcard != wildcard {
+ fail(set, "(j) classes platform %v wildcard %v, want %v %v", d.platform, d.wildcard, platform, wildcard)
+ }
+
+ // The spec's survivors.
+ localWin := -1
+ var remote []int
+ anyReady, anyStamped := false, false
+ for i, m := range set {
+ if m.kind != candReady {
+ continue
+ }
+ anyReady = true
+ if m.stamp != 0 {
+ anyStamped = true
+ if specSuppressed(set, i) {
+ fail(set, "(b) spec: a stamped candidate suppressed")
+ }
+ }
+ if specSuppressed(set, i) {
+ continue
+ }
+ if m.local {
+ localWin = i
+ } else {
+ remote = append(remote, i)
+ }
+ }
+ holdWin := specHoldWinner(set)
+
+ switch {
+ case localWin >= 0:
+ // (l)
+ if d.kind != decLocal || d.up != cs[localWin].up || tablePtr(d.table) != tablePtr(cs[localWin].table) {
+ fail(set, "(l) decision %s, want local %s", describeDecision(d), cs[localWin].app)
+ }
+ case len(remote) > 0:
+ // (a), (c), (e), (h) and (j)'s owner.
+ w := foldOracle(set, cs, remote)
+ if w < 0 {
+ fail(set, "oracle: foldHomes found no dial target")
+ return
+ }
+ c := cs[w]
+ if d.kind != decRemote || d.app != c.app || d.box != c.box || d.eip != c.eip || d.account != c.account || d.stamp != c.stamp {
+ fail(set, "(a) decision %s, want foldHomes's %s at %s", describeDecision(d), c.app, c.box)
+ }
+ if d.up != nil || d.hold != nil || d.table != nil {
+ fail(set, "(j) a remote decision carries a local upstream or a hold")
+ }
+ for _, i := range remote {
+ if !set[i].alias && set[w].alias {
+ fail(set, "(h) an alias won over a real survivor")
+ }
+ }
+ case holdWin >= 0:
+ // (n)
+ if d.kind != decHolding || d.hold != cs[holdWin].hold {
+ fail(set, "(n) decision %s, want the sorted fold's %s", describeDecision(d), cs[holdWin].app)
+ }
+ if anyStamped {
+ fail(set, "(b) a stamped ready lost to a hold")
+ }
+ default:
+ if d.kind != decNone {
+ fail(set, "decision %s, want none: no live ready or hold", describeDecision(d))
+ }
+ if anyReady {
+ fail(set, "spec: a ready candidate and nothing decides")
+ }
+ }
+ if (localWin >= 0 || len(remote) > 0) && d.kind == decHolding {
+ fail(set, "(c)/(e) a hold beat a surviving ready candidate")
+ }
+
+ // (d): removing a suppressed candidate changes no winner.
+ for i := range set {
+ if !specSuppressed(set, i) {
+ continue
+ }
+ without := append(slices.Clone(cs[:i]), cs[i+1:]...)
+ if dw := rank(modelName, without, rankNow); !sameWinner(d, dw) {
+ fail(set, "(d) [%d] is suppressed, yet removing it moves the answer from %s to %s", i, describeDecision(d), describeDecision(dw))
+ }
+ }
+
+ // (g): a candidate of an unshared or empty target decides the same
+ // at every pair.
+ for i, m := range set {
+ if !m.live() {
+ continue
+ }
+ shared := false
+ for j, o := range set {
+ if j != i && o.live() && m.target != "" && o.target == m.target {
+ shared = true
+ }
+ }
+ if shared {
+ continue
+ }
+ for p := range modelPairs {
+ if p == m.pair {
+ continue
+ }
+ alt := slices.Clone(cs)
+ alt[i].incarnation, alt[i].servingSeq = modelPairs[p][0], modelPairs[p][1]
+ if da := rank(modelName, alt, rankNow); !sameDecision(d, da) {
+ fail(set, "(g) [%d] shares its target with nothing, yet at pair %v the answer is %s, not %s", i, modelPairs[p], describeDecision(da), describeDecision(d))
+ }
+ }
+ }
+
+ // (n): input order is not an input.
+ rev := slices.Clone(cs)
+ slices.Reverse(rev)
+ if dr := rank(modelName, rev, rankNow); !sameDecision(d, dr) {
+ fail(set, "(n) reversed input: %s, not %s", describeDecision(dr), describeDecision(d))
+ }
+ if len(cs) > 2 {
+ rot := append(slices.Clone(cs[1:]), cs[0])
+ if dr := rank(modelName, rot, rankNow); !sameDecision(d, dr) {
+ fail(set, "(n) rotated input: %s, not %s", describeDecision(dr), describeDecision(d))
+ }
+ }
+ })
+ t.Logf("%d candidate sets", sets)
+}
+
+// TestLocalReadyIsUnstamped: this box's own ready candidate is never
+// stamped (local first makes stamps moot on the box itself, and a
+// claims-on box publishes no holds), so a hold of its target with a higher
+// pair suppresses it like any stale publication, and the hold answers. At
+// an equal or higher pair it survives and wins over everything: a stamped
+// remote ready, a remote real route and every hold.
+func TestLocalReadyIsUnstamped(t *testing.T) {
+ local := func(inc, seq uint64) candidate {
+ up := &upstream{route: registry.Route{Host: rankHost, App: "local"}}
+ return candidate{kind: candReady, local: true, order: -1, targetHost: rankHost, incarnation: inc, servingSeq: seq,
+ up: up, table: map[string]upstream{rankHost: *up}}
+ }
+ hold := rhold(1, "betty", rankHost, false, 1, 1)
+ for _, p := range permutations([]candidate{local(1, 0), hold}) {
+ wantHolding(t, rank(rankHost, p, rankNow), "mv_betty", "a local ready of the moving target with a lower pair is suppressed")
+ }
+ for _, l := range []candidate{local(1, 1), local(1, 2), local(2, 0)} {
+ others := []candidate{l, hold, rready(0, "annie", rankHost, false, 0, 0, 9), rready(2, "carol", rankHost, false, 3, 3, 0),
+ lhold(rankHost, false, 1, 1, "mv_local")}
+ for _, p := range permutations(others) {
+ if d := rank(rankHost, p, rankNow); d.kind != decLocal || d.up != l.up {
+ t.Fatalf("local (%d,%d) against a stamped remote, a newer remote and two holds = %v, want decLocal", l.incarnation, l.servingSeq, d.kind)
+ }
+ }
+ }
+}
+
+// holdAlphabet is the holding-only model: holds alone, the real one of
+// modelName and alias ones of two primaries, local or in one of two files,
+// at the three pairs, fresh or (remote only) expired. 45 of them.
+func holdAlphabet() []mc {
+ var out []mc
+ targets := []struct {
+ alias bool
+ target string
+ }{{false, modelName}, {true, modelPrimary}, {true, "cart.example.org"}}
+ for p := range modelPairs {
+ for _, tg := range targets {
+ out = append(out, mc{kind: candHolding, local: true, order: -1, alias: tg.alias, target: tg.target, pair: p})
+ for order := 0; order < 2; order++ {
+ for _, expired := range []bool{false, true} {
+ out = append(out, mc{kind: candHolding, order: order, alias: tg.alias, target: tg.target, pair: p, expired: expired})
+ }
+ }
+ }
+ }
+ return out
+}
+
+// eachPermutation calls fn with every order of cs (Heap's algorithm, over
+// one copy permuted in place) until fn returns false.
+func eachPermutation(cs []candidate, fn func([]candidate) bool) {
+ a := slices.Clone(cs)
+ c := make([]int, len(a))
+ if !fn(a) {
+ return
+ }
+ for i := 0; i < len(a); {
+ if c[i] < i {
+ if i%2 == 0 {
+ a[0], a[i] = a[i], a[0]
+ } else {
+ a[c[i]], a[i] = a[i], a[c[i]]
+ }
+ if !fn(a) {
+ return
+ }
+ c[i]++
+ i = 0
+ } else {
+ c[i] = 0
+ i++
+ }
+ }
+}
+
+// TestHoldingSortedFold: every holding-only set of the model (at most one
+// local real hold and one local alias hold) answers the hold the sorted
+// fold names (specHoldWinner: a real hold before an alias, the first by
+// order then target, the highest pair of that target), in every one of its
+// input orders. Two alias holds of different targets in one file are
+// ordered by target (rank's sort), so the page never depends on the order
+// the candidates were collected in.
+func TestHoldingSortedFold(t *testing.T) {
+ alphabet := holdAlphabet()
+ if len(alphabet) != 45 {
+ t.Fatalf("alphabet = %d holds, want 45", len(alphabet))
+ }
+ sets, failures := 0, 0
+ eachSubset(alphabet, 4, func(set []mc) {
+ realLocal, aliasLocal := 0, 0
+ for _, m := range set {
+ if m.local && m.alias {
+ aliasLocal++
+ } else if m.local {
+ realLocal++
+ }
+ }
+ if realLocal > 1 || aliasLocal > 1 {
+ return
+ }
+ sets++
+ cs := buildSet(set)
+ win := specHoldWinner(set)
+ eachPermutation(cs, func(p []candidate) bool {
+ d := rank(modelName, p, rankNow)
+ if (win < 0 && d.kind == decNone) || (win >= 0 && d.kind == decHolding && d.hold == cs[win].hold) {
+ return true
+ }
+ want := "none"
+ if win >= 0 {
+ want = cs[win].app
+ }
+ failures++
+ t.Errorf("decision %s, want %s\n set: %s", describeDecision(d), want, describe(set))
+ if failures >= 10 {
+ t.FailNow()
+ }
+ return false
+ })
+ })
+ t.Logf("%d holding sets", sets)
+}
+
+// The no-hold differential (invariant (a), Review Focus 2): with no live
+// hold, the plan 3 request resolution (Edge.resolve over the table and
+// buildCandidates' output, through rank) answers what today's ServeHTTP
+// dispatch answered, which was local first, then foldHomes:
+//
+// - an exact table entry for the host is served locally;
+// - a table entry only through the host's "*.<parent>" key loses to
+// another box's exact dial target (ExactHome), which an ordinary
+// request backhauls to and a hop or a door request does not (they keep
+// the local catch-all: the decision's fallback); with none, the local
+// catch-all serves;
+// - with nothing local, the folded exact entry, else the folded catch-all
+// entry, is dialled (Home);
+// - an unlabelled box offers no remote answer at all.
+//
+// diffHost is the request host and diffKey its catch-all key.
+const (
+ diffHost = "x.example.com"
+ diffKey = "*.example.com"
+)
+
+// diffWant is today's answer: local names the table key served; remote is
+// the folded entry dialled, with fallback when the local catch-all travels
+// with it.
+type diffWant struct {
+ local string
+ remote *homeEntry
+ fallback bool
+}
+
+func todaysDispatch(table map[string]upstream, files map[string]edgesFileView, self string) diffWant {
+ hosts, _ := foldHomes(files, self, false)
+ dial := func(name string) (homeEntry, bool) {
+ h, ok := hosts[name]
+ return h, ok && h.dial && self != ""
+ }
+ if _, ok := table[diffHost]; ok {
+ return diffWant{local: diffHost}
+ }
+ if _, ok := table[diffKey]; ok {
+ if h, ok := dial(diffHost); ok {
+ return diffWant{remote: &h, fallback: true}
+ }
+ return diffWant{local: diffKey}
+ }
+ if h, ok := dial(diffHost); ok {
+ return diffWant{remote: &h}
+ }
+ if h, ok := dial(diffKey); ok {
+ return diffWant{remote: &h}
+ }
+ return diffWant{}
+}
+
+// diffHostEntry is one file's publication of diffHost: none, a real route
+// or an alias (of modelPrimary, or naming no target), at each pair,
+// stamped or not; the real one in the first file carries platform.
+func diffHostEntries(first bool) []*edgesHostView {
+ out := []*edgesHostView{nil}
+ for p, pair := range modelPairs {
+ for stamp := int64(0); stamp < 2; stamp++ {
+ out = append(out,
+ &edgesHostView{Role: edgeRoleHome, Platform: first, Incarnation: pair[0], ServingSeq: pair[1], Stamp: stamp, App: fmt.Sprintf("real%d%d", p, stamp)},
+ &edgesHostView{Role: edgeRoleHome, Alias: true, TargetHost: modelPrimary, Incarnation: pair[0], ServingSeq: pair[1], Stamp: stamp, App: fmt.Sprintf("alias%d%d", p, stamp)},
+ &edgesHostView{Role: edgeRoleHome, Alias: true, Incarnation: pair[0], ServingSeq: pair[1], Stamp: stamp, App: fmt.Sprintf("legacy%d%d", p, stamp)})
+ }
+ }
+ return out
+}
+
+// diffKeyEntries is one file's publication of diffKey: none, a dialled
+// catch-all at two pairs, or the certificate-only role.
+var diffKeyEntries = []*edgesHostView{
+ nil,
+ {Role: edgeRoleHome, Wildcard: true, Incarnation: 1, App: "wild10"},
+ {Role: edgeRoleHome, Wildcard: true, Incarnation: 1, ServingSeq: 1, App: "wild11"},
+ {Role: edgeRoleWildcard, Wildcard: true},
+}
+
+// diffFile is one other box's file: its diffHost and diffKey entries and,
+// when retained, an expired hold of diffHost at a pair above every ready
+// one (it would suppress all of them if it were live) in a file fetched
+// five minutes ago.
+func diffFile(box string, host, key *edgesHostView, retained bool) edgesFileView {
+ hosts := map[string]edgesHostView{}
+ if host != nil {
+ h := *host
+ h.Account = "acct"
+ h.App = box + "-" + h.App
+ hosts[diffHost] = h
+ }
+ if key != nil {
+ k := *key
+ if k.App != "" {
+ k.Account, k.App = "acct", box+"-"+k.App
+ }
+ hosts[diffKey] = k
+ }
+ f := file(box, box+"-ip", hosts)
+ f.fetchedAt = rankNow
+ if retained {
+ f.fetchedAt = rankNow.Add(-holdingValidity)
+ f.OfflineMoves = []holdingView{{Host: diffHost, Account: "acct", App: box + "-held", MoveID: "mv_" + box, Incarnation: 9, ServingSeq: 9}}
+ }
+ return f
+}
+
+// diffTables is every table: no entry, an exact real route, an exact alias,
+// each with and without the local catch-all.
+func diffTables() []map[string]upstream {
+ exact := []*upstream{nil,
+ {route: registry.Route{Host: diffHost, App: "local-exact"}},
+ {alias: true, route: registry.Route{Host: modelPrimary, App: "local-alias"}}}
+ var out []map[string]upstream
+ for _, x := range exact {
+ for _, wild := range []bool{false, true} {
+ table := map[string]upstream{}
+ if x != nil {
+ table[diffHost] = *x
+ }
+ if wild {
+ table[diffKey] = upstream{alias: true, route: registry.Route{Host: "parent.example.com", App: "local-wild"}}
+ }
+ out = append(out, table)
+ }
+ }
+ return out
+}
+
+// resolveOn is Edge.resolve on an edge labelled self with table and the
+// home map's candidates built from files.
+func resolveOn(table map[string]upstream, files map[string]edgesFileView, self string) decision {
+ e := &Edge{}
+ e.upstreams.Store(&table)
+ hosts, _ := foldHomes(files, self, false)
+ m := &homeMap{self: self, snap: &homeSnapshot{files: files, hosts: hosts, cands: buildCandidates(files, self, false)}}
+ e.homes.Store(m)
+ return e.resolve(diffHost, rankNow)
+}
+
+// diffAgrees reports whether the decision is today's answer: the same
+// table entry served from the same table, or the same dial target, owner,
+// stamp and classes, with the local catch-all as its fallback exactly when
+// today kept it.
+func diffAgrees(got decision, want diffWant, table map[string]upstream) bool {
+ switch {
+ case want.local != "":
+ return got.kind == decLocal && got.up != nil && got.up.route.App == table[want.local].route.App &&
+ tablePtr(got.table) == tablePtr(table) && got.fallback == nil
+ case want.remote != nil:
+ h := want.remote
+ if got.kind != decRemote || got.eip != h.eip || got.box != h.box || got.account != h.account || got.app != h.app || got.stamp != h.stamp ||
+ got.platform != h.platform || got.wildcard != h.wildcard {
+ return false
+ }
+ if want.fallback {
+ return got.fallback != nil && got.fallback.up.route.App == "local-wild" && tablePtr(got.fallback.table) == tablePtr(table)
+ }
+ return got.fallback == nil
+ }
+ return got.kind == decNone
+}
+
+func describeWant(w diffWant) string {
+ switch {
+ case w.local != "":
+ return "local " + w.local
+ case w.remote != nil:
+ s := fmt.Sprintf("remote %s at %s (platform %v wildcard %v)", w.remote.app, w.remote.box, w.remote.platform, w.remote.wildcard)
+ if w.fallback {
+ s += " with the local catch-all as fallback"
+ }
+ return s
+ }
+ return "none"
+}
+
+func describeGot(d decision) string {
+ s := describeDecision(d)
+ if d.kind == decRemote {
+ s += fmt.Sprintf(" (platform %v wildcard %v)", d.platform, d.wildcard)
+ }
+ if d.fallback != nil {
+ s += " with fallback " + d.fallback.up.route.App
+ }
+ return s
+}
+
+// TestRankEqualsFoldWithoutHolds: every set of the no-hold model (two other
+// boxes' files, each publishing the host as nothing, a real route or an
+// alias of a target or of none, at three pairs, stamped or not; the
+// catch-all as nothing, two dialled entries or the certificate-only role;
+// fresh, or retained with an expired hold that would suppress everything;
+// every table; labelled, labelled as one of the publishers, and unlabelled)
+// resolves as today's dispatch did. Two named sets first: the empty-target
+// exception (two legacy aliases never compare pairs, so the first file's
+// lower one keeps the dial) and a stamped publication against a retained
+// file's higher unstamped pair (the stamp wins).
+func TestRankEqualsFoldWithoutHolds(t *testing.T) {
+ check := func(t *testing.T, table map[string]upstream, files map[string]edgesFileView, self string) bool {
+ t.Helper()
+ want := todaysDispatch(table, files, self)
+ got := resolveOn(table, files, self)
+ if !diffAgrees(got, want, table) {
+ keys := make([]string, 0, len(files))
+ for k := range files {
+ keys = append(keys, k)
+ }
+ slices.Sort(keys)
+ var b strings.Builder
+ for _, k := range keys {
+ f := files[k]
+ fmt.Fprintf(&b, "\n %s (fetched %s): hosts %+v holds %d", k, rankNow.Sub(f.fetchedAt), f.Hosts, len(f.OfflineMoves))
+ }
+ tk := slices.Sorted(func(yield func(string) bool) {
+ for k := range table {
+ if !yield(k) {
+ return
+ }
+ }
+ })
+ t.Errorf("self %q table %v: resolve = %s, today = %s%s", self, tk, describeGot(got), describeWant(want), b.String())
+ return false
+ }
+ return true
+ }
+ t.Run("the empty-target exception", func(t *testing.T) {
+ files := map[string]edgesFileView{
+ "control/edges/a.json": diffFile("annie", &edgesHostView{Role: edgeRoleHome, Alias: true, Incarnation: 1, App: "low"}, nil, false),
+ "control/edges/b.json": diffFile("betty", &edgesHostView{Role: edgeRoleHome, Alias: true, Incarnation: 2, App: "high"}, nil, false),
+ }
+ check(t, map[string]upstream{}, files, "zed")
+ if d := resolveOn(map[string]upstream{}, files, "zed"); d.box != "annie" {
+ t.Fatalf("resolve = %s, want annie: aliases naming no target compare no pairs", describeGot(d))
+ }
+ })
+ t.Run("stamped against retained", func(t *testing.T) {
+ files := map[string]edgesFileView{
+ "control/edges/a.json": diffFile("annie", &edgesHostView{Role: edgeRoleHome, Incarnation: 1, ServingSeq: 2, App: "retained"}, nil, true),
+ "control/edges/b.json": diffFile("betty", &edgesHostView{Role: edgeRoleHome, Stamp: 7, App: "stamped"}, nil, false),
+ }
+ check(t, map[string]upstream{}, files, "zed")
+ if d := resolveOn(map[string]upstream{}, files, "zed"); d.box != "betty" {
+ t.Fatalf("resolve = %s, want betty: a stamp outranks any pair, and an expired hold suppresses nothing", describeGot(d))
+ }
+ })
+ t.Run("the model", func(t *testing.T) {
+ tables := diffTables()
+ aHosts, bHosts := diffHostEntries(true), diffHostEntries(false)
+ cases, failures := 0, 0
+ for _, ah := range aHosts {
+ for _, ak := range diffKeyEntries {
+ for _, ar := range []bool{false, true} {
+ for _, bh := range bHosts {
+ for _, bk := range diffKeyEntries {
+ for _, br := range []bool{false, true} {
+ files := map[string]edgesFileView{
+ "control/edges/a.json": diffFile("annie", ah, ak, ar),
+ "control/edges/b.json": diffFile("betty", bh, bk, br),
+ }
+ for _, table := range tables {
+ for _, self := range []string{"zed", "annie", ""} {
+ cases++
+ if !check(t, table, files, self) {
+ if failures++; failures >= 10 {
+ t.FailNow()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ t.Logf("%d resolutions", cases)
+ })
+}