Item 5 (join 11): an asker's build-seat queue is served by the seat's holders, so the indexer draws its kind-6 edge
An asker names the queue it asks as seat:<seat>.accept.<queue> (A-231); no module's serves lists that form, so graph.Servers matched nothing and the indexer drew no served-verb edge from a build seat's holders to the asker. Servers now reads the form through mesh-sdk's catalogue.QueueInvoke and answers every module serving a verb of the seat; the kind-6 edge asks the module graph's Servers, the one rule, instead of a match of its own. Builds: design 47 G §544, §605, A-231 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-sdk/graph"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
"git.novox.be/novox/mesh-sdk/go/seatdef"
|
||||
)
|
||||
@@ -232,6 +233,12 @@ func edgesOf(a meshcatalog.CatalogEntry, all map[string]meshcatalog.CatalogEntry
|
||||
}
|
||||
// Kind 6: a verb or a tool it invokes and another entry serves (§47), unless its edge lies on a cycle and is left out (ADR 0614 §3).
|
||||
// A verb whose answer's fields it relies on (the long form of `invokes`, §558) names them in the edge's `why`.
|
||||
// Who serves an invoke is the module graph's one rule (graph.Servers): a build seat's queue, `seat:<seat>.accept.<queue>`,
|
||||
// is its holders' (A-231).
|
||||
serving := graph.Graph{}
|
||||
for _, m := range modules {
|
||||
serving[m] = graph.Node{Serves: all[m].Serves}
|
||||
}
|
||||
fields := manifestOf(a).InvokeFields
|
||||
for _, verb := range a.Invokes {
|
||||
if slices.Contains(a.LeftOut, verb) {
|
||||
@@ -241,9 +248,9 @@ func edgesOf(a meshcatalog.CatalogEntry, all map[string]meshcatalog.CatalogEntry
|
||||
if named := fields[verb]; len(named) > 0 {
|
||||
why += " fields " + strings.Join(named, ", ")
|
||||
}
|
||||
for _, m := range modules {
|
||||
if b := all[m]; m != a.Module && slices.Contains(b.Serves, verb) {
|
||||
add(meshcatalog.Edge{Kind: 6, From: primaryOf(b), To: delivers, Word: verb, Why: why})
|
||||
for _, m := range serving.Servers(verb) {
|
||||
if m != a.Module {
|
||||
add(meshcatalog.Edge{Kind: 6, From: primaryOf(all[m]), To: delivers, Word: verb, Why: why})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,11 @@ func TestAnEntryCarriesItsEdgesOfKindsOneToFourAndSix(t *testing.T) {
|
||||
Provides: []string{"builder"}, Serves: []string{"seat:mesh-builds.build"}},
|
||||
"db": {Module: "db", Artifacts: []meshcatalog.Artifact{{Ref: "db:image", Kind: "image"}}, Provides: []string{"sql"}},
|
||||
"cfg": {Module: "cfg", Artifacts: []meshcatalog.Artifact{{Ref: "cfg:archive", Kind: "archive"}}},
|
||||
// A build seat's holder: the queue an asker names in its invokes, `seat:<seat>.accept.<queue>`, is its (A-231).
|
||||
"node-go": {Module: "node-go", Artifacts: []meshcatalog.Artifact{{Ref: "node-go:program", Language: "go"}}, Serves: []string{"seat:node-build-go.steps"}},
|
||||
"app": {Module: "app", Packages: map[string]string{"git.example/lib/go": "1.2.3"}, Bases: []string{"db"},
|
||||
Toolchains: map[string]meshcatalog.BuildEdge{"go": {Module: "build-go"}},
|
||||
Awaits: []string{"sql"}, Invokes: []string{"seat:mesh-builds.build", "seat:mesh-builds.cycle"}, LeftOut: []string{"seat:mesh-builds.cycle"},
|
||||
Awaits: []string{"sql"}, Invokes: []string{"seat:mesh-builds.build", "seat:mesh-builds.cycle", "seat:node-build-go.accept.check"}, LeftOut: []string{"seat:mesh-builds.cycle"},
|
||||
Manifest: map[string]any{"build": map[string]any{"artifacts": []any{map[string]any{"name": "program", "needs": []any{"cfg:archive", "nothing:here"}}}}},
|
||||
Artifacts: []meshcatalog.Artifact{{Ref: "app:program", Language: "go"}}},
|
||||
}
|
||||
@@ -35,6 +37,7 @@ func TestAnEntryCarriesItsEdgesOfKindsOneToFourAndSix(t *testing.T) {
|
||||
{Kind: 3, From: "db:image", To: "app:program", Stale: true, Word: "build.on", Why: "db"},
|
||||
{Kind: 4, From: "db:image", To: "app:program", Word: "requires", Why: "sql"},
|
||||
{Kind: 6, From: "build-go:program", To: "app:program", Word: "seat:mesh-builds.build", Why: "seat:mesh-builds.build"},
|
||||
{Kind: 6, From: "node-go:program", To: "app:program", Word: "seat:node-build-go.accept.check", Why: "seat:node-build-go.accept.check"},
|
||||
}
|
||||
if !slices.Equal(got, want) {
|
||||
t.Errorf("edges\n got %+v\nwant %+v", got, want)
|
||||
|
||||
@@ -338,11 +338,17 @@ func (g Graph) Dependents(module string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// Servers are the modules whose Serves names invoke (a seat verb or a module tool), sorted.
|
||||
// Servers are the modules whose Serves names invoke (a seat verb or a module tool), sorted. An asker's queue of a build
|
||||
// seat, `seat:<seat>.accept.<queue>` (design 47 G §544, A-231, read by catalogue.QueueInvoke), is served by every holder
|
||||
// of the seat: each module whose Serves names a verb of it.
|
||||
func (g Graph) Servers(invoke string) []string {
|
||||
seat, _, queue := catalogue.QueueInvoke(invoke)
|
||||
var out []string
|
||||
for name, n := range g {
|
||||
if slices.Contains(n.Serves, invoke) {
|
||||
if slices.Contains(n.Serves, invoke) || queue && slices.ContainsFunc(n.Serves, func(v string) bool {
|
||||
s, _, ok := catalogue.SeatInvoke(v)
|
||||
return ok && s == seat
|
||||
}) {
|
||||
out = append(out, name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,6 +298,15 @@ func readersOfTheSeatList(t *testing.T) {
|
||||
if got := g.Servers(list); !reflect.DeepEqual(got, []string{"indexer"}) {
|
||||
t.Errorf("servers of the seat list = %v", got)
|
||||
}
|
||||
// A-231: an asker's queue of a build seat, `seat:<seat>.accept.<queue>`, is served by the seat's holders.
|
||||
g["build-go"] = node(func(n *Node) { n.Serves = []string{"seat:node-build-go.steps"} })
|
||||
if got := g.Servers("seat:node-build-go.accept.check"); !reflect.DeepEqual(got, []string{"build-go"}) {
|
||||
t.Errorf("servers of a build seat's queue = %v", got)
|
||||
}
|
||||
if got := g.Servers("seat:node-build-go.accept.check.extra"); len(got) != 0 {
|
||||
t.Errorf("servers of what is no queue = %v", got)
|
||||
}
|
||||
delete(g, "build-go")
|
||||
if got := g.Before("checker"); !reflect.DeepEqual(got, []string{"indexer"}) {
|
||||
t.Errorf("the checker waits for %v, want the indexer", got)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user