diff --git a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/bus_test.go b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/bus_test.go index a33421423..d52c1e910 100644 --- a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/bus_test.go +++ b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/bus_test.go @@ -100,7 +100,7 @@ func newTestBus(t *testing.T) *testBus { // The streams the events are on (mesh.mod..event., mesh.seat..event.). if _, err := js.CreateStream(context.Background(), jetstream.StreamConfig{Name: "EVENTS", Subjects: []string{"mesh.seat.git.event.>", "mesh.seat." + oc.Seat + ".event.>", - "mesh.mod." + forgeBridgeModule + ".event.>"}}); err != nil { + "mesh.mod.mesh-delivery-forge-bridge.event.>"}}); err != nil { t.Fatal(err) } return b diff --git a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/consumer.go b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/consumer.go index 33f55c13d..ae74e5266 100644 --- a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/consumer.go +++ b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/consumer.go @@ -12,6 +12,7 @@ package main import ( "encoding/json" "fmt" + ownmanifest "mesh-delivery-gate" "strings" "sync" "time" @@ -48,12 +49,37 @@ type stepFamily struct { // The step events on main the record is built from. A family is added here, with its `consumes` line, when its owner // publishes it (design 47 *What each step says*); each other step's event is its owner's to add in the same milestone. var stepFamilies = []stepFamily{ - // An entry taken in (the indexer's own `take-in.taken`, ADR 0633 §1): the merges a source revision took in. - {Pattern: indexerModule + "." + takein.TakeInTakenEvent, Owner: indexerModule, Event: takein.TakeInTakenEvent, Decode: decodeTakenIn}, + // An entry taken in (the holder of the seat mesh-catalog's own `take-in.taken`, ADR 0633 §1): the merges a source + // revision took in. Its owner is the one the manifest consumes it from. + family(takein.TakeInTakenEvent, decodeTakenIn), } -// indexerModule is the holder of the seat mesh-catalog whose own events the record hears. -const indexerModule = "mesh-delivery-indexer" +// family is a step family of an event as the manifest consumes it: `.`. +func family(event string, decode func(json.RawMessage, time.Time) ([]StepOutcome, error)) stepFamily { + pattern := declared(event) + owner, _, _ := strings.Cut(pattern, ".") + return stepFamily{Pattern: pattern, Owner: owner, Event: event, Decode: decode} +} + +// consumed is what the gate's manifest consumes (its own manifest): every event it follows is one of them. +var consumed = func() []string { + c, err := ownmanifest.Consumes() + if err != nil { + panic(err) + } + return c +}() + +// declared is the event the manifest consumes under this name after its owner, `.`: the gate names no +// other module in code. Empty, and so never followed or matched, when the manifest consumes none. +func declared(event string) string { + for _, c := range consumed { + if _, name, ok := strings.Cut(c, "."); ok && name == event { + return c + } + } + return "" +} // stepPatterns are the patterns of every family, in the order the manifest consumes them. func stepPatterns() []string { diff --git a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/manifest_test.go b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/manifest_test.go index e61ec7458..16147a69d 100644 --- a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/manifest_test.go +++ b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/manifest_test.go @@ -93,6 +93,27 @@ func TestItClaimsTheDeliverySeatAndFollowsWhatItHandles(t *testing.T) { t.Errorf("the manifest still consumes %s (ADR 0539 §17)", c) } } + // The names move (milestone 47/G): the families heard from another module are its manifest's consumes, and no Go + // source of the gate names those modules. + if !slices.Contains(m.Consumes, owedEndedEvent) || owedEndedEvent == "" || len(stepFamilies) != 1 || + !slices.Contains(m.Consumes, stepFamilies[0].Pattern) || stepFamilies[0].Owner+"."+stepFamilies[0].Event != stepFamilies[0].Pattern { + t.Fatalf("owed.ended is %q and the step families %+v, not the manifest's consumes %v", owedEndedEvent, stepFamilies, m.Consumes) + } + sources, _ := filepath.Glob("*.go") + for _, f := range sources { + if strings.HasSuffix(f, "_test.go") { + continue + } + raw, err := os.ReadFile(f) + if err != nil { + t.Fatal(err) + } + for _, name := range []string{`"mesh-delivery-indexer`} { + if strings.Contains(string(raw), name) { + t.Errorf("%s names %s in code: it is the manifest's to say", f, name) + } + } + } if !reflect.DeepEqual(m.Consumes, followed) || !slices.Contains(m.Consumes, "mesh-delivery-forge-bridge.forge.**") { t.Fatalf("consumes %v, follows %v (the bridge's forge messages among them)", m.Consumes, followed) } diff --git a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/owedended.go b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/owedended.go index 46039cc45..5efc1c744 100644 --- a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/owedended.go +++ b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/owedended.go @@ -10,8 +10,8 @@ import ( ) // owedEndedEvent is the forge bridge's word on an act owed, owed.ended on its stream forge (design 47 *What the gate owes -// the forge*): the outcome of one id, the gate's own or the checker's. -const owedEndedEvent = forgeBridgeModule + "." + forgemsg.OwedEndedEvent +// the forge*): the outcome of one id, the gate's own or the checker's. Its owner is the one the manifest consumes it from. +var owedEndedEvent = declared(forgemsg.OwedEndedEvent) // OwedEnded takes the forge bridge's outcome of one act this owner said as owed. The outcome is written into the delivery // record that holds the pull request at that head, and only then is the act answered: taken off its delivery's or group's diff --git a/modules/mesh-delivery-gate/manifest.go b/modules/mesh-delivery-gate/manifest.go new file mode 100644 index 000000000..a6214ed30 --- /dev/null +++ b/modules/mesh-delivery-gate/manifest.go @@ -0,0 +1,23 @@ +// Package gate holds the delivery gate's own manifest, so its code takes from the manifest's declarations what it hears, +// never another module's name written in code. +package gate + +import ( + _ "embed" + "encoding/json" + "fmt" +) + +//go:embed module.json +var manifest []byte + +// Consumes is what the gate's manifest consumes, in its order. +func Consumes() ([]string, error) { + var m struct { + Consumes []string `json:"consumes"` + } + if err := json.Unmarshal(manifest, &m); err != nil { + return nil, fmt.Errorf("the gate's own manifest is not readable: %w", err) + } + return m.Consumes, nil +}