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) } } }