Builder: the manifest names no other module, the floor reads the seat git and the catalog half

The floor's tags are the seat git's verb tags and its requirements what the catalog half's entries
name for the package (indexer_requirements and the forge bridge's bridge_tags go from code and
manifest); a catalog revision the builder hears wakes a silent floor (the forge stream's consume
and its wake go). The guard test says A-107 relaxes ADR 0437 section 8 for a seat's verbs and
accepted kinds. The integration bed creates the state bounds the step bounds are kept in.
The assignments view's seat form (A-119 (3)) is not built here.

Builds: design 47 G §7, A-82, A-107, A-119
Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 01:18:40 +01:00
parent fd8f019751
commit 1eb481ccc8
14 changed files with 111 additions and 127 deletions
@@ -9,8 +9,8 @@ import (
// The tools' descriptions.
const (
FloorAgainDescription = "Ask the floor of one name again now, by hand (design 51 *The floor*): the seat's versions, the forge bridge's " +
"bridge_tags and the indexer's indexer_requirements, as the builder asks them by itself when a silent source says something. " +
FloorAgainDescription = "Ask the floor of one name again now, by hand (design 51 *The floor*): the seat's versions, the seat git's " +
"git.tags and the indexer's indexer_requirements, as the builder asks them by itself when a silent source says something. " +
"Answers which sources were silent and whether the floor is now known. A name the builder's versions already hold needs no floor: " +
"refused, saying so. A hand act."
)
@@ -135,3 +135,20 @@ func HolderOf(branches *meshcatalogclient.Branches) func(seat string) (string, b
return holders[0], true
}
}
// RequirementsFrom answers the versions of a package the entries of every followed half require, each once, in order: what a
// consumer's entry names for it in its packages (design 47 G A-119), the floor's third source.
func RequirementsFrom(all Entries) func(ctx context.Context, name string) ([]string, error) {
return func(_ context.Context, name string) ([]string, error) {
seen := map[string]bool{}
var out []string
for _, e := range all() {
if v := e.Packages[name]; v != "" && !seen[v] {
seen[v] = true
out = append(out, v)
}
}
sort.Strings(out)
return out, nil
}
}
@@ -53,3 +53,22 @@ func TestPackageNamesAreReadFromTheCatalogHalfsEntries(t *testing.T) {
t.Errorf("CarriersFrom(twin) = %v, want %v", got, want)
}
}
// Design 47 G A-119: the floor's requirements are what the catalog half's entries name for the package, each version once.
func TestRequirementsFromAreTheVersionsEntriesNameForAPackage(t *testing.T) {
entries := func() []meshcatalog.CatalogEntry {
return []meshcatalog.CatalogEntry{
{Module: "a", Packages: map[string]string{"x/sdk": "v0.0.0-2026-aaa", "y": "v1.0.0"}},
{Module: "b", Packages: map[string]string{"x/sdk": "v0.0.0-2026-bbb"}},
{Module: "c", Packages: map[string]string{"x/sdk": "v0.0.0-2026-aaa"}},
{Module: "d"},
}
}
got, err := RequirementsFrom(entries)(context.Background(), "x/sdk")
if err != nil || !reflect.DeepEqual(got, []string{"v0.0.0-2026-aaa", "v0.0.0-2026-bbb"}) {
t.Errorf("requirements = %v, %v", got, err)
}
if got, _ := RequirementsFrom(entries)(context.Background(), "none"); len(got) != 0 {
t.Errorf("a package no entry names has requirements %v", got)
}
}
@@ -17,9 +17,9 @@ import (
type FloorSources struct {
// Seat is `seat:<registry>.versions` of the registry seat the name is published to.
Seat func(ctx context.Context, seat, name string) ([]string, error)
// Tags is the forge bridge's bridge_tags: the git tags of the repository the name is built from, under prefix.
// Tags is the seat git's tags: the git tags of the repository the name is built from, under prefix.
Tags func(ctx context.Context, repository, prefix string) ([]string, error)
// Requirements is the indexer's indexer_requirements: the highest pseudo-versions consumers require.
// Requirements are the versions of a package the catalog half's entries require (design 47 G A-119).
Requirements func(ctx context.Context, name string) ([]string, error)
}
@@ -64,9 +64,9 @@ func (s FloorSources) Ask(ctx context.Context, of FloorOf) (Floor, map[string]st
const (
// WakePublished is the holder's `published` on the builder's durable consumer of `<seat>.events`.
WakePublished = "published"
// WakeForge is the forge bridge's next message on its stream `forge`.
WakeForge = "forge"
// WakeAccepted is the indexer's next `manifest-accepted`.
// WakeRevision is a catalog revision the builder hears (the catalog half's entry changed): tags and requirements are asked again.
WakeRevision = "catalog-revision"
// WakeAccepted is the next `manifest-accepted` of the seat mesh-catalog.
WakeAccepted = "manifest-accepted"
// WakeCleared is the condition keeper's clear of a silent module's health condition on `mesh-conditions`.
WakeCleared = "condition-cleared"
@@ -75,7 +75,7 @@ const (
)
// sourceOfWake is the floor source each event says something of; a clear names the source by its module.
var sourceOfWake = map[string]string{WakePublished: SourceSeat, WakeForge: SourceTags, WakeAccepted: SourceRequirements}
var sourceOfWake = map[string]string{WakePublished: SourceSeat, WakeAccepted: SourceRequirements}
// SourceSeats are the seats whose holders are the floor's tag and requirement sources (design 47 G A-82): the seat git (tags)
// and the seat mesh-catalog (requirements), the holders read from the seat list and the catalog half.
@@ -297,7 +297,11 @@ func (fw *FloorWaits) Wake(kind, seat, module, name string) []string {
}
default:
src := sourceOfWake[kind]
if slices.Contains(w.Silent, src) && (kind != WakePublished || seat == "" || seat == w.Seat) {
if kind == WakeRevision {
if slices.Contains(w.Silent, SourceTags) || slices.Contains(w.Silent, SourceRequirements) {
out = append(out, n)
}
} else if slices.Contains(w.Silent, src) && (kind != WakePublished || seat == "" || seat == w.Seat) {
out = append(out, n)
}
}
@@ -184,21 +184,21 @@ func Patch(series, version string) (int, bool) {
}
// Floor is what the three sources answered for a name (design 51 *The floor*, ADR 0606 §3): the seat's versions, the
// package's git tags (the forge bridge's bridge_tags) and the pseudo-versions consumers require (the indexer's
// package's git tags (the seat git's tags) and the pseudo-versions consumers require (the catalog half's
// indexer_requirements). A source not answered is listed in Silent.
type Floor struct {
Seat []string `json:"seat,omitempty"`
Tags []string `json:"tags,omitempty"`
Requirements []string `json:"requirements,omitempty"`
// Silent names the sources that did not answer: "seat", "bridge_tags", "indexer_requirements".
// Silent names the sources that did not answer: "seat", "git.tags", "catalog.requirements".
Silent []string `json:"silent,omitempty"`
}
// The floor's sources, as Floor.Silent names them.
const (
SourceSeat = "seat"
SourceTags = "bridge_tags"
SourceRequirements = "indexer_requirements"
SourceTags = "git.tags"
SourceRequirements = "catalog.requirements"
)
// Known is whether every source answered.
@@ -256,12 +256,12 @@ func TestTheBuildersVersions(t *testing.T) {
}
f, why := src.Ask(ctx, FloorOf{Seat: "oci-artifact-registry", Name: "m/program"})
if f.Known() || !reflect.DeepEqual(f.Silent, []string{SourceTags}) || why[SourceTags] != "no answer" {
t.Fatalf("Ask = %+v, %v; want bridge_tags silent", f, why)
t.Fatalf("Ask = %+v, %v; want git.tags silent", f, why)
}
holders := map[string]string{SourceSeats[SourceTags]: "mesh-delivery-forge-bridge", SourceSeats[SourceRequirements]: "mesh-delivery-indexer"}
fw := FloorWaits{Holder: func(seat string) (string, bool) { h, ok := holders[seat]; return h, ok }}
w := fw.Wait("m/program", "oci-artifact-registry", "distribution", f, why, time.Unix(0, 0))
if !strings.Contains(w.Finding(), "bridge_tags (no answer)") {
if !strings.Contains(w.Finding(), "git.tags (no answer)") {
t.Errorf("finding = %q", w.Finding())
}
for _, c := range []struct {
@@ -270,7 +270,7 @@ func TestTheBuildersVersions(t *testing.T) {
}{
{WakePublished, "oci-artifact-registry", "", "", nil}, // the seat answered already: a publish wakes nothing
{WakeAccepted, "", "", "", nil},
{WakeForge, "", "", "", []string{"m/program"}},
{WakeRevision, "", "", "", []string{"m/program"}},
{WakeCleared, "", "mesh-delivery-forge-bridge", "", []string{"m/program"}}, // recovered with nothing to say
{WakeCleared, "", "mesh-delivery-indexer", "", nil},
{WakeByHand, "", "", "m/program", []string{"m/program"}},
@@ -295,7 +295,7 @@ func TestTheBuildersVersions(t *testing.T) {
kept := keeperMem{}
restarted := &FloorWaits{}
restarted.Keep(kept, []FloorWait{{Name: "m/held", Seat: SeatImages, Silent: []string{SourceTags}, Since: time.Unix(5, 0)}})
if got := restarted.Wake(WakeForge, "", "", ""); !reflect.DeepEqual(got, []string{"m/held"}) {
if got := restarted.Wake(WakeRevision, "", "", ""); !reflect.DeepEqual(got, []string{"m/held"}) {
t.Errorf("a wait held in floor-waits woke %v after a restart, want m/held", got)
}
restarted.Wait("m/new", SeatNPM, "", Floor{Silent: []string{SourceSeat}}, nil, time.Unix(9, 0))