messenger invoked seat:node-engine.root-free while nothing answered it, and Telegram held every ask that offers an approval, silently. Nothing judged a seat:<seat>.<verb> invoke beyond its spelling: not that the seat exists, that it promises the verb, nor that anything holds it. Quick fix: messenger asks the controller's root-free (mesh-catalog bc271896) and the engine announces its seat as discovery reads it (mesh-host 7ecf7ba). Thorough fix, chosen because an invoke nothing answers fails only at the call, silently for whoever waits on it: CatalogueProblems refuses every seat verb a module or one of its processes invokes whose seat no module declares and the mesh does not define, whose seat does not promise the verb, or whose seat no module claims (a seat every node's engine holds, ADR 0563 §1, is held). Over some manifests alone a seat whose holder was not given is a note (IsUndeclaredSeat). Over every manifest of mesh-catalog, mesh-control and mesh-delivery today it refuses nothing.
90 lines
3.2 KiB
Go
90 lines
3.2 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"strings"
|
|
)
|
|
|
|
// A seat verb a module invokes is one some holder serves (issue 774, sweep item 1). messenger invoked
|
|
// `seat:node-engine.root-free`, which nothing in the mesh answered, so every ask that offers an approval was held on
|
|
// Telegram, silently. A manifest names what it calls (novox/hq ADR 0152); that a seat by that name exists, promises
|
|
// that verb, and has a holder is only known over the whole catalogue, so it is judged here, beside the seats' other
|
|
// rules (CatalogueProblems).
|
|
|
|
// UnheldSeat ends the problem of a `seat:<seat>.<verb>` whose seat no module given claims: over the whole catalogue a
|
|
// refusal, over some manifests alone a seat whose holder was not given (IsUndeclaredSeat says both).
|
|
const UnheldSeat = "which no module claims, so nothing answers it"
|
|
|
|
// SeatInvoke splits an invoke `seat:<seat>.<verb>` into its seat and verb; ok is false for anything else (a module's
|
|
// tool, `*`).
|
|
func SeatInvoke(invoke string) (seat, verb string, ok bool) {
|
|
rest, isSeat := strings.CutPrefix(invoke, "seat:")
|
|
if !isSeat {
|
|
return "", "", false
|
|
}
|
|
seat, verb, ok = strings.Cut(rest, ".")
|
|
return seat, verb, ok && seat != "" && verb != ""
|
|
}
|
|
|
|
// seatInvokeProblems are the `seat:<seat>.<verb>` a module or one of its processes invokes that nothing answers: a seat
|
|
// no module declares and the mesh does not define, a verb the seat does not promise, or a seat with no holder (a
|
|
// mesh seat no module claims, unless its node's engine holds it, ADR 0563 §1).
|
|
func seatInvokeProblems(shelf Shelf, declared map[string]SeatDeclaration) []string {
|
|
claimed := map[string]bool{}
|
|
for _, m := range shelf {
|
|
for _, c := range m.Claims {
|
|
claimed[c.Name] = true
|
|
if s, ok := SeatNamed(c.Name); ok {
|
|
claimed[s.Name] = true
|
|
}
|
|
}
|
|
}
|
|
var problems []string
|
|
for _, module := range shelfOrder(shelf) {
|
|
m := shelf[module]
|
|
for _, invoke := range invokesOf(m) {
|
|
seat, verb, ok := SeatInvoke(invoke)
|
|
if !ok {
|
|
continue
|
|
}
|
|
var verbs []Verb
|
|
held := claimed[seat]
|
|
if s, isMesh := SeatNamed(seat); isMesh {
|
|
verbs, held = s.Serves, held || claimed[s.Name] || s.HeldByTheEngine
|
|
} else if d, isModule := declared[seat]; isModule {
|
|
verbs = d.Serves
|
|
} else {
|
|
problems = append(problems, fmt.Sprintf("%s invokes %s, a verb of the seat %q, "+UndeclaredSeat, module, invoke, seat))
|
|
continue
|
|
}
|
|
if !slices.ContainsFunc(verbs, func(v Verb) bool { return v.Name == verb }) {
|
|
problems = append(problems, fmt.Sprintf("%s invokes %s, and the seat %s serves no verb %q", module, invoke, seat, verb))
|
|
continue
|
|
}
|
|
if !held {
|
|
problems = append(problems, fmt.Sprintf("%s invokes %s, a verb of the seat %q, "+UnheldSeat, module, invoke, seat))
|
|
}
|
|
}
|
|
}
|
|
return problems
|
|
}
|
|
|
|
// invokesOf is everything a module says it invokes: its own and each process's bus, once each.
|
|
func invokesOf(m Manifest) []string {
|
|
out := append([]string(nil), m.Invokes...)
|
|
for _, r := range m.Resources {
|
|
if fmt.Sprint(r["type"]) != "process" {
|
|
continue
|
|
}
|
|
if _, present := r["bus"]; !present {
|
|
continue
|
|
}
|
|
if b, _, err := processBusOf(r); err == nil {
|
|
out = append(out, b.Invokes...)
|
|
}
|
|
}
|
|
slices.Sort(out)
|
|
return slices.Compact(out)
|
|
}
|