Issue 1585, S19: the strict parser, every manifest problem function and the judge's tables (192 declarations, about 5,200 lines) and their 244 tests leave; composition keeps its own refusals and the helpers it uses. The catalogue's tests decode the manifests they build. ParseManifest, ParseManifestWith, ParseManifestForInputs, CatalogueProblems and the rest are gone; mesh-delivery-indexer/judge holds them. Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
73 lines
3.4 KiB
Go
73 lines
3.4 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"regexp"
|
|
"slices"
|
|
)
|
|
|
|
// What a module may call an event, and what a consumer may ask for.
|
|
//
|
|
// A module names an event **locally**: `order.placed`, not a subject and not a routing key
|
|
// (design 29 §1). A consumer names the emitter and the event: `billing.order.placed`. The mesh
|
|
// derives the subject from those, so reorganising the subject space leaves every manifest correct.
|
|
//
|
|
// **Nothing checked this until every manifest in the catalogue was wrong the same way**
|
|
// (novox/hq 04-ISSUES/127). All thirty-seven kept the old bus's routing key —
|
|
// `module.<module>.<verb>` — which the derivation read as "a module called `module`", so every
|
|
// cross-module subscription in the mesh pointed at a namespace nobody publishes to. Nothing failed:
|
|
// the services started and none of them reacted. The documentation on these fields taught the old
|
|
// form too, which is why the drift was uniform rather than scattered.
|
|
|
|
// eventName is one name in a local event: lower-case, and no wildcard.
|
|
var eventName = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*$`)
|
|
|
|
// The wildcards a consumer may use, spelled the mesh's way and derived to whatever the transport
|
|
// spells them as.
|
|
//
|
|
// **A manifest holds no transport token**, which is the whole point of naming locally: the bus the
|
|
// mesh runs on today spells these `*` and `#`, and the one being built spells them `*` and `>`. A
|
|
// manifest that said either would be a manifest that stopped being true when the wire changed.
|
|
const (
|
|
// OneName stands for exactly one name.
|
|
OneName = "*"
|
|
// TheRest stands for one or more names, and may only come last.
|
|
TheRest = "**"
|
|
)
|
|
|
|
// The events a provider says about its consumers (novox/hq ADR 0224): a consumer it has failed
|
|
// without one success for minutes, and that consumer succeeding again or being withdrawn. The
|
|
// controller follows them from every module and `status` names a consumer failing until it recovers.
|
|
//
|
|
// **And what becomes of a consumer the mesh stopped asking for** (novox/hq ADR 0230): retired — its
|
|
// access disabled and its data kept — after the same answer in five passes, waiting for a person when
|
|
// more would go than the bound allows, re-enabled when asked for again, and deleted only by a person's
|
|
// `cleanup delete`. One event, its `change` saying which.
|
|
const (
|
|
ProvisionerFailing = "provisioner.failing"
|
|
ProvisionerRecovered = "provisioner.recovered"
|
|
ProvisionerRetirement = "provisioner.retirement"
|
|
)
|
|
|
|
// ProvisionerEvents are all three, in the order they are said.
|
|
var ProvisionerEvents = []string{ProvisionerFailing, ProvisionerRecovered, ProvisionerRetirement}
|
|
|
|
// EmitsAll is every event a module may publish: what it declares and, for a module that receives
|
|
// contributions — a provider, running a provisioner over them — the provider's standing events.
|
|
//
|
|
// **Derived, not declared**, because they are the mesh's rule about every provider rather than
|
|
// anything one module chose to say: a provider whose manifest forgot them would fail its consumers
|
|
// as silently as on 2026-10-05, with its announcement refused by the bus (novox/hq issue 179). Every
|
|
// grant of a module's publishing reads this, never the declared list alone.
|
|
func (m Manifest) EmitsAll() []string {
|
|
out := append([]string(nil), m.Emits...)
|
|
if len(m.Receives) == 0 {
|
|
return out
|
|
}
|
|
for _, e := range ProvisionerEvents {
|
|
if !slices.Contains(out, e) {
|
|
out = append(out, e)
|
|
}
|
|
}
|
|
return out
|
|
}
|