Move the delivery module to the gate: mesh-delivery-gate claims the seat with its own buckets and reads (issue 1346)
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
# mesh-delivery
|
||||
# mesh-delivery-gate
|
||||
|
||||
The `mesh-delivery` module of the mesh catalogue: claims the seat `mesh-delivery`.
|
||||
The `mesh-delivery-gate` module of the mesh catalogue: the gate of design 47. It claims the seat `mesh-delivery`, whose
|
||||
name stays (ADR 0437 §11), and takes over from the module `mesh-delivery` (ADR 0437 §3, ADR 0450 §6). Its buckets are
|
||||
`mesh-delivery-gate_*`.
|
||||
|
||||
## Files it does not know
|
||||
|
||||
+7
-3
@@ -27,8 +27,12 @@ import (
|
||||
//
|
||||
// The terminal Approve (ADR 0398 §3) is issue 953; today the proving channel is the operator's phone.
|
||||
|
||||
// Module is this module's name: the one the bus grants its asks under.
|
||||
const Module = "mesh-delivery"
|
||||
// Module is this module's name: the one the bus names its buckets and events under (novox/hq ADR 0437 §3). Seat is
|
||||
// the seat it claims, whose name stays `mesh-delivery` (ADR 0437 §11).
|
||||
const (
|
||||
Module = "mesh-delivery-gate"
|
||||
Seat = "mesh-delivery"
|
||||
)
|
||||
|
||||
// The two answers, both at the level approve.
|
||||
const (
|
||||
@@ -61,7 +65,7 @@ func headsString(heads map[string]string) string {
|
||||
|
||||
// mergeAct is what an answer binds: this ask, the answer, and the heads it covers.
|
||||
func mergeAct(ask, option string, heads map[string]string) asks.Act {
|
||||
return asks.Act{"verb": Module + ".merge", "ask": ask, "option": option, "heads": headsString(heads)}
|
||||
return asks.Act{"verb": Seat + ".merge", "ask": ask, "option": option, "heads": headsString(heads)}
|
||||
}
|
||||
|
||||
var unshownPath = regexp.MustCompile(`[/\\@~$]|\d+\.\d+\.\d+|[A-Za-z0-9+/=_]{24,}|(?i)\b[a-z0-9-]+\.[a-z]{2,12}\b`)
|
||||
+2
-2
@@ -75,7 +75,7 @@ func newTestBus(t *testing.T) *testBus {
|
||||
b := &testBus{nc: nc, js: js, kvs: map[string]jetstream.KeyValue{}}
|
||||
// The controller's job: a bucket per state the manifest declares.
|
||||
m, _ := readManifest(t)
|
||||
for _, name := range m.State {
|
||||
for _, name := range m.buckets() {
|
||||
kv, err := js.CreateKeyValue(context.Background(), jetstream.KeyValueConfig{Bucket: m.Module + "_" + name, History: 1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -121,7 +121,7 @@ type askedOfMesh struct {
|
||||
func (b *testBus) start(t *testing.T) *runtime {
|
||||
t.Helper()
|
||||
cmd := exec.Command(os.Args[0], "-test.run=^$")
|
||||
cmd.Env = append(os.Environ(), bundleVar+"=1", "MESH_SERVED_MODULE=mesh-delivery", "MESH_MODULE=mesh-delivery", "MESH_NODE=test")
|
||||
cmd.Env = append(os.Environ(), bundleVar+"=1", "MESH_SERVED_MODULE=mesh-delivery-gate", "MESH_MODULE=mesh-delivery-gate", "MESH_NODE=test")
|
||||
in, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
// mesh-delivery: the holder of the mesh-delivery seat (novox/hq ADR 0239, to-be 47). A Go bundle the node's
|
||||
// mesh-delivery-gate: the holder of the mesh-delivery seat (novox/hq ADR 0239, to-be 47). A Go bundle the node's
|
||||
// runtime launches. It owns the delivery — one commit in one repository, from its pull request's head to
|
||||
// every machine — and the delivery group above it: their states in one compiled table, kept in its own state
|
||||
// on the bus, every transition said as an event, noted on the commit and shown on the pull request through
|
||||
@@ -246,7 +246,7 @@ func need(a map[string]any, keys ...string) error {
|
||||
}
|
||||
|
||||
func tools(h *Holder, l *listening) []stdio.Tool {
|
||||
seat := "mesh-delivery."
|
||||
seat := Seat + "."
|
||||
list := []stdio.Tool{
|
||||
{Name: seat + "deliveries",
|
||||
Description: "Every delivery not final, those that ended in the last day, and any stop `stalled` still lists, one line each: its id " +
|
||||
+39
-16
@@ -26,10 +26,25 @@ type manifest struct {
|
||||
Consumes []string `json:"consumes"`
|
||||
Emits []string `json:"emits"`
|
||||
Invokes []string `json:"invokes"`
|
||||
State []string `json:"state"`
|
||||
State []any `json:"state"`
|
||||
Reads []string `json:"reads"`
|
||||
Tools []string `json:"tools"`
|
||||
}
|
||||
|
||||
// buckets are the names of the state the manifest declares, each a bare name or an object with a name and a history.
|
||||
func (m manifest) buckets() []string {
|
||||
var out []string
|
||||
for _, s := range m.State {
|
||||
switch v := s.(type) {
|
||||
case string:
|
||||
out = append(out, v)
|
||||
case map[string]any:
|
||||
out = append(out, v["name"].(string))
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func readManifest(t *testing.T) (manifest, string) {
|
||||
t.Helper()
|
||||
raw, err := os.ReadFile(filepath.Join("..", "..", "module.json"))
|
||||
@@ -45,35 +60,43 @@ func readManifest(t *testing.T) (manifest, string) {
|
||||
|
||||
func TestItClaimsTheDeliverySeatAndFollowsWhatItHandles(t *testing.T) {
|
||||
m, raw := readManifest(t)
|
||||
if m.Module != "mesh-delivery" || len(m.Claims) != 1 || m.Claims[0].Name != "mesh-delivery" || m.Claims[0].Scope != "mesh" {
|
||||
if m.Module != "mesh-delivery-gate" || len(m.Claims) != 1 || m.Claims[0].Name != "mesh-delivery" || m.Claims[0].Scope != "mesh" {
|
||||
t.Fatalf("claims %+v", m.Claims)
|
||||
}
|
||||
// The seat is the mesh's own (mesh-*): a module claims it and never declares it.
|
||||
if len(m.Seats) != 0 {
|
||||
t.Fatal("the manifest declares a seat; mesh-delivery is the mesh's own")
|
||||
}
|
||||
if !reflect.DeepEqual(m.Consumes, followed) {
|
||||
t.Fatalf("consumes %v, follows %v", m.Consumes, followed)
|
||||
// The thirteen verbs of the seat (ADR 0437 §3, §11).
|
||||
if len(m.Claims[0].Serves) != 13 {
|
||||
t.Fatalf("serves %d verbs, wanted 13: %v", len(m.Claims[0].Serves), m.Claims[0].Serves)
|
||||
}
|
||||
if !reflect.DeepEqual(m.Consumes, append(append([]string{}, followed...), "mesh-delivery-forge-bridge.forge.**")) {
|
||||
t.Fatalf("consumes %v, follows %v and the bridge's forge messages", m.Consumes, followed)
|
||||
}
|
||||
if !reflect.DeepEqual(m.Emits, []string{"transition", "group", "merged"}) {
|
||||
t.Fatalf("emits %v", m.Emits)
|
||||
}
|
||||
if !reflect.DeepEqual(m.State, []string{"deliveries", "groups", "asked", "pulls"}) {
|
||||
t.Fatalf("state %v", m.State)
|
||||
// Seven buckets, and no `asked` (the teller asks, ADR 0437 §6): ADR 0450 §3.
|
||||
buckets := m.buckets()
|
||||
if !reflect.DeepEqual(buckets, []string{"deliveries", "groups", "pulls", "asks", "merges", "owed", "source"}) {
|
||||
t.Fatalf("state %v", buckets)
|
||||
}
|
||||
// It calls exactly what its ports ask: the controller's verbs and the forge's tools.
|
||||
// What it reads: the carry from today's module's three buckets, the teller's answers, the seat's holder and the
|
||||
// machines' haves (ADR 0450 §6 and its insight of 2026-10-20).
|
||||
if !reflect.DeepEqual(m.Reads, []string{"mesh-delivery.deliveries", "mesh-delivery.groups", "mesh-delivery.pulls",
|
||||
"mesh-delivery-teller.answers", "mesh-controller.assignments", "node-engine.have"}) {
|
||||
t.Fatalf("reads %v", m.Reads)
|
||||
}
|
||||
// It calls exactly the controller's seven verbs (ADR 0450 §7) and reads the forge with three tools; the forge's
|
||||
// writes are the bridge's (ADR 0437 §8). It uses no operator-channel: the teller asks (ADR 0437 §6).
|
||||
want := []string{}
|
||||
for _, v := range []string{"delivery-plan", "delivery-check", "deliver", "delivery-backups-again", "delivery-stop", "delivery-walks", "forget-checks"} {
|
||||
for _, v := range []string{"deliver", "delivery-stop", "delivery-backups-again", "delivery-walks", "delivery-check", "forget-checks", "plans"} {
|
||||
want = append(want, "seat:"+ControllerSeat+"."+v)
|
||||
}
|
||||
want = append(want, "gitea.gitea_note_append", "gitea.gitea_delivery_view", "gitea.gitea_commit_status",
|
||||
"gitea.gitea_commit_statuses", "gitea.gitea_contains", "gitea.gitea_open_pulls",
|
||||
// The merge on a ready mark (novox/hq issue 722): the merge tool, a comment, a label taken off.
|
||||
"gitea.gitea_merge_pull_request", "gitea.gitea_add_comment")
|
||||
// A merge into main asks the operator for the Approve (novox/hq ADR 0398 §3, issue 948), as the knowledge base asks.
|
||||
want = append(want, "seat:operator-channel.notify")
|
||||
if !reflect.DeepEqual(m.Uses, []string{"operator-channel"}) {
|
||||
t.Fatalf("uses %v", m.Uses)
|
||||
want = append(want, "gitea.gitea_commit_statuses", "gitea.gitea_contains", "gitea.gitea_open_pulls")
|
||||
if len(m.Uses) != 0 {
|
||||
t.Fatalf("uses %v: the teller asks, not the gate", m.Uses)
|
||||
}
|
||||
if !reflect.DeepEqual(m.Invokes, want) {
|
||||
t.Fatalf("invokes %v, wanted %v", m.Invokes, want)
|
||||
@@ -1,22 +1,22 @@
|
||||
module mesh-delivery
|
||||
module mesh-delivery-gate
|
||||
|
||||
go 1.25.0
|
||||
go 1.26.0
|
||||
|
||||
require (
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013182924-5933eb757d44
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261019230201-5786ba190c69
|
||||
github.com/nats-io/nats-server/v2 v2.11.17
|
||||
github.com/nats-io/nats.go v1.51.0
|
||||
github.com/nats-io/nats.go v1.54.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op // indirect
|
||||
github.com/google/go-tpm v0.9.8 // indirect
|
||||
github.com/klauspost/compress v1.18.5 // indirect
|
||||
github.com/klauspost/compress v1.20.0 // indirect
|
||||
github.com/minio/highwayhash v1.0.4 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.8.1 // indirect
|
||||
github.com/nats-io/nkeys v0.4.15 // indirect
|
||||
github.com/nats-io/nkeys v0.4.16 // indirect
|
||||
github.com/nats-io/nuid v1.0.1 // indirect
|
||||
golang.org/x/crypto v0.50.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/crypto v0.57.0 // indirect
|
||||
golang.org/x/sys v0.48.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
)
|
||||
@@ -1,11 +1,15 @@
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013182924-5933eb757d44 h1:r5xIo5qWOXQdCSMxvqJy8kV4U+P/QWXFK6971Ha6wU8=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261013182924-5933eb757d44/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261019230201-5786ba190c69 h1:kvtV/SPsdRVUL/BZ3xxGS6U8YrXy/t7TRBjVrD6VLw8=
|
||||
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261019230201-5786ba190c69/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=
|
||||
github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY=
|
||||
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
|
||||
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/klauspost/compress v1.20.0 h1:a3C1ke2ohxFymNlb2HWAHjDeKCI90scRskErZkR0ezA=
|
||||
github.com/klauspost/compress v1.20.0/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
|
||||
github.com/minio/highwayhash v1.0.4 h1:asJizugGgchQod2ja9NJlGOWq4s7KsAWr5XUc9Clgl4=
|
||||
github.com/minio/highwayhash v1.0.4/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
|
||||
github.com/nats-io/jwt/v2 v2.8.1 h1:V0xpGuD/N8Mi+fQNDynXohVvp7ZztevW5io8CUWlPmU=
|
||||
@@ -14,14 +18,22 @@ github.com/nats-io/nats-server/v2 v2.11.17 h1:GKEghcFK6A+aFx11Yf1LjgLC3txAwvyhnY
|
||||
github.com/nats-io/nats-server/v2 v2.11.17/go.mod h1:B1sFVz4StNosQ903ak4N1G01Fl/9f8e06mXpFIE2K24=
|
||||
github.com/nats-io/nats.go v1.51.0 h1:ByW84XTz6W03GSSsygsZcA+xgKK8vPGaa/FCAAEHnAI=
|
||||
github.com/nats-io/nats.go v1.51.0/go.mod h1:26HypzazeOkyO3/mqd1zZd53STJN0EjCYF9Uy2ZOBno=
|
||||
github.com/nats-io/nats.go v1.54.0 h1:vsXoOxjHp/GmPUN+EcI7uOf/uB+iAP+kEsAFNQN0yzA=
|
||||
github.com/nats-io/nats.go v1.54.0/go.mod h1:y+DZoD1oBOYfZTU681eTUiUjI0vbqYGixNVFHcjHJ0k=
|
||||
github.com/nats-io/nkeys v0.4.15 h1:JACV5jRVO9V856KOapQ7x+EY8Jo3qw1vJt/9Jpwzkk4=
|
||||
github.com/nats-io/nkeys v0.4.15/go.mod h1:CpMchTXC9fxA5zrMo4KpySxNjiDVvr8ANOSZdiNfUrs=
|
||||
github.com/nats-io/nkeys v0.4.16 h1:rd5oAuLOb8mnAycB0xleuEBNS1pVVnN0fv/FF34Eypg=
|
||||
github.com/nats-io/nkeys v0.4.16/go.mod h1:llLgWoI0o4z/Q57q2R1kHfmocyhGV6VG/U18Glg1Afs=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||
golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
|
||||
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
|
||||
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"module": "mesh-delivery",
|
||||
"module": "mesh-delivery-gate",
|
||||
"version": "1",
|
||||
"slug": "deliver",
|
||||
"slug": "gate",
|
||||
"claims": [
|
||||
{
|
||||
"name": "mesh-delivery",
|
||||
@@ -31,7 +31,8 @@
|
||||
"gitea.forge.pull-request.edited",
|
||||
"gitea.forge.pull-request.closed",
|
||||
"mesh-controller.checked",
|
||||
"mesh-controller.plan-moved"
|
||||
"mesh-controller.plan-moved",
|
||||
"mesh-delivery-forge-bridge.forge.**"
|
||||
],
|
||||
"emits": [
|
||||
"transition",
|
||||
@@ -39,31 +40,46 @@
|
||||
"merged"
|
||||
],
|
||||
"invokes": [
|
||||
"seat:mesh-controller.delivery-plan",
|
||||
"seat:mesh-controller.delivery-check",
|
||||
"seat:mesh-controller.deliver",
|
||||
"seat:mesh-controller.delivery-backups-again",
|
||||
"seat:mesh-controller.delivery-stop",
|
||||
"seat:mesh-controller.delivery-backups-again",
|
||||
"seat:mesh-controller.delivery-walks",
|
||||
"seat:mesh-controller.delivery-check",
|
||||
"seat:mesh-controller.forget-checks",
|
||||
"gitea.gitea_note_append",
|
||||
"gitea.gitea_delivery_view",
|
||||
"gitea.gitea_commit_status",
|
||||
"seat:mesh-controller.plans",
|
||||
"gitea.gitea_commit_statuses",
|
||||
"gitea.gitea_contains",
|
||||
"gitea.gitea_open_pulls",
|
||||
"gitea.gitea_merge_pull_request",
|
||||
"gitea.gitea_add_comment",
|
||||
"seat:operator-channel.notify"
|
||||
],
|
||||
"uses": [
|
||||
"operator-channel"
|
||||
"gitea.gitea_open_pulls"
|
||||
],
|
||||
"state": [
|
||||
"deliveries",
|
||||
"groups",
|
||||
"asked",
|
||||
"pulls"
|
||||
"pulls",
|
||||
{
|
||||
"name": "asks",
|
||||
"history": 5
|
||||
},
|
||||
{
|
||||
"name": "merges",
|
||||
"history": 10
|
||||
},
|
||||
{
|
||||
"name": "owed",
|
||||
"history": 5
|
||||
},
|
||||
{
|
||||
"name": "source",
|
||||
"history": 64
|
||||
}
|
||||
],
|
||||
"reads": [
|
||||
"mesh-delivery.deliveries",
|
||||
"mesh-delivery.groups",
|
||||
"mesh-delivery.pulls",
|
||||
"mesh-delivery-teller.answers",
|
||||
"mesh-delivery-teller.answers-placeholder",
|
||||
"mesh-controller.assignments",
|
||||
"node-engine.have"
|
||||
],
|
||||
"tools": [
|
||||
"delivery_status"
|
||||
@@ -84,10 +100,10 @@
|
||||
"kind": "bundle",
|
||||
"language": "go",
|
||||
"system": "arch",
|
||||
"from": "cmd/mesh-delivery",
|
||||
"binary": "mesh-delivery",
|
||||
"from": "cmd/mesh-delivery-gate",
|
||||
"binary": "mesh-delivery-gate",
|
||||
"loads": [
|
||||
"mesh-delivery"
|
||||
"mesh-delivery-gate"
|
||||
]
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user