From f17001d920facafda370389283d0c1a6e59fbb50 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 12 Nov 2026 04:59:17 +0100 Subject: [PATCH] KB3: the overview hears git.pull-merged and the runner's group-ended, not the gate's group and merged MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Builds: design 47 G §431 --- .../cmd/mesh-knowledge/overview.go | 14 +++++++------- .../cmd/mesh-knowledge/overview_test.go | 16 ++++++++-------- modules/mesh-knowledge/module.json | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/modules/mesh-knowledge/cmd/mesh-knowledge/overview.go b/modules/mesh-knowledge/cmd/mesh-knowledge/overview.go index 9878134bd..88bbf9a39 100644 --- a/modules/mesh-knowledge/cmd/mesh-knowledge/overview.go +++ b/modules/mesh-knowledge/cmd/mesh-knowledge/overview.go @@ -35,7 +35,7 @@ const ( // OverviewEvents are the events the page consumes, by source, as the manifest declares them. var OverviewEvents = map[string][]string{ SourceTracker: {"mesh-issues.opened", "mesh-issues.moved", "mesh-issues.milestone-set", "mesh-issues.milestone-moved"}, - SourceDelivery: {"mesh-delivery-gate.group", "mesh-delivery-gate.transition", "mesh-delivery-gate.merged"}, + SourceDelivery: {"git.pull-merged", "mesh-delivery-gate.transition", "mesh-pipeline-runner.group-ended"}, SourceAsks: {"messenger.offered", "messenger.closed"}, } @@ -344,6 +344,7 @@ func (o *Overview) Heard(source, event string, body json.RawMessage) { Design int `json:"design"` ID string `json:"id"` Group string `json:"group"` + Branch string `json:"branch"` Outcome string `json:"outcome"` Issues []int `json:"issues"` Members []string `json:"members"` @@ -383,18 +384,17 @@ func (o *Overview) Heard(source, event string, body json.RawMessage) { case SourceDelivery: id := firstNonEmpty(f.Group, f.ID) switch name { - case "group": - g := o.groups[id] - g.ID, g.State, g.Why = id, firstNonEmpty(f.State, f.To, g.State), firstNonEmpty(f.Why, g.Why) - g.Members = firstStrings(f.Members, g.Members) - o.groups[id] = g + case "pull-merged": + // A merged pull request leaves the group named by its head branch (a group's id is its branch name): it waits for + // the operator no longer (design 47 G §431). + delete(o.groups, f.Branch) case "transition": if g, ok := o.groups[id]; ok { g.State = firstNonEmpty(f.To, f.State, g.State) g.Why = firstNonEmpty(f.Why, g.Why) o.groups[id] = g } - case "merged": + case "group-ended": delete(o.groups, id) } case SourceAsks: diff --git a/modules/mesh-knowledge/cmd/mesh-knowledge/overview_test.go b/modules/mesh-knowledge/cmd/mesh-knowledge/overview_test.go index 262d4a0e6..646ac6f92 100644 --- a/modules/mesh-knowledge/cmd/mesh-knowledge/overview_test.go +++ b/modules/mesh-knowledge/cmd/mesh-knowledge/overview_test.go @@ -25,7 +25,7 @@ func newOverviewWorld(t *testing.T) *overviewWorld { w := &overviewWorld{now: time.Date(2026, 11, 4, 12, 0, 0, 0, time.UTC), fail: map[string]bool{}, answers: map[string]string{ TrackerMilestonesVerb: `{"milestones":[{"design":47,"id":"1","outcome":"A merge is never dropped","status":"open","issues":[973,525]},{"design":47,"id":"2","outcome":"Done thing","status":"done","issues":[1]}]}`, TrackerListVerb: `[{"number":973,"title":"The window","status":"fixing"},{"number":525,"title":"The queue","status":"open"}]`, - DeliveryGroupsVerb: `[{"id":"fix/a","state":"held","why":"a member is held","members":["x@1"]}]`, + DeliveryGroupsVerb: `[{"id":"fix/a","state":"held","why":"a member is held","members":["x@1"]},{"id":"fix/b","state":"checking","members":["y@2"]}]`, AsksVerb: `{"asks":[{"key":"mesh-knowledge.1","asker":"mesh-knowledge","headline":"Approve ADR 0301","state":"open","offered_on":["telegram"]},{"key":"ask-0","asker":"x","headline":"old","state":"answered"}]}`, }} w.o = NewOverview(func(key string, body any) (json.RawMessage, error) { @@ -68,7 +68,7 @@ func TestThePageModelHasThreeBlocksKeptByEventsAndAsksNoVerbAgain(t *testing.T) t.Fatalf("the design block: %+v", m.Designs) } if len(m.Accepted) != 2 || len(m.Waiting) != 2 || len(m.Operator.Records) != 1 || m.Operator.Records[0].Record != "ADR 0303" || - len(m.Operator.Asks) != 1 || m.Operator.Asks[0].Key != "mesh-knowledge.1" || len(m.Operator.Groups) != 1 { + len(m.Operator.Asks) != 1 || m.Operator.Asks[0].Key != "mesh-knowledge.1" || len(m.Operator.Groups) != 2 { t.Fatalf("%+v", m) } asked := map[string]int{} @@ -76,20 +76,20 @@ func TestThePageModelHasThreeBlocksKeptByEventsAndAsksNoVerbAgain(t *testing.T) asked[v] = w.o.Calls(v) } // Events change the blocks. - w.o.Heard(SourceDelivery, "mesh-delivery-gate.group", json.RawMessage(`{"group":"fix/b","state":"checking","members":["y@2"]}`)) + w.o.Heard(SourceDelivery, "git.pull-merged", json.RawMessage(`{"repository":"novox/y","number":2,"branch":"fix/b"}`)) w.o.Heard(SourceDelivery, "mesh-delivery-gate.transition", json.RawMessage(`{"group":"fix/a","to":"approved"}`)) w.o.Heard(SourceAsks, "messenger.offered", json.RawMessage(`{"id":"2","asker":"mesh-delivery","headline":"Approve the group","channels":["telegram"]}`)) w.o.Heard(SourceTracker, "mesh-issues.opened", json.RawMessage(`{"number":1999,"title":"New","status":"open"}`)) w.o.Heard(SourceTracker, "mesh-issues.milestone-moved", json.RawMessage(`{"design":47,"id":"1","to":"done","issues":[973,525,1999]}`)) m, _ = w.o.Model() - if len(m.Operator.Groups) != 2 || m.Operator.Groups[0].State != "approved" || len(m.Operator.Asks) != 2 || len(m.Designs) != 0 { + if len(m.Operator.Groups) != 1 || m.Operator.Groups[0].State != "approved" || len(m.Operator.Asks) != 2 || len(m.Designs) != 0 { t.Fatalf("after the events: %+v", m) } - w.o.Heard(SourceDelivery, "mesh-delivery-gate.merged", json.RawMessage(`{"group":"fix/a"}`)) + w.o.Heard(SourceDelivery, "mesh-pipeline-runner.group-ended", json.RawMessage(`{"group":"fix/a","branch":"main","outcome":"passed"}`)) w.o.Heard(SourceAsks, "messenger.closed", json.RawMessage(`{"id":"1","asker":"mesh-knowledge","how":"answered"}`)) m, _ = w.o.Model() - if len(m.Operator.Groups) != 1 || m.Operator.Groups[0].ID != "fix/b" || len(m.Operator.Asks) != 1 || m.Operator.Asks[0].Key != "mesh-delivery.2" { - t.Fatalf("after merged and closed: %+v", m.Operator) + if len(m.Operator.Groups) != 0 || len(m.Operator.Asks) != 1 || m.Operator.Asks[0].Key != "mesh-delivery.2" { + t.Fatalf("after the group ended and the ask closed: %+v", m.Operator) } for v, n := range asked { if w.o.Calls(v) != n { @@ -146,7 +146,7 @@ func TestASourceThatDoesNotAnswerIsSaidAndAskedAgainOnABackoff(t *testing.T) { w.now = w.o.state[SourceDelivery].Mark.Next w.o.Due() m, _ = w.o.Model() - if len(w.o.Unanswered()) != 0 || len(m.Operator.Groups) != 1 { + if len(w.o.Unanswered()) != 0 || len(m.Operator.Groups) != 2 { t.Fatalf("%+v", m) } // A subscription that goes silent marks the source from the subscription and asks nothing while it is silent. diff --git a/modules/mesh-knowledge/module.json b/modules/mesh-knowledge/module.json index c765e2862..0382b6308 100644 --- a/modules/mesh-knowledge/module.json +++ b/modules/mesh-knowledge/module.json @@ -217,9 +217,9 @@ "mesh-issues.moved", "mesh-issues.milestone-set", "mesh-issues.milestone-moved", - "mesh-delivery-gate.group", + "git.pull-merged", "mesh-delivery-gate.transition", - "mesh-delivery-gate.merged", + "mesh-pipeline-runner.group-ended", "messenger.offered", "messenger.closed", "mesh-conditions.findings-asked"