The node-engine's seat reader reads invokes in both forms and refuses a form it cannot read
Builds: design 47 G A-275, §558 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
@@ -2,9 +2,11 @@ package selfcompose
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
||||
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshwants"
|
||||
)
|
||||
|
||||
@@ -33,3 +35,20 @@ func TestTheKeepingNodeIsTheWantsKeptOn(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Design 47 G §558, A-275: a manifest's `invokes` in its long form {verb, fields} is read for its seat, and one of a form that
|
||||
// cannot be read is refused, never read as no seats.
|
||||
func TestSeatsOfReadsALongFormInvokeAndRefusesAnUnreadableOne(t *testing.T) {
|
||||
c := New(Env{Node: "n1"})
|
||||
c.modules["m"] = meshcatalog.ModulesByModuleValue{Manifest: "d1"}
|
||||
c.modules["bad"] = meshcatalog.ModulesByModuleValue{Manifest: "d2"}
|
||||
c.manifests["d1"] = []byte(`{"module":"m","invokes":["seat:a.b",{"verb":"seat:mesh-catalog.revision","fields":["x"]}]}`)
|
||||
c.manifests["d2"] = []byte(`{"module":"bad","invokes":[3]}`)
|
||||
seats, err := c.seatsOf(context.Background(), reader{c: c}, "m")
|
||||
if err != nil || !slices.Equal(seats, []string{"a", "mesh-catalog"}) {
|
||||
t.Fatalf("seats %v, %v", seats, err)
|
||||
}
|
||||
if seats, err := c.seatsOf(context.Background(), reader{c: c}, "bad"); err == nil {
|
||||
t.Fatalf("an unreadable invokes gave seats %v", seats)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2035,7 +2035,7 @@ func (c *Composer) heldUntilListed(ctx context.Context, r reader, own meshmodule
|
||||
held := map[string]string{}
|
||||
for _, pm := range own.Modules {
|
||||
if pm.Module == "" || pm.Module == agent.NodeModule || slices.Contains(holders, pm.Module) ||
|
||||
c.env.SeatList.MayAct(c.seatsOf(ctx, r, pm.Module)...) {
|
||||
c.mayAct(ctx, r, pm.Module) {
|
||||
continue
|
||||
}
|
||||
held[pm.Module] = line + composesNothingNewOfIt
|
||||
@@ -2094,7 +2094,7 @@ func (c *Composer) holdUntilListed(ctx context.Context, r reader, compositions m
|
||||
held[module] = WaitsForTheSeatListOwnPart
|
||||
continue
|
||||
}
|
||||
} else if c.env.SeatList.MayAct(c.seatsOf(ctx, r, module)...) {
|
||||
} else if c.mayAct(ctx, r, module) {
|
||||
continue
|
||||
}
|
||||
delete(compositions, key)
|
||||
@@ -2207,41 +2207,55 @@ func (c *Composer) claimants(ctx context.Context, r reader, seat string) []strin
|
||||
return out
|
||||
}
|
||||
|
||||
// seatsOf is the seats a module claims, invokes or provides, from the manifest its module record names; none when it
|
||||
// cannot be read, which the reader judges as a module no bootstrapped seat names.
|
||||
func (c *Composer) seatsOf(ctx context.Context, r reader, module string) []string {
|
||||
// mayAct is whether the seat list lets module act: of the seats it claims or invokes (seatsOf). A manifest whose `invokes`
|
||||
// is of a form that cannot be read is refused, never read as no seats (design 47 G A-275).
|
||||
func (c *Composer) mayAct(ctx context.Context, r reader, module string) bool {
|
||||
seats, err := c.seatsOf(ctx, r, module)
|
||||
if err != nil {
|
||||
return false // refused: held with the module's other waits, never judged as no seats
|
||||
}
|
||||
return c.env.SeatList.MayAct(seats...)
|
||||
}
|
||||
|
||||
// seatsOf is the seats a module claims or invokes, from the manifest its module record names; none when it cannot be
|
||||
// fetched, which the reader judges as a module no bootstrapped seat names, and an error when its manifest is of a form that
|
||||
// cannot be read (design 47 G §558, A-275).
|
||||
func (c *Composer) seatsOf(ctx context.Context, r reader, module string) ([]string, error) {
|
||||
c.mu.Lock()
|
||||
m, ok := c.modules[module]
|
||||
c.mu.Unlock()
|
||||
if !ok || m.Manifest == "" {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
raw, err := r.Manifest(ctx, m.Manifest)
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
var man struct {
|
||||
Claims []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"claims"`
|
||||
Invokes []string `json:"invokes"`
|
||||
Provides []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"provides"`
|
||||
Invokes json.RawMessage `json:"invokes"`
|
||||
}
|
||||
if json.Unmarshal(raw, &man) != nil {
|
||||
return nil
|
||||
if err := json.Unmarshal(raw, &man); err != nil {
|
||||
return nil, fmt.Errorf("the manifest of %s cannot be read: %w", module, err)
|
||||
}
|
||||
var invokes []string
|
||||
if len(man.Invokes) > 0 {
|
||||
if invokes, err = catalogue.InvokedVerbs(man.Invokes); err != nil {
|
||||
return nil, fmt.Errorf("the manifest of %s: %w", module, err)
|
||||
}
|
||||
}
|
||||
var seats []string
|
||||
for _, cl := range man.Claims {
|
||||
seats = append(seats, cl.Name)
|
||||
}
|
||||
for _, in := range man.Invokes {
|
||||
for _, in := range invokes {
|
||||
if seat, _, ok := strings.Cut(strings.TrimPrefix(in, "seat:"), "."); ok && strings.HasPrefix(in, "seat:") {
|
||||
seats = append(seats, seat)
|
||||
}
|
||||
}
|
||||
return seats
|
||||
return seats, nil
|
||||
}
|
||||
|
||||
// unmadeOf is each module wanted at a fingerprint (fps) of which the pass made no composition at it, with why, apart from
|
||||
|
||||
Reference in New Issue
Block a user