W5.10 (base): the module graph's node of a catalog entry is read in the domain SDK's graph, for every reader of the catalog half

graph.NodeOf moves from the indexer's own package to sdk/graph, since the assigner reads its verb edges from the catalog
half too (a second reader).

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ

Builds: design 47 G §47 to §50, §121, §122, §378
This commit is contained in:
2026-11-11 14:36:24 +01:00
parent 941af88086
commit 7a7b504836
5 changed files with 30 additions and 22 deletions
@@ -73,24 +73,6 @@ func ModuleValueOf(e meshcatalog.CatalogEntry) meshcatalog.ModulesByModuleValue
return v
}
// NodeOf is the node of the module graph an entry carries, as CatalogEntryOf took it in: the graph the indexer holds in
// memory is read back from the newest trunk revision at its start (TrunkView), so a revision kept before its first
// recompute loses no edge.
func NodeOf(e meshcatalog.CatalogEntry) graph.Node {
n := graph.Node{V: graph.Version, FP: e.Fp, None: e.None, Repository: e.Repository, Path: e.Path, Bases: e.Bases,
Provides: e.Provides, Requires: e.Requires, Awaits: e.Awaits, Invokes: e.Invokes, Serves: e.Serves, LeftOut: e.LeftOut}
if len(e.Packages) > 0 {
n.Packages = slices.Sorted(maps.Keys(e.Packages))
}
for language, t := range e.Toolchains {
if n.Toolchains == nil {
n.Toolchains = map[string]graph.Toolchain{}
}
n.Toolchains[language] = graph.Toolchain{Module: t.Module, Version: t.Version, Recipe: t.Recipe}
}
return n
}
// EncodeEntry is an entry's bytes and their sha256 in hex, the name of its object: the same entry in two revisions is
// one object (design 47, *An unchanged entry is stored once*).
func EncodeEntry(e meshcatalog.CatalogEntry) (string, []byte, error) {
@@ -380,7 +380,7 @@ func TrunkView(ctx context.Context, o Objects) (modules, nodes Store, at int64,
if err != nil {
continue // a module the graph cannot name has no node, as writeGraph writes none
}
node, err := graph.Encode(NodeOf(e))
node, err := graph.Encode(graph.NodeOf(e))
if err != nil {
return nil, nil, 0, fmt.Errorf("trunk.%d: the node of %s: %w", newest.Revision, e.Module, err)
}
@@ -372,9 +372,9 @@ func TestBasesAreComputedFirstAndNoFingerprintTakesTheBuilder(t *testing.T) { //
// first recompute after a start loses no edge.
gk, _ := graph.Key(name)
rawNode, _, found, _ := nodes.Get(context.Background(), gk)
if back, err := graph.Decode(rawNode); !found || err != nil || !reflect.DeepEqual(NodeOf(e), back) || back.FP != e.Fp ||
if back, err := graph.Decode(rawNode); !found || err != nil || !reflect.DeepEqual(graph.NodeOf(e), back) || back.FP != e.Fp ||
!reflect.DeepEqual(back.Bases, e.Bases) || !reflect.DeepEqual(CatalogEntryOf(name, ModuleValueOf(e), catalogue.Manifest{}, "", back).Bases, e.Bases) {
t.Errorf("the view's node of %s = %+v (%v), want %+v", name, back, err, NodeOf(e))
t.Errorf("the view's node of %s = %+v (%v), want %+v", name, back, err, graph.NodeOf(e))
}
}
if empty, _, at, err := TrunkView(context.Background(), newMemObjects(0)); err != nil || at != 0 || func() bool { k, _ := empty.Keys(context.Background()); return len(k) != 0 }() {
+1 -1
View File
@@ -15,4 +15,4 @@ require (
golang.org/x/sys v0.48.0 // indirect
)
require git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog v0.0.0-00010101000000-000000000000 // indirect
require git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog v0.0.0-00010101000000-000000000000
+26
View File
@@ -0,0 +1,26 @@
package graph
import (
"maps"
"slices"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
)
// NodeOf is the node of the module graph a catalog graph entry carries, as the indexer took it in (design 47, *Two
// graphs*): the catalog half's holder reads its graph back from its newest trunk revision, and every part that reads the
// catalog half reads the module graph from its entries, never from the holder's state.
func NodeOf(e meshcatalog.CatalogEntry) Node {
n := Node{V: Version, FP: e.Fp, None: e.None, Repository: e.Repository, Path: e.Path, Bases: e.Bases,
Provides: e.Provides, Requires: e.Requires, Awaits: e.Awaits, Invokes: e.Invokes, Serves: e.Serves, LeftOut: e.LeftOut}
if len(e.Packages) > 0 {
n.Packages = slices.Sorted(maps.Keys(e.Packages))
}
for language, t := range e.Toolchains {
if n.Toolchains == nil {
n.Toolchains = map[string]Toolchain{}
}
n.Toolchains[language] = Toolchain{Module: t.Module, Version: t.Version, Recipe: t.Recipe}
}
return n
}