Event names are checked now, per manifest and across the catalogue
Issue 127 stood because nothing compared the two halves. Every manifest was well-formed on its own and every derivation correct on its own, and no cross-module subscription in the mesh matched anything — a subscription that matches nothing is not an error, it is silence. Two checks, because the mistake is possible at two scales. Per manifest: an event is a local name, and `module.` is refused with the name to write instead. A module emitting under what reads as another module's name is refused too, pointing at the seat, where a name outlives whoever holds it. Across the catalogue: where a consumed event's emitter is present, it must emit that event. It cannot demand a live emitter for everything — a module lives in its own repository and may be installed long before the one whose events it wants — so the rule is narrower and still catches this. It found two real dangling subscriptions the moment it ran. Wildcards were undecided and two manifests needed them: `*` is one name and `**` is the rest, spelled the mesh's way and derived to `>` here and `#` on the old bus. A manifest naming either would stop being true when the wire changed, which is the whole reason names are local. And the field documentation taught the old form, examples included — which is why the drift was uniform across 37 manifests rather than scattered. Nobody was guessing; everybody followed the comment.
This commit is contained in:
@@ -176,15 +176,29 @@ type Manifest struct {
|
||||
// Requires are names that must be provided by something assigned to the same node.
|
||||
Requires []string `json:"requires,omitempty"`
|
||||
|
||||
// Emits are the event types this module publishes onto the broker — dotted topic keys, e.g.
|
||||
// "module.umami.site.created". Declared so the mesh knows the event graph; events are
|
||||
// provisioning's lighter sibling — 1:many and broadcast, no credential (novox/hq ADR 0041).
|
||||
// Emits are the events this module publishes, named **locally**: `order.placed`, not a subject
|
||||
// and not a routing key. The mesh derives where it lands (design 29 §1), so reorganising the
|
||||
// subject space leaves this manifest correct. Events are provisioning's lighter sibling — 1:many
|
||||
// and broadcast, no credential (novox/hq ADR 0041).
|
||||
//
|
||||
// A module publishes under its own name only. If the event is about a *role* rather than about
|
||||
// this module, it belongs on that seat, where the name outlives whoever holds it.
|
||||
//
|
||||
// **This said "dotted topic keys, e.g. module.umami.site.created" until 04-ISSUES/127**, which
|
||||
// is the old bus's routing key, and is why every manifest in the catalogue had the same mistake:
|
||||
// nobody was guessing, everybody followed this comment.
|
||||
Emits []string `json:"emits,omitempty"`
|
||||
|
||||
// Consumes are the event patterns this module subscribes to — topic patterns over module,
|
||||
// mesh and node events alike, e.g. "node.*.joined" or "#" (the audit logger). The runtime
|
||||
// wires the subscription; the module ships the handler. A Consumes for an event nothing on
|
||||
// the mesh Emits is a dangling edge.
|
||||
// Consumes are the events this module reacts to, each naming its emitter and the event:
|
||||
// `billing.order.placed`. `*` stands for one name and `**` for the rest, so `*.download.completed`
|
||||
// is that event from any module and `**` is every event in the mesh.
|
||||
//
|
||||
// Spelled the mesh's way rather than the wire's, for the reason Emits is: the bus the mesh runs
|
||||
// on today spells these `*` and `#`, the one being built spells them `*` and `>`, and a manifest
|
||||
// naming either would stop being true when the wire changed.
|
||||
//
|
||||
// The runtime wires the subscription; the module ships the handler. A Consumes for an event
|
||||
// nothing on the mesh Emits is a dangling edge.
|
||||
Consumes []string `json:"consumes,omitempty"`
|
||||
|
||||
// Claims are singular resources. Two modules claiming one thing within a scope cannot both
|
||||
@@ -999,6 +1013,10 @@ func ParseManifest(raw []byte) (Manifest, error) {
|
||||
problems = append(problems, fmt.Sprintf("%s requires itself", m.Module))
|
||||
}
|
||||
}
|
||||
// What it may call an event, and what it may ask to hear (events.go). Checked here because a
|
||||
// module whose event names are wrong installs, starts, connects and reacts to nothing, with
|
||||
// every log line saying it is fine (novox/hq 04-ISSUES/127).
|
||||
problems = append(problems, EventProblems(m)...)
|
||||
wellFormed := true
|
||||
for _, c := range m.Claims {
|
||||
if !name.MatchString(c.Name) {
|
||||
|
||||
Reference in New Issue
Block a user