Pin the gate to mesh-sdk's release 6 verb tables and prove it holds the seat as they have it (issue 1946, R6-C3)

The integration tests hear the forge's own word that a pull request merged, as the real flow does, and fail on any call of the controller.
This commit is contained in:
2026-10-24 16:35:15 +02:00
parent 5ff337e0dc
commit 30d04f6bef
7 changed files with 50 additions and 28 deletions
@@ -584,6 +584,8 @@ func TestAPassingVerdictAsksTheApproveAndItsApproveMergesWithinSecondsOverARealB
// The bridge says it merged; the mesh's source then holds the merge, in one write.
b.forgeSays(t, sdk.Forge{Kind: sdk.ForgeMerged, Repository: "novox/app", Number: 7, Head: head, Merge: strings.Repeat("b", 40),
Root: "r", Trees: map[string]string{"app": "t"}})
// The forge's own word that the pull request merged follows the bridge's (its webhook): the delivery ends merged.
b.publish(t, "mesh.mod.gitea.event.pull.merged", merged("novox/app", 7, head, strings.Repeat("b", 40)))
rt.until("source.main to hold the merge", eventWithin, func() bool {
e, err := b.kvs["source"].Get(ctx, sdk.SourceMainKey)
if err != nil {
@@ -742,6 +744,7 @@ func TestAGroupOfTwoWithGreenChecksGetsOneAskAndOnItsApproveBothMergeOneAfterThe
one := first.Pulls[0]
b.forgeSays(t, sdk.Forge{Kind: sdk.ForgeMerged, Repository: one.Repository, Number: one.Number, Head: one.Head.Head,
Merge: strings.Repeat("a", 40), Root: "r", Trees: map[string]string{"x": "t"}})
b.publish(t, "mesh.mod.gitea.event.pull.merged", merged(one.Repository, one.Number, one.Head.Head, strings.Repeat("a", 40)))
var both sdk.Merge
rt.until("the second member to be handed", eventWithin, func() bool { both = mergeAt(b, "feat/x"); return len(both.Pulls) == 2 })
if both.Pulls[0].State != sdk.MergeMerged || both.Pulls[1].State != sdk.MergeMerging || both.Pulls[1].Repository == one.Repository {
@@ -750,6 +753,7 @@ func TestAGroupOfTwoWithGreenChecksGetsOneAskAndOnItsApproveBothMergeOneAfterThe
two := both.Pulls[1]
b.forgeSays(t, sdk.Forge{Kind: sdk.ForgeMerged, Repository: two.Repository, Number: two.Number, Head: two.Head.Head,
Merge: strings.Repeat("b", 40), Root: "r", Trees: map[string]string{"x": "t"}})
b.publish(t, "mesh.mod.gitea.event.pull.merged", merged(two.Repository, two.Number, two.Head.Head, strings.Repeat("b", 40)))
rt.until("source.main to hold both merges", eventWithin, func() bool {
e, err := b.kvs["source"].Get(ctx, sdk.SourceMainKey)
if err != nil {
@@ -12,11 +12,10 @@ import (
// **The gate is the only claimant of the seat `mesh-delivery` in the catalogue** (novox/hq ADR 0437 §1, ADR 0449 §4, ADR 0454,
// issue 1351; how it is checked). Today's module `modules/mesh-delivery` was removed by a pull request of its own after the
// handover, so the claimants are exactly one. And no manifest but the gate's and mesh-issues' names the old module in what it
// reads or hears, but through the seat's name (`mesh-delivery` as a seat or a repository, `seat:mesh-delivery.<verb>`) and the
// names below: the three buckets the gate carries over (ADR 0450 §6). The event `mesh-delivery.transition` is no longer heard by anyone (issue 1406).
var oldModuleNames = map[string][]string{
"mesh-delivery-gate": {"mesh-delivery.deliveries", "mesh-delivery.groups", "mesh-delivery.pulls"},
}
// reads or hears, but through the seat's name (`mesh-delivery` as a seat or a repository, `seat:mesh-delivery.<verb>`). The
// three buckets the gate once carried over (ADR 0450 §6) went with the carry (ADR 0539 §17), and the event
// `mesh-delivery.transition` is heard by no one (issue 1406).
var oldModuleNames = map[string][]string{}
// seatClaimants are the modules that claim the seat: the gate alone.
var seatClaimants = []string{"mesh-delivery-gate"}
@@ -877,9 +877,6 @@ func (h *Holder) plan() []func() {
return asks
}
// askedCheck is whether a proposed delivery's own check stands asked: a kept ask with no id is none.
func askedCheck(d *Delivery) bool { return d.CheckAsk != nil && d.CheckAsk.ID != "" }
// askChecks reads the forge's open pull requests once for the proposed deliveries with no verdict (issue 1115), and takes the
// checker's mesh/check where one stands on a head (issue 1302); the base's required statuses are kept. Nothing is asked of
// the controller: the checker checks every head on every move (ADR 0447 §4, issue 1318). Under the lock; the read runs outside it.
@@ -1088,9 +1085,3 @@ func containsString(xs []string, x string) bool {
}
return false
}
// refusedAfter is whether a member's merge, not yet merged, was refused by the merge tool in a try made at or after at.
func refusedAfter(d *Delivery, at time.Time) bool {
r := d.Ready
return r != nil && r.Merged == nil && d.MergedAs == "" && r.RefusedSince != nil && !r.LastTry.Before(at)
}
@@ -359,14 +359,3 @@ func TestGroupsNamesEachMembersPullRequestHeadBaseAndOpen(t *testing.T) {
}
}
}
// composed are the asks of a group's composed check among the checks asked: a member's own check has no group before its colon.
func composed(checks []string) []string {
var out []string
for _, c := range checks {
if !strings.HasPrefix(c, ":") {
out = append(out, c)
}
}
return out
}
@@ -10,6 +10,8 @@ import (
"strings"
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The manifest says what the code does: the seat it claims and the verbs it serves, the events it follows
@@ -202,3 +204,40 @@ func TestARowWrittenWithTheReadyMarkStillReads(t *testing.T) {
t.Fatalf("the old row is not read: %+v", d.Ready)
}
}
// R6-C3 (ADR 0539 §17): the gate holds the seat as the SDK's table of release 6 has it. Every verb of the table that is not
// optional is served; the verbs release 6 removed are optional rows the SDK answers by name, and the gate serves none of them;
// and the SDK's own test of whether a module can hold a seat (CanHold) finds nothing missing or unpromised.
func TestTheGateHoldsTheSeatAsTheSDKsTableOfRelease6HasIt(t *testing.T) {
_, raw := readManifest(t)
manifest, err := catalogue.ParseManifest([]byte(raw))
if err != nil {
t.Fatalf("the SDK this module pins cannot read its manifest: %v", err)
}
seat, ok := catalogue.SeatNamed("mesh-delivery")
if !ok {
t.Fatal("the SDK this module pins names no seat mesh-delivery")
}
if err := catalogue.CanHold(manifest, seat); err != nil {
t.Fatalf("the gate cannot hold the seat of the SDK it pins: %v", err)
}
served := map[string]bool{}
for _, tool := range tools(&Holder{}, &listening{}) {
if _, verb, ok := strings.Cut(tool.Name, "."); ok {
served[verb] = true
}
}
for removed := range catalogue.RemovedDeliveryVerbs {
if served[removed] {
t.Errorf("the gate serves %s, which release 6 removed: the SDK answers it by name", removed)
}
if slices.Contains(manifest.Claims[0].Serves, removed) {
t.Errorf("the manifest serves %s, which release 6 removed", removed)
}
}
for _, verb := range []string{"deliveries", "show", "groups", "checks", "table", "stalled", "recheck", "close"} {
if !served[verb] {
t.Errorf("the gate does not serve %s, which the seat keeps", verb)
}
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-gate
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261022190740-104533e8c0c9
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024143211-d506f2196a7c
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2 -2
View File
@@ -1,5 +1,5 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261022190740-104533e8c0c9 h1:Ufmd2cYEXICQ817IGflccP9bexABE4WhIO49HPbaoSo=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261022190740-104533e8c0c9/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024143211-d506f2196a7c h1:WwOv9KGSaZh38Pbz2tGVXFMn5girjUZvjHG+8xYSY0o=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261024143211-d506f2196a7c/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=