Let a module-declared seat carry needs, so mail-notifier can need node-notifier (issue 802)

ADR 0220's dependency mechanism served compiled seats only and retired its one user with
node-resolver-config (commit f68521da). ADR 0378 S8 revives it for module-declared seats:
SeatDeclaration gains Needs, judged by the catalogue check (node scope only, a name that
resolves to a node seat somewhere in the catalogue, never itself), and DependsOn now takes
the catalogue so a claimed seat's needs are found wherever they are declared.
This commit is contained in:
jochen
2026-10-15 17:18:23 +02:00
parent 0ab61d1be8
commit b5a441a978
9 changed files with 188 additions and 23 deletions
+61
View File
@@ -71,6 +71,12 @@ type SeatDeclaration struct {
// mesh's own seats name theirs by: a node seat only, each absolute and literal, and none another seat
// names. A module's seat never steps back.
Paths []string `json:"paths,omitempty"`
// Needs is every node seat this seat's holder needs held on its own node (novox/hq ADR 0220, ADR
// 0378 §8): a role whose holder is only right while another role is filled beside it. A module
// claiming this seat depends on each, exactly as a module declaring a service depends on the
// service manager (ADR 0207) — derived from the claim, never written again in the claimant's own
// manifest. Only a node seat may carry needs, and a compiled seat carries none.
Needs []string `json:"needs,omitempty"`
}
// KindedBenches are the seats that may be kinded (novox/hq ADR 0234 §2): `channel` sends to the operator,
@@ -168,6 +174,7 @@ func declaredSeatProblems(m Manifest) []string {
}
problems = append(problems, trafficProblems(m, s)...)
problems = append(problems, declaredSeatPathProblems(m, s)...)
problems = append(problems, declaredSeatNeedsProblems(m, s)...)
}
for _, u := range m.Uses {
@@ -228,6 +235,30 @@ func trafficProblems(m Manifest, s SeatDeclaration) []string {
return problems
}
// declaredSeatNeedsProblems is what one declaration's needs can be judged on alone (novox/hq ADR
// 0378 §8): only a node seat is ever held beside another on the same node, so only a node seat may
// carry needs; and a seat needing itself names nothing that was not already true of holding it.
// Whether each named need itself exists as a node seat somewhere in the catalogue is CatalogueProblems'
// to say, once every manifest is known.
func declaredSeatNeedsProblems(m Manifest, s SeatDeclaration) []string {
var problems []string
if len(s.Needs) == 0 {
return problems
}
if s.At() != ScopeNode {
problems = append(problems, fmt.Sprintf(
"%s declares %s needing %s, and only a node seat needs another held beside it "+
"(novox/hq ADR 0378 §8)", m.Module, s.Name, strings.Join(s.Needs, ", ")))
}
for _, need := range s.Needs {
if need == s.Name {
problems = append(problems, fmt.Sprintf(
"%s declares %s needing itself (novox/hq ADR 0378 §8)", m.Module, s.Name))
}
}
return problems
}
// A Shelf is every manifest the mesh has registered, by module name.
type Shelf map[string]Manifest
@@ -280,6 +311,36 @@ func CatalogueProblems(shelf Shelf) []string {
return ok
}
// atNode says whether a seat, compiled or declared, is a node seat — judged here because only
// the whole catalogue knows a declared one's scope (novox/hq ADR 0378 §8).
atNode := func(seat string) bool {
if s, isMesh := SeatNamed(seat); isMesh {
return s.Scope == ScopeNode
}
if s, ok := declared[seat]; ok {
return s.At() == ScopeNode
}
return false
}
// A module-declared seat's needs name node seats that hold beside it (novox/hq ADR 0378 §8):
// whether one exists at all, compiled or declared by any module, only the whole catalogue can
// say — a single manifest's own problems (declaredSeatProblems) judge its needs no further.
for _, module := range shelfOrder(shelf) {
for _, s := range shelf[module].DefinesSeats {
for _, need := range s.Needs {
if !exists(need) {
problems = append(problems, fmt.Sprintf(
"%s declares %s needing %s, "+UndeclaredSeat, module, s.Name, need))
} else if !atNode(need) {
problems = append(problems, fmt.Sprintf(
"%s declares %s needing %s, which is not a node seat (novox/hq ADR 0378 §8)",
module, s.Name, need))
}
}
}
}
// Which seats name each path (novox/hq ADR 0287): a module's seat naming one another seat names loses.
named, pathProblems := pathSeats(shelfOrder(shelf), shelf, declaredBy)
problems = append(problems, pathProblems...)