BL7: reserved by name from the catalog half's view, builder_versions calls it

The builder's tools bundle serves reserved given a package's name: it follows the catalog half's packages view itself, finds the
module from the name, answers the reserved version, or for a version no reservation holds asks the seat mesh-catalog's versions
and answers released with the release's digests; a name no entry carries, two entries carry, or a version neither reserved nor
released is answered error. builder_versions by name calls reserved through its invokes. The builder's process serves no call.

Builds: design 47 G §572, §582 (A-70)
Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-11 23:12:27 +01:00
parent efcc8125af
commit 260a16181c
9 changed files with 308 additions and 17 deletions
@@ -15,6 +15,8 @@ import (
"time"
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/buildrun"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-builder/builds"
"git.novox.be/novox/mesh-delivery/sdk/buildstep"
@@ -35,8 +37,11 @@ type queueAsker func(key string, value []byte) (json.RawMessage, error)
// Tools are the builder's tools: stuck reads, askAgain writes the reasks value, queue writes a queues value and waits for
// the builder's read, buildAgain writes a reasks value of mode build and waits for the builder's answer.
//
// builder_versions, asked by a name, answers also what the verb reserved answers for it (reserve; design 47 G §572): the
// bundle calls the seat mesh-builds through its invokes, as any caller does. Nil answers none.
func Tools(r build.StuckReader, askAgain func(key string, value []byte) error, queue, buildAgain queueAsker, since build.LogSince, now func() time.Time, vs versions.Reader,
fw, of versions.Reader) []stdio.Tool {
fw, of versions.Reader, reserve func(name, version string) (meshbuilds.ReservedAnswer, error)) []stdio.Tool {
str := func(args map[string]any, k string) string { s, _ := args[k].(string); return strings.TrimSpace(s) }
// handAct writes a reasks value of a versions hand act and answers the builder's answer, or its refusal as an error.
handAct := func(key string, value []byte, err error) (any, error) {
@@ -91,7 +96,16 @@ func Tools(r build.StuckReader, askAgain func(key string, value []byte) error, q
"version": map[string]any{"type": "string", "description": "one version, to ask whether it is recorded"},
"digest": map[string]any{"type": "string", "description": "with version: the digest the holder received"}}},
Run: func(args map[string]any) (any, error) {
return versions.AnswerVersions(context.Background(), vs, str(args, "name"), str(args, "version"), str(args, "digest"))
out, err := versions.AnswerVersions(context.Background(), vs, str(args, "name"), str(args, "version"), str(args, "digest"))
if err != nil || reserve == nil {
return out, err
}
ra, err := reserve(out.Name, str(args, "version"))
if err != nil {
return nil, fmt.Errorf("the seat mesh-builds' reserved did not answer for %s: %w", out.Name, err)
}
out.Reserved = &ra
return out, nil
}},
{Name: build.StuckTool,
Description: "Every build key that waits (building or queued), oldest first: its module, fingerprint, step words and since when, and each ask it " +
@@ -314,6 +328,26 @@ func written(s stdio.KeptState, key string, revision uint64) time.Time {
return time.Time{}
}
// The state the bundle follows, its owner's tool, and the seat verbs it calls (the manifest's invokes).
const (
indexerModule = "mesh-delivery-indexer"
packagesState = "packages"
packagesTool = indexerModule + ".indexer_read_packages"
catalogVersionsVerb = "seat:mesh-catalog.versions"
reservedVerb = "seat:mesh-builds.reserved"
)
// followedPackages is the catalog half's packages state as the bundle's picture of it holds it (versions.PackagesState).
type followedPackages struct{ r *views.Reader }
func (f followedPackages) Keys(context.Context) ([]string, error) {
return f.r.Keys(indexerModule + "." + packagesState)
}
func (f followedPackages) Get(_ context.Context, key string) ([]byte, bool, error) {
return f.r.Get(indexerModule+"."+packagesState, key)
}
func main() {
steps := map[string]build.StateRead{}
for _, bm := range build.StuckBuildModules {
@@ -370,8 +404,33 @@ func main() {
}
return e.Value, true, nil
}}
tools := Tools(r, put, askQueue(stdio.State(build.QueuesState), 25*time.Second), buildAgain, stdio.Log(builds.BuilderLog).Since, time.Now, vr, fr, ofr)
tools = append(tools, reservedTools(rr, buildAgain, time.Now, meshhandactsclient.Recorder{Ask: stdio.Ask})...)
// The catalog half's view of the packages the bundle follows itself (design 47 G §572, A-70), as other bundles follow views.
pk := &views.Reader{Module: builds.BuilderModule, Logf: func(f string, a ...any) { fmt.Fprintf(os.Stderr, "[mesh-delivery-builder-tools] "+f+"\n", a...) },
Acts: meshhandactsclient.Recorder{Ask: stdio.Ask}}
pk.Follow(indexerModule, packagesState, packagesTool)
pk.Start(context.Background())
carriers := versions.Carriers(followedPackages{pk})
released := func(_ context.Context, module string) ([]meshcatalog.VersionEntry, error) {
raw, err := stdio.Ask(catalogVersionsVerb, meshcatalog.VersionsInput{Module: module})
if err != nil {
return nil, err
}
var a meshcatalog.VersionsAnswer
if err := json.Unmarshal(raw, &a); err != nil {
return nil, fmt.Errorf("the seat mesh-catalog's versions answered what does not read: %w", err)
}
return a.Versions, nil
}
reserve := func(name, version string) (meshbuilds.ReservedAnswer, error) {
raw, err := stdio.Ask(reservedVerb, meshbuilds.ReservedInput{Name: name, Version: version})
if err != nil {
return meshbuilds.ReservedAnswer{}, err
}
var a meshbuilds.ReservedAnswer
return a, json.Unmarshal(raw, &a)
}
tools := Tools(r, put, askQueue(stdio.State(build.QueuesState), 25*time.Second), buildAgain, stdio.Log(builds.BuilderLog).Since, time.Now, vr, fr, ofr, reserve)
tools = append(tools, reservedTools(rr, buildAgain, time.Now, meshhandactsclient.Recorder{Ask: stdio.Ask}, carriers, released)...)
ws := stdio.State(build.WaitsState)
wr := versions.Reader{Keys: ws.Keys, Get: func(key string) (json.RawMessage, bool, error) {
e, err := ws.Get(key)
@@ -1,6 +1,7 @@
package main
import (
"context"
"errors"
"fmt"
"strings"
@@ -16,7 +17,10 @@ import (
// reservedTools are builder_reserved, builder_reserved_drop and the seat mesh-builds' verb reserved (design 47 G section
// 369), served as tools of the bundle. The drop is a hand act: it is recorded in the hand-act log first, then written to
// reasks for the builder, which owns the reservations, to answer.
func reservedTools(rr versions.Reader, ask queueAsker, now func() time.Time, acts meshhandactsclient.Recorder) []stdio.Tool {
//
// The verb reserved given a name finds the module from the catalog half's view the bundle follows (carriers) and, for a version
// no reservation holds, asks the seat mesh-catalog's verb versions (released); the builder's process serves no call (A-70).
func reservedTools(rr versions.Reader, ask queueAsker, now func() time.Time, acts meshhandactsclient.Recorder, carriers func(context.Context, string) ([]versions.Built, error), released versions.CatalogVersions) []stdio.Tool {
str := func(args map[string]any, k string) string { s, _ := args[k].(string); return strings.TrimSpace(s) }
return []stdio.Tool{
{Name: versions.ReservedTool, Description: versions.ReservedDescription,
@@ -25,10 +29,14 @@ func reservedTools(rr versions.Reader, ask queueAsker, now func() time.Time, act
Run: func(args map[string]any) (any, error) { return versions.AnswerReserved(rr, str(args, "module")) }},
{Name: versions.ReservedVerb, Description: "The seat mesh-builds' verb reserved: a module's reserved version with each artifact's digest once built " +
"(design 47 G section 369), for a registry holder deciding whether to publish. Read-only.",
Input: map[string]any{"type": "object", "required": []string{"module"}, "properties": map[string]any{
"module": map[string]any{"type": "string", "description": "the module"},
Input: map[string]any{"type": "object", "properties": map[string]any{
"module": map[string]any{"type": "string", "description": "the module; give this or name"},
"name": map[string]any{"type": "string", "description": "a package's or an image's name in its ecosystem, in place of module"},
"version": map[string]any{"type": "string", "description": "the version, when asked for a particular one"}}},
Run: func(args map[string]any) (any, error) {
if name := str(args, "name"); name != "" {
return versions.AnswerReservedByName(context.Background(), rr, carriers, released, name, str(args, "version"))
}
return versions.AnswerReservedVerb(rr, str(args, "module"), str(args, "version"))
}},
{Name: versions.ReservedDropTool, Description: versions.ReservedDropDescription,
@@ -0,0 +1,58 @@
package main
import (
"context"
"encoding/json"
"testing"
"time"
"git.novox.be/novox/mesh-contracts/health-and-repair/go/clients/meshhandactsclient"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
"mesh-delivery-builder/internal/build"
"mesh-delivery-builder/internal/versions"
)
// Design 47 G §572, §582, A-70: the bundle's verb reserved takes a name and answers from the view it follows and the catalog's
// versions, and builder_versions, asked by a name, calls reserved and answers what it answers.
func TestReservedByNameIsTheBundlesAndBuilderVersionsCallsIt(t *testing.T) {
none := versions.Reader{Keys: func() ([]string, error) { return nil, nil }, Get: func(string) (json.RawMessage, bool, error) { return nil, false, nil }}
carriers := func(_ context.Context, name string) ([]versions.Built, error) {
if name == "@novox/mesh-sdk" {
return []versions.Built{{Module: "mesh-sdk", Artifact: "ts"}}, nil
}
return nil, nil
}
released := func(_ context.Context, module string) ([]meshcatalog.VersionEntry, error) {
return []meshcatalog.VersionEntry{{Module: module, Version: "0.1.2", Artifacts: []meshcatalog.VersionArtifact{{Artifact: "mesh-sdk:ts", Digest: "sha256:dd"}}}}, nil
}
acts := meshhandactsclient.Recorder{Ask: func(string, any) (json.RawMessage, error) { return json.RawMessage(`{}`), nil }}
byName := map[string]func(map[string]any) (any, error){}
for _, tl := range reservedTools(none, nil, time.Now, acts, carriers, released) {
byName[tl.Name] = tl.Run
}
got, err := byName[versions.ReservedVerb](map[string]any{"name": "@novox/mesh-sdk", "version": "0.1.2"})
want := meshbuilds.ReservedAnswer{Module: "mesh-sdk", Version: "0.1.2", Released: true, Artifacts: []meshbuilds.ReservedAnswerArtifactsItem{{Artifact: "mesh-sdk:ts", Digest: "sha256:dd"}}}
if err != nil || got.(meshbuilds.ReservedAnswer).Released != want.Released || got.(meshbuilds.ReservedAnswer).Artifacts[0] != want.Artifacts[0] {
t.Fatalf("reserved by name = %+v (%v), want %+v", got, err, want)
}
var called []string
reserve := func(name, version string) (meshbuilds.ReservedAnswer, error) {
called = append(called, name+"@"+version)
return want, nil
}
tools := Tools(build.StuckReader{}, nil, nil, nil, nil, time.Now, none, none, none, reserve)
for _, tl := range tools {
if tl.Name == versions.VersionsTool {
out, err := tl.Run(map[string]any{"name": "@novox/mesh-sdk", "version": "0.1.2"})
ans, ok := out.(versions.VersionsAnswer)
if err != nil || !ok || ans.Reserved == nil || ans.Reserved.Module != "mesh-sdk" || !ans.Reserved.Released {
t.Fatalf("builder_versions by name = %+v (%v), want reserved's answer in it", out, err)
}
}
}
if len(called) != 1 || called[0] != "@novox/mesh-sdk@0.1.2" {
t.Errorf("reserved was called %v, want once, by the name and version", called)
}
}
@@ -2,6 +2,8 @@ package versions
import (
"context"
"errors"
"fmt"
"sort"
"strings"
@@ -71,22 +73,28 @@ func isSeriesKey(key string) bool {
return ok
}
// ModuleOf is the module and artifact a package's name in its ecosystem is built from, as the indexer's packages state holds
// them (the inverse of NamesIn; design 47 G §373, §465): the series key whose value names that name.
func ModuleOf(s PackagesState) func(ctx context.Context, name string) (module, artifact string, found bool, err error) {
return func(ctx context.Context, name string) (string, string, bool, error) {
// Built is a module's artifact, which a package's name is the name of.
type Built struct{ Module, Artifact string }
// Carriers are the module artifacts a package's name in its ecosystem is the name of, as the catalog half's packages view
// holds them (the inverse of NamesIn; design 47 G §572, §478): each distinct module and artifact of a series key whose value
// names that name, sorted. A name no entry carries answers none.
func Carriers(s PackagesState) func(ctx context.Context, name string) ([]Built, error) {
return func(ctx context.Context, name string) ([]Built, error) {
keys, err := s.Keys(ctx)
if err != nil {
return "", "", false, err
return nil, err
}
sort.Strings(keys)
seen := map[Built]bool{}
var out []Built
for _, key := range keys {
if !isSeriesKey(key) {
continue
}
value, found, err := s.Get(ctx, key)
if err != nil {
return "", "", false, err
return nil, err
}
if !found {
continue
@@ -95,10 +103,38 @@ func ModuleOf(s PackagesState) func(ctx context.Context, name string) (module, a
if err != nil || v.Name != name {
continue
}
if module, artifact, cut := strings.Cut(v.Package, "/"); cut && module != "" && artifact != "" {
return module, artifact, true, nil
if module, artifact, cut := strings.Cut(v.Package, "/"); cut && module != "" && artifact != "" && !seen[Built{module, artifact}] {
seen[Built{module, artifact}] = true
out = append(out, Built{module, artifact})
}
}
return "", "", false, nil
return out, nil
}
}
// ModuleOf is the module and artifact a package's name is built from (Carriers), found false for a name no entry carries; more
// than one entry carrying it is an error naming them.
func ModuleOf(s PackagesState) func(ctx context.Context, name string) (module, artifact string, found bool, err error) {
carriers := Carriers(s)
return func(ctx context.Context, name string) (string, string, bool, error) {
got, err := carriers(ctx, name)
switch {
case err != nil:
return "", "", false, err
case len(got) == 0:
return "", "", false, nil
case len(got) > 1:
return "", "", false, errors.New(MoreThanOne(name, got))
}
return got[0].Module, got[0].Artifact, true, nil
}
}
// MoreThanOne is the words of a name that more than one entry carries.
func MoreThanOne(name string, got []Built) string {
var refs []string
for _, b := range got {
refs = append(refs, b.Module+"/"+b.Artifact)
}
return fmt.Sprintf("the name %s is carried by more than one entry: %s", name, strings.Join(refs, ", "))
}
@@ -11,6 +11,7 @@ import (
"time"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
)
// **The reservation is one key per module and MAJOR.MINOR** (design 47 G §369, §52): the builder keeps in its old state
@@ -436,6 +437,53 @@ func AnswerReservedVerb(r Reader, module, version string) (meshbuilds.ReservedAn
return out, nil
}
// CatalogVersions answers a module's released versions, the seat mesh-catalog's verb versions (design 47 G §582).
type CatalogVersions func(ctx context.Context, module string) ([]meshcatalog.VersionEntry, error)
// AnswerReservedByName is the verb reserved given a package's name (design 47 G §572, §582, A-70): the module is found from the
// name in the catalog half's view (carriers); that module's reserved version answers as AnswerReservedVerb does. A version
// given with no reservation of it (a reservation goes once its version is released) is asked of the catalog, and answers
// released with the artifacts and digests the release recorded. A name no entry carries, more than one entry carries, or a
// version neither reserved nor released is answered error, naming which, set alone.
func AnswerReservedByName(ctx context.Context, r Reader, carriers func(context.Context, string) ([]Built, error), released CatalogVersions, name, version string) (meshbuilds.ReservedAnswer, error) {
name, version = strings.TrimSpace(name), strings.TrimSpace(version)
got, err := carriers(ctx, name)
if err != nil {
return meshbuilds.ReservedAnswer{}, fmt.Errorf("the entries of %s cannot be read: %w", name, err)
}
switch {
case len(got) == 0:
return meshbuilds.ReservedAnswer{Error: "no entry carries the name " + name}, nil
case len(got) > 1:
return meshbuilds.ReservedAnswer{Error: MoreThanOne(name, got)}, nil
}
module := got[0].Module
rs := &Reserver{Store: readOnlyReserve{readStore{r}}}
if _, found, err := rs.Of(ctx, module, version); err != nil {
return meshbuilds.ReservedAnswer{}, err
} else if found {
return AnswerReservedVerb(r, module, version)
}
if version != "" {
entries, err := released(ctx, module)
if err != nil {
return meshbuilds.ReservedAnswer{}, fmt.Errorf("the released versions of %s cannot be read: %w", module, err)
}
for _, e := range entries {
if e.Version != version {
continue
}
out := meshbuilds.ReservedAnswer{Module: module, Version: version, Released: true, Artifacts: []meshbuilds.ReservedAnswerArtifactsItem{}}
for _, a := range e.Artifacts {
out.Artifacts = append(out.Artifacts, meshbuilds.ReservedAnswerArtifactsItem{Artifact: a.Artifact, Digest: a.Digest})
}
return out, nil
}
return meshbuilds.ReservedAnswer{Error: fmt.Sprintf("%s (%s) has no version %s reserved or released", name, module, version)}, nil
}
return meshbuilds.ReservedAnswer{Error: fmt.Sprintf("%s (%s) has no reserved version", name, module)}, nil
}
// The descriptions of the reservation's tools.
const (
ReservedDescription = "The versions the builder reserved (its state reserved, design 47 G section 369): one per module and MAJOR.MINOR, " +
@@ -0,0 +1,76 @@
package versions
import (
"context"
"encoding/json"
"errors"
"strings"
"testing"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
)
// TestReservedByNameAnswersFromTheViewAndTheCatalog: design 47 G §572, §582, A-70 — a package's name (an npm name or a Go
// module path) is mapped to its module from the catalog half's view; the reserved version answers as for the module, a version
// no reservation holds is asked of the catalog's versions and answers released with the release's digests, and a name no entry
// carries, one more than one carries, or a version neither reserved nor released answers error, set alone.
func TestReservedByNameAnswersFromTheViewAndTheCatalog(t *testing.T) {
ctx := context.Background()
view := packagesMem{
"git=2enovox=2ebe/novox/mesh-sdk/go.0.1": []byte(`{"v":1,"name":"git.novox.be/novox/mesh-sdk/go","package":"mesh-sdk/go","series":"0.1"}`),
"git=2enovox=2ebe/novox/mesh-sdk/go.0.2": []byte(`{"v":1,"name":"git.novox.be/novox/mesh-sdk/go","package":"mesh-sdk/go","series":"0.2"}`),
"@novox/mesh-sdk.0.1": []byte(`{"v":1,"name":"@novox/mesh-sdk","package":"mesh-sdk/ts","series":"0.1"}`),
"twice.0.1": []byte(`{"v":1,"name":"twice","package":"a/x","series":"0.1"}`),
"twice-b.0.1": []byte(`{"v":1,"name":"twice","package":"b/y","series":"0.1"}`),
}
store := &reserveMem{mem: newMem()}
r := &Reserver{Store: store, ReleasedOf: func(context.Context, string) ([]string, error) { return []string{"0.1.3"}, nil }}
if _, err := r.Reserve(ctx, "mesh-sdk", "0.1", []string{"mesh-sdk:ts"}, Source{}); err != nil {
t.Fatal(err)
}
rd := Reader{
Keys: func() ([]string, error) { return store.KeysOf(ctx, AllFilter) },
Get: func(key string) (json.RawMessage, bool, error) {
raw, _, ok, err := store.Get(ctx, key)
return raw, ok, err
}}
var asked []string
released := func(_ context.Context, module string) ([]meshcatalog.VersionEntry, error) {
asked = append(asked, module)
return []meshcatalog.VersionEntry{{Module: module, Version: "0.1.2", Artifacts: []meshcatalog.VersionArtifact{{Artifact: "mesh-sdk:go", Digest: "sha256:dd"}}}}, nil
}
carriers := Carriers(view)
ask := func(name, version string) meshbuilds.ReservedAnswer {
t.Helper()
got, err := AnswerReservedByName(ctx, rd, carriers, released, name, version)
if err != nil {
t.Fatalf("%s %s: %v", name, version, err)
}
return got
}
if got := ask("@novox/mesh-sdk", ""); got.Module != "mesh-sdk" || got.Version != "0.1.4" || got.Released || got.Error != "" {
t.Errorf("an npm name = %+v, want the module's reserved version", got)
}
if got := ask("git.novox.be/novox/mesh-sdk/go", "0.1.2"); !got.Released || got.Module != "mesh-sdk" || len(got.Artifacts) != 1 || got.Artifacts[0].Digest != "sha256:dd" {
t.Errorf("a Go module path = %+v, want the release's artifacts and digests (two series of one entry are one entry)", got)
}
if len(asked) != 1 || asked[0] != "mesh-sdk" {
t.Errorf("the catalog was asked for %v, want the module's versions once, for the version no reservation holds", asked)
}
for name, c := range map[string]struct{ name, version, want string }{
"unknown name": {"nothing", "", "no entry carries"},
"two entries": {"twice", "", "more than one entry"},
"neither released": {"git.novox.be/novox/mesh-sdk/go", "9.9.9", "reserved or released"},
} {
if got := ask(c.name, c.version); !strings.Contains(got.Error, c.want) || got.Module != "" || len(got.Artifacts) != 0 {
t.Errorf("%s = %+v, want error naming %q alone", name, got, c.want)
}
}
if _, err := AnswerReservedByName(ctx, rd, Carriers(packagesMem(nil)), released, "x", ""); err == nil {
t.Error("an unreadable view was answered as if no entry carried the name")
}
if _, err := AnswerReservedByName(ctx, rd, carriers, func(context.Context, string) ([]meshcatalog.VersionEntry, error) { return nil, errors.New("down") }, "git.novox.be/novox/mesh-sdk/go", "0.1.2"); err == nil {
t.Error("an unreadable catalog was answered as if the version were not released")
}
}
@@ -6,6 +6,8 @@ import (
"errors"
"fmt"
"strings"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshbuilds"
)
// The builder's tools of its versions (design 51 *Events of the builder*, *Tools of the builder*).
@@ -64,6 +66,9 @@ type VersionsAnswer struct {
Asked string `json:"asked,omitempty"`
Recorded *bool `json:"recorded,omitempty"`
Why string `json:"why,omitempty"`
// Reserved is what the seat mesh-builds' verb reserved answers for the name (and version): the reserved or released version
// with each artifact's digest, or its error (design 47 G §572, §582).
Reserved *meshbuilds.ReservedAnswer `json:"reserved,omitempty"`
}
// AnswerVersions is builder_versions: a name's versions in order, in one call; with a version (and a digest), whether
@@ -143,7 +143,7 @@ func TestManifestDeclarations(t *testing.T) { // 1607/AC1
if want := []string{"mesh-delivery-assigner.assigner_read_assignments", "mesh-delivery-forge-bridge.bridge_tags", "mesh-delivery-indexer.indexer_read_candidates", "mesh-delivery-indexer.indexer_read_manifests",
"mesh-delivery-indexer.indexer_read_modules", "mesh-delivery-indexer.indexer_read_packages", "mesh-delivery-indexer.indexer_requirements", "seat:container-image-registry.remove", "seat:container-image-registry.versions",
"seat:git.tag",
"seat:go-package-registry.remove", "seat:go-package-registry.versions", "seat:mesh-artifact-sweep.held", "seat:mesh-catalog.versions", "seat:mesh-hand-acts.hand-act", "seat:mesh-watchdogs.presence", "seat:node-build-go.drop", "seat:node-build-image.drop", "seat:node-build-node.drop", "seat:node-engine.manifest-reads", "seat:npm-package-registry.remove",
"seat:go-package-registry.remove", "seat:go-package-registry.versions", "seat:mesh-artifact-sweep.held", "seat:mesh-builds.reserved", "seat:mesh-catalog.versions", "seat:mesh-hand-acts.hand-act", "seat:mesh-watchdogs.presence", "seat:node-build-go.drop", "seat:node-build-image.drop", "seat:node-build-node.drop", "seat:node-engine.manifest-reads", "seat:npm-package-registry.remove",
"seat:npm-package-registry.versions", "seat:oci-artifact-registry.remove", "seat:oci-artifact-registry.versions"}; !reflect.DeepEqual(sorted(m.Invokes), want) {
t.Errorf("invokes = %v, want %v", m.Invokes, want)
}
@@ -82,6 +82,7 @@
"seat:go-package-registry.remove",
"seat:go-package-registry.versions",
"seat:mesh-artifact-sweep.held",
"seat:mesh-builds.reserved",
"seat:mesh-catalog.versions",
"seat:mesh-hand-acts.hand-act",
"seat:mesh-watchdogs.presence",