diff --git a/modules/mesh-delivery-indexer/judge/rules.go b/modules/mesh-delivery-indexer/judge/rules.go index 2a25acc0..5e32d375 100644 --- a/modules/mesh-delivery-indexer/judge/rules.go +++ b/modules/mesh-delivery-indexer/judge/rules.go @@ -3991,12 +3991,24 @@ func filepathDir(p string) string { } // invokeNameValid says a module or process's invoked entry names a tool: ., a role's -// seat:., or * for every tool on the mesh (novox/hq ADR 0152, ADR 0436 §1). +// seat:. or a kind the seat accepts (seat:., seat:.., design 47 G A-102), +// or * for every tool on the mesh (novox/hq ADR 0152, ADR 0436 §1). func invokeNameValid(t string) bool { if t == "*" { return true } - t = strings.TrimPrefix(t, "seat:") + if rest, isSeat := strings.CutPrefix(t, "seat:"); isSeat { + // A seat's verb, or a kind the seat accepts: ``, or `.` for one that rides a stream (design 47 G + // A-102); seatInvokeProblems judges it against the seat. + seat, after, named := strings.Cut(rest, ".") + if !named || !name.MatchString(seat) { + return false + } + if stream, kind, onStream := strings.Cut(after, "."); onStream { + return toolName.MatchString(stream) && toolName.MatchString(kind) + } + return toolName.MatchString(after) + } first, second, named := strings.Cut(t, ".") return named && name.MatchString(first) && toolName.MatchString(second) } diff --git a/modules/mesh-delivery-indexer/judge/rules_test.go b/modules/mesh-delivery-indexer/judge/rules_test.go index e5d69b46..92b0d9fb 100644 --- a/modules/mesh-delivery-indexer/judge/rules_test.go +++ b/modules/mesh-delivery-indexer/judge/rules_test.go @@ -6457,7 +6457,8 @@ func TestASeatNamedReadIsJudgedAgainstTheSeatsStates(t *testing.T) { {"seat:mesh-provisioner.check.other", `serves no verb "check.other"`}, } { shelf["caller"] = catalogue.Manifest{Module: "caller", Invokes: []string{row.invoke}} - problems := strings.Join(seatInvokeProblems(shelf, nil), "\n") + // The manifest's own invokes rule (at parse) takes the dotted kind as well; the seat's rule then judges it. + problems := strings.Join(append(invokeProblems(shelf["caller"]), seatInvokeProblems(shelf, nil)...), "\n") if row.says == "" && problems != "" || row.says != "" && !strings.Contains(problems, row.says) { t.Errorf("%s: problems %q, want %q", row.invoke, problems, row.says) }