mesh/merge-gate head 755457cc379e merged into trunk 4cc6b6c566a5 — pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus…
mesh/repo-check head 755457cc379e merged into trunk 4cc6b6c566a5 — pass: its merge-check.sh passed
mesh/delivery covered after its failure: a later walk that contains it was delivered: plan-1792019685173332639 (novox/mesh-controller at 0b7e740b into ma…
A session on the mesh MCP server polls for every verdict, answer and delivery because the tool runner's account hears no event. ADR 0367 lets the tool runner's module name, one by one, the families a session may wait on: the manifest's `waits`, refused for any other module and for a wildcard. The controller grants the runtime's account a plain subscription on those subjects alone, makes no durable consumer for them, and issues the same list in the tool runner's membership, so the grant and what `mesh_wait` offers come from one composition and no call or setting widens it. A family on a seat whose events end in a kind or an asker must name it, and is refused at composition without it, so it is never granted a subject nothing publishes on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
44 lines
2.1 KiB
Go
44 lines
2.1 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// novox/hq ADR 0367 §2: the tool runner's module names, one by one, the event families a session may wait on.
|
|
func TestTheToolRunnerMayNameTheEventsASessionWaitsOn(t *testing.T) {
|
|
m, err := ParseManifest([]byte(`{"module":"node-tools","version":"1",` +
|
|
`"waits":["mesh-knowledge.reviewed","operator-channel.decided.claude-code"]}`))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(m.Waits) != 2 || m.Waits[1] != "operator-channel.decided.claude-code" {
|
|
t.Fatalf("waits not read: %v", m.Waits)
|
|
}
|
|
}
|
|
|
|
// A family is named one by one, never by a wildcard, and only by the tool runner's module (ADR 0367 §2, §6):
|
|
// each refusal is said in the manifest's words, at parse, rather than at the composition of the bus's users.
|
|
func TestAWaitIsRefusedUnlessItNamesOneFamilyOfTheToolRunner(t *testing.T) {
|
|
for manifest, want := range map[string]string{
|
|
`{"module":"shop","version":"1","waits":["mesh-knowledge.reviewed"]}`: "only node-tools",
|
|
`{"module":"node-tools","version":"1","waits":["mesh-knowledge.*"]}`: "never a wildcard",
|
|
`{"module":"node-tools","version":"1","waits":["**"]}`: "never a wildcard",
|
|
`{"module":"node-tools","version":"1","waits":["mesh-knowledge.>"]}`: "never a wildcard",
|
|
`{"module":"node-tools","version":"1","waits":["*.reviewed"]}`: "never a wildcard",
|
|
`{"module":"node-tools","version":"1","waits":["reviewed"]}`: "does not name an emitter and an event",
|
|
`{"module":"node-tools","version":"1","waits":["mesh-knowledge..reviewed"]}`: "does not name an emitter and an event",
|
|
`{"module":"node-tools","version":"1","waits":["Mesh-Knowledge.reviewed x"]}`: "does not name an emitter and an event",
|
|
`{"module":"node-tools","version":"1","waits":["a.b","a.b"]}`: "twice",
|
|
} {
|
|
_, err := ParseManifest([]byte(manifest))
|
|
if err == nil {
|
|
t.Errorf("accepted: %s", manifest)
|
|
continue
|
|
}
|
|
if !strings.Contains(err.Error(), want) {
|
|
t.Errorf("%s refused for the wrong reason (want %q): %v", manifest, want, err)
|
|
}
|
|
}
|
|
}
|