From 9b3cc53db96b97a00cefb4beebd9fa5f0b3019a4 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 12 Nov 2026 02:49:04 +0100 Subject: [PATCH] Join 10: the validator takes a seat's accepted kind on a stream in invokes at parse, as its seat rule does The per-manifest invokes rule refused seat:.. (the pipeline's seat:node-build-go.check.step) before the seat rule that accepts it was reached; the test now runs both rules on each row. Builds: design 47 G A-102 Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h --- modules/mesh-delivery-indexer/judge/rules.go | 16 ++++++++++++++-- .../mesh-delivery-indexer/judge/rules_test.go | 3 ++- 2 files changed, 16 insertions(+), 3 deletions(-) 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) }