The seat-invoke rule refused mesh-config, mesh-healers and messenger calling the controller's verbs, and mesh-self-check calling the watchman's seat, over a catalogue that holds no manifest of their holders: the controller answers its seat itself, and the watchman lives in mesh-delivery. mesh-control's TestModuleCheckPassesTheCatalogue (the captured mesh-catalog) failed on it. A mesh seat is held by the mesh or by a module of any repository, so one repository's catalogue cannot say it has no holder: for a mesh seat only the verb is judged; a seat a module declares is still judged for a claimant. Over the captured catalogue, the live mesh-catalog alone, and mesh-catalog, mesh-control, mesh-delivery and mesh-host together: no refusal.
94 lines
3.5 KiB
Go
94 lines
3.5 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
|
|
// seat a module declares and no module claims; a mesh seat's holder, the mesh itself or a module of any repository,
|
|
// is not judged).
|
|
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 {
|
|
// A mesh seat is held by the mesh itself or by a module of any repository: one repository's catalogue
|
|
// cannot say it has no holder, so only its verbs are judged (the lead, 2026-10-30: mesh-control's check
|
|
// runs over the captured mesh-catalog alone, whose mesh-self-check calls the watchman's seat).
|
|
verbs, held = s.Serves, true
|
|
} 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)
|
|
}
|