Bootstrap the seat mesh-delivery so a runner admits its source before the seat list is read (A-362)
mesh/delivery merged: source.main moved to novox/mesh-sdk@d11e2423ff04
mesh/delivery-group group fix/47-G-start merged: every member is merged

The catalog half is read through mesh-delivery's source as well as mesh-catalog's verbs, and a runner with an unread
seat list admitted only the latter. The bootstrapped copy is mesh-delivery main 21eaa55b's contract file, byte for
byte; the tests' seat list and the captured beside copy take the same file.

Builds: design 47 G lead answers A-362, A-353

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-13 17:45:44 +01:00
parent affde04396
commit ab355879f0
5 changed files with 2499 additions and 8 deletions
File diff suppressed because it is too large Load Diff
+1
View File
@@ -26,6 +26,7 @@ func TestEveryBootstrappedDefinitionEqualsItsContractsFile(t *testing.T) {
{"operator-channel", "mesh-contracts", "operator-and-conversation/seats/operator-channel/seat.json"}, {"operator-channel", "mesh-contracts", "operator-and-conversation/seats/operator-channel/seat.json"},
{"mesh-catalog", "mesh-delivery", "modules/mesh-delivery-contracts/seats/mesh-catalog/seat.json"}, {"mesh-catalog", "mesh-delivery", "modules/mesh-delivery-contracts/seats/mesh-catalog/seat.json"},
{"mesh-delivery-checker", "mesh-delivery", "modules/mesh-delivery-contracts/seats/mesh-delivery-checker/seat.json"}, {"mesh-delivery-checker", "mesh-delivery", "modules/mesh-delivery-contracts/seats/mesh-delivery-checker/seat.json"},
{"mesh-delivery", "mesh-delivery", "modules/mesh-delivery-contracts/seats/mesh-delivery/seat.json"},
} }
var have []string var have []string
for _, d := range Bootstrapped() { for _, d := range Bootstrapped() {
+8
View File
@@ -6,6 +6,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
"slices"
"strings" "strings"
"testing" "testing"
"time" "time"
@@ -182,6 +183,13 @@ func TestTheBootstrapIsHeldAndNothingNewIsActedOnUntilTheSeatAnswers(t *testing.
if got := len(r.Definitions()); got != len(boot) { if got := len(r.Definitions()); got != len(boot) {
t.Fatalf("the reader holds %d definitions, the bootstrap has %d", got, len(boot)) t.Fatalf("the reader holds %d definitions, the bootstrap has %d", got, len(boot))
} }
// Design 47 G lead answers A-353, A-362: before the list is read the runner admits the seat verbs its catalog half is
// read by, mesh-delivery's source beside mesh-catalog's registrations, revision and entry.
for _, sv := range [][2]string{{"mesh-catalog", "registrations"}, {"mesh-catalog", "revision"}, {"mesh-catalog", "entry"}, {"mesh-delivery", "source"}} {
if !slices.ContainsFunc(r.Definitions()[sv[0]].Verbs, func(v seatdef.Verb) bool { return v.Name == sv[1] }) {
t.Errorf("with the seat list unread the reader holds no %s.%s", sv[0], sv[1])
}
}
st := r.Status() st := r.Status()
if st.Heard || len(st.Waiting) != len(boot) || st.LastError == "" || st.Health() == "" { if st.Heard || len(st.Waiting) != len(boot) || st.LastError == "" || st.Health() == "" {
t.Fatalf("status %+v: want the seat not heard, every bootstrapped seat waiting, the error and the health said", st) t.Fatalf("status %+v: want the seat not heard, every bootstrapped seat waiting, the error and the health said", st)
@@ -101,18 +101,15 @@
}, },
{ {
"name": "source", "name": "source",
"description": "One watched branch's source revision (design 47 *Watched branches and the catalog graph per branch*: source.<branch> in place of source.main): The source revision the gate holds: every repository it names, its trunk branch and that trunk's head as the gate merged or seeded it, and the group that moved it last. Read, never written: the node-engines read it to call a reverted build's catch-up tool once per repository, never the gate's state (design 47).", "description": "One watched branch's source revision (design 47 *Watched branches and the catalog graph per branch*: source.<branch> in place of source.main): The source revision the gate holds: every repository it names, its trunk branch and that trunk's head as the gate merged or seeded it, and the group that moved it last. Read, never written: the node-engines read it to call a reverted build's catch-up tool once per repository, never the gate's state (design 47). Given no branch it answers branches alone, the branch of each source key the gate keeps; given a branch, that branch's source revision (design 47 G section 690).",
"input": { "input": {
"type": "object", "type": "object",
"properties": { "properties": {
"branch": { "branch": {
"type": "string", "type": "string",
"description": "the watched branch, escaped as a key name is" "description": "the watched branch, escaped as a key name is; absent: the answer is the list of the branches the gate keeps a source revision of (design 47 G section 690)"
} }
}, }
"required": [
"branch"
]
}, },
"answer": { "answer": {
"type": "object", "type": "object",
@@ -139,6 +136,13 @@
"branch": { "branch": {
"type": "string", "type": "string",
"description": "the watched branch the source revision is of" "description": "the watched branch the source revision is of"
},
"branches": {
"type": "array",
"items": {
"type": "string"
},
"description": "given no branch: the branch name of each source.<branch> key the gate keeps, which every reader of the catalog half follows before the first registrations (design 47 G section 614, section 690)"
} }
} }
}, },
@@ -304,6 +308,22 @@
"type": "boolean", "type": "boolean",
"description": "a merge made at the forge, with no Approve" "description": "a merge made at the forge, with no Approve"
}, },
"repository": {
"type": "string",
"description": "for a forge-made record, the repository, <owner>/<name>"
},
"pull": {
"type": "integer",
"description": "for a forge-made record, the pull request's number"
},
"commit": {
"type": "string",
"description": "for a forge-made record, the merge commit"
},
"branch": {
"type": "string",
"description": "for a forge-made record, the branch the merge moved"
},
"at": { "at": {
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",
@@ -429,6 +449,14 @@
"type": "string", "type": "string",
"description": "the repository" "description": "the repository"
}, },
"module": {
"type": "string",
"description": "the module the merge changed, from the delivery record"
},
"branch": {
"type": "string",
"description": "the watched branch the merge moved"
},
"commit": { "commit": {
"type": "string", "type": "string",
"description": "the merge commit" "description": "the merge commit"
@@ -453,6 +481,65 @@
"why" "why"
] ]
} }
},
{
"name": "approval-carried",
"subject": "approval-carried.<repository>.<pull>",
"keep": {
"max-age-days": 90
},
"body": {
"type": "object",
"description": "an Approve given before G, carried as that pull request's approval step: said at G's switch for each merges key the old bridge had not performed (design 47 G 542)",
"properties": {
"repository": {
"type": "string",
"description": "the repository"
},
"pull": {
"type": "integer",
"description": "the pull request's number",
"minimum": 1
},
"commit": {
"type": "string",
"description": "the head the Approve named"
},
"approver": {
"type": "string",
"description": "who approved: the operator"
},
"at": {
"type": "string",
"description": "when it was said, RFC 3339",
"format": "date-time"
}
},
"required": [
"repository",
"pull",
"commit",
"approver",
"at"
]
}
},
{
"name": "pins-stated",
"body": {
"type": "object",
"description": "the gate states every pin it holds once its pinned events are said, so an indexer whose state pins was made later hears them all; kept as pinned is, on the seat's family (design 47 G 579, 652)",
"properties": {
"at": {
"type": "string",
"description": "when it was said, RFC 3339",
"format": "date-time"
}
},
"required": [
"at"
]
}
} }
], ],
"states": [ "states": [
@@ -992,9 +1079,24 @@
"catalog": { "catalog": {
"type": "array", "type": "array",
"items": { "items": {
"type": "integer" "type": "object",
"description": "one catalog graph revision, named by its watched branch and its number on the seat mesh-catalog (revisions are numbered per branch)",
"properties": {
"branch": {
"type": "string",
"description": "the watched branch the revision belongs to"
},
"revision": {
"type": "integer",
"description": "its number on that branch"
}
},
"required": [
"branch",
"revision"
]
}, },
"description": "catalog graph revisions, by their number on the seat mesh-catalog" "description": "catalog graph revisions, by watched branch and number on the seat mesh-catalog"
}, },
"assignment": { "assignment": {
"type": "array", "type": "array",