node-engine client: the codec and the comparison of the have and the node's facts, and the phases and healths a have names (ADR 0634 §1, §4; issue 1966)

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-05 15:14:16 +01:00
parent 181441e91b
commit db2a6da471
79 changed files with 313 additions and 6248 deletions
@@ -1,63 +0,0 @@
// Package containerimageregistryclient is the container-image-registry seat's client (novox/hq ADR 0627 §1, §2; ADR 0611, design 51
// *Publishing*): it publishes a file in parts to the seat's holder. `publish` opens the transfer naming every part,
// the holder answers the parts it lacks, and only those travel by `publish-part`, in chunks a bus message carries; a
// cut transfer goes on from what the holder answers when the same transfer is opened again. The sending in parts is
// mesh-sdk's seat-neutral runtime (parts); this client binds it to this seat's verbs and types alone. The call is the
// caller's own (a bundle's stdio.Ask, a process's call of a seat verb), so it holds no transport.
package containerimageregistryclient
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
seat "git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry"
"git.novox.be/novox/mesh-sdk/go/parts"
)
// Call asks one verb of the seat, `seat:<seat>.<verb>`, with a body, and answers its JSON.
type Call func(key string, body any) (json.RawMessage, error)
// Sent is what a Publish did: the transfer, whether the holder held its digest already, the parts it lacked and were
// sent, and the chunks they took.
type Sent struct {
Transfer string
parts.Sent
}
// Publish opens (or opens again) the transfer in on the seat and sends the parts the holder answers it lacks, each in
// chunks of at most parts.MaxChunk, in sequence, the last marked. in.Parts is written from parts. A part whose bytes
// do not hash to its digest is refused before anything of it is sent; a part the holder does not name is never read.
// Its outcome, published or refused, is the holder's event, which the caller waits for.
func Publish(ctx context.Context, call Call, in seat.PublishInput, ps []parts.Part) (Sent, error) {
open := func(_ context.Context, ps []parts.Part) (parts.Opened, error) {
in.Parts = make([]seat.Part, 0, len(ps))
for _, p := range ps {
in.Parts = append(in.Parts, seat.Part{Digest: p.Digest, Size: p.Size})
}
raw, err := call("seat:"+seat.Seat+"."+seat.VerbPublish, in)
if err != nil {
return parts.Opened{}, fmt.Errorf("%s's publish of %s: %w", seat.Seat, in.Name, err)
}
var a seat.PublishAnswer
if err := json.Unmarshal(raw, &a); err != nil {
return parts.Opened{}, fmt.Errorf("%s's answer to publish: %w", seat.Seat, err)
}
return parts.Opened{Held: a.Held, Lacks: a.Lacks}, nil
}
chunk := func(_ context.Context, part string, sequence int, last bool, data []byte) error {
raw, err := call("seat:"+seat.Seat+"."+seat.VerbPublishPart, seat.PublishPartInput{Transfer: in.Transfer, Part: part,
Sequence: int64(sequence), Last: last, Data: base64.StdEncoding.EncodeToString(data)})
if err != nil {
return fmt.Errorf("%s's publish-part: %w", seat.Seat, err)
}
var a seat.PublishPartAnswer
if err := json.Unmarshal(raw, &a); err != nil {
return fmt.Errorf("%s's answer to publish-part: %w", seat.Seat, err)
}
return nil
}
sent, err := parts.Send(ctx, open, chunk, ps)
return Sent{Transfer: in.Transfer, Sent: sent}, err
}
@@ -1,57 +0,0 @@
package containerimageregistryclient
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"io"
"testing"
seat "git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry"
"git.novox.be/novox/mesh-sdk/go/parts"
)
// The client publishes over its own seat's verbs alone (ADR 0627 §1): publish names every part, and only the part the
// holder lacks travels by publish-part, its bytes whole, the last chunk marked.
func TestPublishTalksToItsOwnSeat(t *testing.T) {
held, lacked := []byte("held"), []byte("lacked")
part := func(b []byte) parts.Part {
sum := sha256.Sum256(b)
return parts.Part{Digest: "sha256:" + hex.EncodeToString(sum[:]), Size: int64(len(b)),
Open: func() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(b)), nil }}
}
ps := []parts.Part{part(held), part(lacked)}
var asked []string
var got []byte
call := func(key string, body any) (json.RawMessage, error) {
asked = append(asked, key)
raw, _ := json.Marshal(body)
switch key {
case "seat:container-image-registry.publish":
var in seat.PublishInput
_ = json.Unmarshal(raw, &in)
if len(in.Parts) != 2 {
t.Errorf("publish names %d parts, want 2", len(in.Parts))
}
return json.Marshal(seat.PublishAnswer{Transfer: in.Transfer, Lacks: []string{ps[1].Digest}})
case "seat:container-image-registry.publish-part":
var in seat.PublishPartInput
_ = json.Unmarshal(raw, &in)
data, _ := base64.StdEncoding.DecodeString(in.Data)
if in.Part != ps[1].Digest || !in.Last || in.Transfer != "t1" {
t.Errorf("publish-part %+v", in)
}
got = append(got, data...)
return json.Marshal(seat.PublishPartAnswer{Transfer: in.Transfer, Part: in.Part})
}
t.Fatalf("asked %s", key)
return nil, nil
}
sent, err := Publish(context.Background(), call, seat.PublishInput{Transfer: "t1", Name: "x"}, ps)
if err != nil || sent.Transfer != "t1" || sent.Chunks != 1 || len(sent.Parts) != 1 || !bytes.Equal(got, lacked) || len(asked) != 2 {
t.Errorf("sent %+v, %q arrived, asked %v, %v", sent, got, asked, err)
}
}
@@ -1,17 +0,0 @@
module git.novox.be/novox/mesh-contracts/go/clients/containerimageregistryclient
go 1.26.0
require (
git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry v0.0.0-20261104172218-347a3053580a
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef
)
require (
github.com/klauspost/compress v1.20.1 // indirect
github.com/nats-io/nats.go v1.54.0 // indirect
github.com/nats-io/nkeys v0.4.16 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
golang.org/x/crypto v0.57.0 // indirect
golang.org/x/sys v0.48.0 // indirect
)
@@ -1,18 +0,0 @@
git.novox.be/novox/mesh-contracts/go v0.0.0-20261104172218-347a3053580a h1:E9ERPqR4uZXypudHGxv2/wNIOYcder9torVqJwJq/DI=
git.novox.be/novox/mesh-contracts/go v0.0.0-20261104172218-347a3053580a/go.mod h1:0dD1XEJBJ0G5UYDQxSZI84nuujb6m3tOpJl4C8rQVvg=
git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry v0.0.0-20261104172218-347a3053580a h1:BTqpa7dCCTQH9m08Jle8KVFwyIHiHPSUbwWxuqSg2yA=
git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry v0.0.0-20261104172218-347a3053580a/go.mod h1:pPxwhTMb3hIk7UUrBicJnGQCqfTEoBGJvNFspEK2U18=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef h1:/Jic5ho0xz32Z9DH2NSUqVxCF1KyfIOWuRTrX1aLjus=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef/go.mod h1:2wHG7ntLCG8Tpm/SCfgp524a5emUJm1gAC4KrRYsU9s=
github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ=
github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
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.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.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
@@ -1,63 +0,0 @@
// Package gopackageregistryclient is the go-package-registry seat's client (novox/hq ADR 0627 §1, §2; ADR 0611, design 51
// *Publishing*): it publishes a file in parts to the seat's holder. `publish` opens the transfer naming every part,
// the holder answers the parts it lacks, and only those travel by `publish-part`, in chunks a bus message carries; a
// cut transfer goes on from what the holder answers when the same transfer is opened again. The sending in parts is
// mesh-sdk's seat-neutral runtime (parts); this client binds it to this seat's verbs and types alone. The call is the
// caller's own (a bundle's stdio.Ask, a process's call of a seat verb), so it holds no transport.
package gopackageregistryclient
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
seat "git.novox.be/novox/mesh-contracts/go/seats/gopackageregistry"
"git.novox.be/novox/mesh-sdk/go/parts"
)
// Call asks one verb of the seat, `seat:<seat>.<verb>`, with a body, and answers its JSON.
type Call func(key string, body any) (json.RawMessage, error)
// Sent is what a Publish did: the transfer, whether the holder held its digest already, the parts it lacked and were
// sent, and the chunks they took.
type Sent struct {
Transfer string
parts.Sent
}
// Publish opens (or opens again) the transfer in on the seat and sends the parts the holder answers it lacks, each in
// chunks of at most parts.MaxChunk, in sequence, the last marked. in.Parts is written from parts. A part whose bytes
// do not hash to its digest is refused before anything of it is sent; a part the holder does not name is never read.
// Its outcome, published or refused, is the holder's event, which the caller waits for.
func Publish(ctx context.Context, call Call, in seat.PublishInput, ps []parts.Part) (Sent, error) {
open := func(_ context.Context, ps []parts.Part) (parts.Opened, error) {
in.Parts = make([]seat.Part, 0, len(ps))
for _, p := range ps {
in.Parts = append(in.Parts, seat.Part{Digest: p.Digest, Size: p.Size})
}
raw, err := call("seat:"+seat.Seat+"."+seat.VerbPublish, in)
if err != nil {
return parts.Opened{}, fmt.Errorf("%s's publish of %s: %w", seat.Seat, in.Name, err)
}
var a seat.PublishAnswer
if err := json.Unmarshal(raw, &a); err != nil {
return parts.Opened{}, fmt.Errorf("%s's answer to publish: %w", seat.Seat, err)
}
return parts.Opened{Held: a.Held, Lacks: a.Lacks}, nil
}
chunk := func(_ context.Context, part string, sequence int, last bool, data []byte) error {
raw, err := call("seat:"+seat.Seat+"."+seat.VerbPublishPart, seat.PublishPartInput{Transfer: in.Transfer, Part: part,
Sequence: int64(sequence), Last: last, Data: base64.StdEncoding.EncodeToString(data)})
if err != nil {
return fmt.Errorf("%s's publish-part: %w", seat.Seat, err)
}
var a seat.PublishPartAnswer
if err := json.Unmarshal(raw, &a); err != nil {
return fmt.Errorf("%s's answer to publish-part: %w", seat.Seat, err)
}
return nil
}
sent, err := parts.Send(ctx, open, chunk, ps)
return Sent{Transfer: in.Transfer, Sent: sent}, err
}
@@ -1,57 +0,0 @@
package gopackageregistryclient
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"io"
"testing"
seat "git.novox.be/novox/mesh-contracts/go/seats/gopackageregistry"
"git.novox.be/novox/mesh-sdk/go/parts"
)
// The client publishes over its own seat's verbs alone (ADR 0627 §1): publish names every part, and only the part the
// holder lacks travels by publish-part, its bytes whole, the last chunk marked.
func TestPublishTalksToItsOwnSeat(t *testing.T) {
held, lacked := []byte("held"), []byte("lacked")
part := func(b []byte) parts.Part {
sum := sha256.Sum256(b)
return parts.Part{Digest: "sha256:" + hex.EncodeToString(sum[:]), Size: int64(len(b)),
Open: func() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(b)), nil }}
}
ps := []parts.Part{part(held), part(lacked)}
var asked []string
var got []byte
call := func(key string, body any) (json.RawMessage, error) {
asked = append(asked, key)
raw, _ := json.Marshal(body)
switch key {
case "seat:go-package-registry.publish":
var in seat.PublishInput
_ = json.Unmarshal(raw, &in)
if len(in.Parts) != 2 {
t.Errorf("publish names %d parts, want 2", len(in.Parts))
}
return json.Marshal(seat.PublishAnswer{Transfer: in.Transfer, Lacks: []string{ps[1].Digest}})
case "seat:go-package-registry.publish-part":
var in seat.PublishPartInput
_ = json.Unmarshal(raw, &in)
data, _ := base64.StdEncoding.DecodeString(in.Data)
if in.Part != ps[1].Digest || !in.Last || in.Transfer != "t1" {
t.Errorf("publish-part %+v", in)
}
got = append(got, data...)
return json.Marshal(seat.PublishPartAnswer{Transfer: in.Transfer, Part: in.Part})
}
t.Fatalf("asked %s", key)
return nil, nil
}
sent, err := Publish(context.Background(), call, seat.PublishInput{Transfer: "t1", Name: "x"}, ps)
if err != nil || sent.Transfer != "t1" || sent.Chunks != 1 || len(sent.Parts) != 1 || !bytes.Equal(got, lacked) || len(asked) != 2 {
t.Errorf("sent %+v, %q arrived, asked %v, %v", sent, got, asked, err)
}
}
-17
View File
@@ -1,17 +0,0 @@
module git.novox.be/novox/mesh-contracts/go/clients/gopackageregistryclient
go 1.26.0
require (
git.novox.be/novox/mesh-contracts/go/seats/gopackageregistry v0.0.0-20261104172218-347a3053580a
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef
)
require (
github.com/klauspost/compress v1.20.1 // indirect
github.com/nats-io/nats.go v1.54.0 // indirect
github.com/nats-io/nkeys v0.4.16 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
golang.org/x/crypto v0.57.0 // indirect
golang.org/x/sys v0.48.0 // indirect
)
-18
View File
@@ -1,18 +0,0 @@
git.novox.be/novox/mesh-contracts/go v0.0.0-20261104172218-347a3053580a h1:E9ERPqR4uZXypudHGxv2/wNIOYcder9torVqJwJq/DI=
git.novox.be/novox/mesh-contracts/go v0.0.0-20261104172218-347a3053580a/go.mod h1:0dD1XEJBJ0G5UYDQxSZI84nuujb6m3tOpJl4C8rQVvg=
git.novox.be/novox/mesh-contracts/go/seats/gopackageregistry v0.0.0-20261104172218-347a3053580a h1:Zl6CzMg9AZtk7RU/DSJxSGGoUg5fSW3t7Yf8zyfXbVY=
git.novox.be/novox/mesh-contracts/go/seats/gopackageregistry v0.0.0-20261104172218-347a3053580a/go.mod h1:Y5kgBh0hBbL/hgc+abCF9Vbhov+vCsB0ckpRzUw1D+0=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef h1:/Jic5ho0xz32Z9DH2NSUqVxCF1KyfIOWuRTrX1aLjus=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef/go.mod h1:2wHG7ntLCG8Tpm/SCfgp524a5emUJm1gAC4KrRYsU9s=
github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ=
github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
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.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.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
+206
View File
@@ -0,0 +1,206 @@
package nodeengineclient
import (
"bytes"
"encoding/json"
"fmt"
"regexp"
seat "git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
"git.novox.be/novox/mesh-sdk/go/keys"
)
// The state have (novox/hq ADR 0539 clause 9): a module's have on a node under `<node>.<module>` and the node's own facts
// under `<node>.node`; their layouts are the seat's contract (seat.HaveByNodeModuleValue, seat.HaveByNodeNodeValue). This
// file is the codec the node-engine, the assigner, the watchman and every reader share: it writes the version, and refuses
// a phase, a health, a judgement or a digest outside the lists.
// The phases of a module's change on a node, as the have states them (the seat's constants, short).
const (
PhaseBackingUp = seat.HaveByNodeModuleValuePhaseBackingUp
PhaseApplying = seat.HaveByNodeModuleValuePhaseApplying
PhaseChecking = seat.HaveByNodeModuleValuePhaseChecking
PhaseRunning = seat.HaveByNodeModuleValuePhaseRunning
PhaseFailed = seat.HaveByNodeModuleValuePhaseFailed
PhaseRemoved = seat.HaveByNodeModuleValuePhaseRemoved
PhaseHeld = seat.HaveByNodeModuleValuePhaseHeld
PhaseWaitingYes = seat.HaveByNodeModuleValuePhaseWaitingYes
)
// The healths a have carries.
const (
HealthOK = seat.HaveByNodeModuleValueHealthOk
HealthFailed = seat.HaveByNodeModuleValueHealthFailed
HealthWaits = seat.HaveByNodeModuleValueHealthWaits
HealthUnknown = seat.HaveByNodeModuleValueHealthUnknown
)
// The judgements of a move that waits for a yes.
const (
JudgedRecreates = seat.HaveByNodeModuleValueJudgementRecreates
JudgedMovesData = seat.HaveByNodeModuleValueJudgementMovesData
JudgedCannot = seat.HaveByNodeModuleValueJudgementCannotJudge
)
// ComposesOwn is a node applying its own compositions (the node facts' composes).
const ComposesOwn = "own"
// composedByTheEndedController is what an engine from before the controller ended wrote in composes: read, never written.
const composedByTheEndedController = "controller"
var digestForm = regexp.MustCompile(`^sha256:[0-9a-f]{64}$`)
func checkDigest(digest, of string) error {
if !digestForm.MatchString(digest) {
return fmt.Errorf("node-engine: %s %q is not sha256:<64 lowercase hex digits>", of, digest)
}
return nil
}
func checkHave(h seat.HaveByNodeModuleValue) error {
switch h.Phase {
case PhaseBackingUp, PhaseApplying, PhaseChecking, PhaseRunning, PhaseFailed, PhaseRemoved, PhaseHeld:
if h.Judgement != "" || h.Waits != "" || h.BuildAlone {
return fmt.Errorf("node-engine: only a have waiting for a yes names a judgement, the composition waiting and whether it changes the build alone")
}
if h.PullWait != nil && h.Phase != PhaseFailed {
return fmt.Errorf("node-engine: only a failed have names the pull it waits on, not one %s", h.Phase)
}
case PhaseWaitingYes:
if h.Judgement != JudgedRecreates && h.Judgement != JudgedMovesData && h.Judgement != JudgedCannot {
return fmt.Errorf("node-engine: a have waiting for a yes names the judgement %q, not recreates, moves-data or cannot-judge", h.Judgement)
}
if err := checkDigest(h.Waits, "the composition a have waits a yes for"); err != nil {
return err
}
default:
return fmt.Errorf("node-engine: phase %q is not backing-up, applying, checking, running, failed, removed, held or waiting-yes", h.Phase)
}
if w := h.PullWait; w != nil && (w.Image == "" || w.Holder == "") {
return fmt.Errorf("node-engine: a have's pull wait names no image or no holder")
}
if h.Composed != "" {
if err := checkDigest(h.Composed, "the have's composition digest"); err != nil {
return err
}
}
switch h.Health {
case HealthOK, HealthFailed, HealthWaits, HealthUnknown:
default:
return fmt.Errorf("node-engine: health %q is not ok, failed, waits or unknown", h.Health)
}
return nil
}
// EncodeHave is h as JSON at the current version; it refuses a phase or health outside the lists.
func EncodeHave(h seat.HaveByNodeModuleValue) ([]byte, error) {
if err := checkHave(h); err != nil {
return nil, err
}
h.V = keys.Version
return json.Marshal(h)
}
// DecodeHave reads a have; it refuses an unknown version (keys.ErrUnknownVersion), a field the contract does not know and
// what EncodeHave refuses.
func DecodeHave(data []byte) (seat.HaveByNodeModuleValue, error) {
if err := keys.CheckVersion(data); err != nil {
return seat.HaveByNodeModuleValue{}, err
}
h, err := seat.DecodeHaveByNodeModuleValue(data)
if err != nil {
return seat.HaveByNodeModuleValue{}, fmt.Errorf("node-engine: value does not fit its shape: %w", err)
}
if err := checkHave(h); err != nil {
return seat.HaveByNodeModuleValue{}, err
}
return h, nil
}
func checkHaveNode(n seat.HaveByNodeNodeValue) error {
switch n.Composes {
case "", ComposesOwn, composedByTheEndedController:
default:
return fmt.Errorf("node-engine: a node composes %q, not %s", n.Composes, ComposesOwn)
}
for group, a := range n.Candidates {
if group == "" {
return fmt.Errorf("node-engine: a node's candidate answer names no group")
}
switch a.Verdict {
case seat.CandidateAnswerVerdictSame, seat.CandidateAnswerVerdictDiffers, seat.CandidateAnswerVerdictRefused:
default:
return fmt.Errorf("node-engine: the answer to %s's candidate has the verdict %q", group, a.Verdict)
}
}
return nil
}
// EncodeHaveNode is n as JSON at the current version; it refuses a candidate answer with a verdict outside the lists.
func EncodeHaveNode(n seat.HaveByNodeNodeValue) ([]byte, error) {
if err := checkHaveNode(n); err != nil {
return nil, err
}
n.V = keys.Version
return json.Marshal(n)
}
// DecodeHaveNode reads a node's facts; it refuses an unknown version (keys.ErrUnknownVersion), a field the contract does
// not know and what EncodeHaveNode refuses.
func DecodeHaveNode(data []byte) (seat.HaveByNodeNodeValue, error) {
if err := keys.CheckVersion(data); err != nil {
return seat.HaveByNodeNodeValue{}, err
}
n, err := seat.DecodeHaveByNodeNodeValue(data)
if err != nil {
return seat.HaveByNodeNodeValue{}, fmt.Errorf("node-engine: value does not fit its shape: %w", err)
}
if err := checkHaveNode(n); err != nil {
return seat.HaveByNodeNodeValue{}, err
}
return n, nil
}
// SameHave says whether two haves are the same value, so a writer writes only when they differ: times compare as
// instants, the user list's and the handed accounts' time as well.
func SameHave(a, b seat.HaveByNodeModuleValue) bool {
return sameJSON(utcHave(a), utcHave(b))
}
// SameHaveNode says whether two node facts are the same value, compared as their JSON (maps sorted, spacing dropped).
func SameHaveNode(a, b seat.HaveByNodeNodeValue) bool { return sameJSON(a, b) }
// SameNodeRecord says whether two records are the same value but for their version.
func SameNodeRecord(a, b seat.NodeRecord) bool {
a.V, b.V = 0, 0
return sameJSON(a, b)
}
func utcHave(h seat.HaveByNodeModuleValue) seat.HaveByNodeModuleValue {
if w := h.PullWait; w != nil {
c := *w
c.Began = c.Began.UTC()
if c.RetriedAt != nil {
t := c.RetriedAt.UTC()
c.RetriedAt = &t
}
h.PullWait = &c
}
if u := h.UserList; u != nil {
c := *u
c.At = c.At.UTC()
if c.Handed != nil {
hd := *c.Handed
hd.At = hd.At.UTC()
c.Handed = &hd
}
h.UserList = &c
}
return h
}
func sameJSON(a, b any) bool {
ra, errA := json.Marshal(a)
rb, errB := json.Marshal(b)
return errA == nil && errB == nil && bytes.Equal(ra, rb)
}
+107
View File
@@ -0,0 +1,107 @@
package nodeengineclient
import (
"errors"
"strings"
"testing"
"time"
seat "git.novox.be/novox/mesh-contracts/go/seats/nodeengine"
"git.novox.be/novox/mesh-sdk/go/keys"
)
const digestA = "sha256:0000000000000000000000000000000000000000000000000000000000000001"
func TestHaveCodec(t *testing.T) {
good := seat.HaveByNodeModuleValue{Phase: PhaseRunning, Health: HealthOK, Composed: digestA, Fp: "src2:x"}
waiting := seat.HaveByNodeModuleValue{Phase: PhaseWaitingYes, Health: HealthOK, Judgement: JudgedRecreates, Waits: digestA}
pull := &seat.PullWait{Image: "i", Holder: "h"}
tests := map[string]struct {
have seat.HaveByNodeModuleValue
bad string
}{
"running": {good, ""},
"waiting for a yes": {waiting, ""},
"unknown phase": {seat.HaveByNodeModuleValue{Phase: "gone", Health: HealthOK}, "phase"},
"unknown health": {seat.HaveByNodeModuleValue{Phase: PhaseRunning, Health: "fine"}, "health"},
"judgement outside a yes": {seat.HaveByNodeModuleValue{Phase: PhaseRunning, Health: HealthOK, Judgement: JudgedCannot}, "judgement"},
"a yes without a digest": {seat.HaveByNodeModuleValue{Phase: PhaseWaitingYes, Health: HealthOK, Judgement: JudgedCannot, Waits: "x"}, "sha256"},
"pull wait on a running": {seat.HaveByNodeModuleValue{Phase: PhaseRunning, Health: HealthOK, PullWait: pull}, "pull"},
"pull wait without holder": {seat.HaveByNodeModuleValue{Phase: PhaseFailed, Health: HealthFailed, PullWait: &seat.PullWait{Image: "i"}}, "holder"},
"bad composed digest": {seat.HaveByNodeModuleValue{Phase: PhaseRunning, Health: HealthOK, Composed: "abc"}, "sha256"},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
raw, err := EncodeHave(tc.have)
if tc.bad != "" {
if err == nil || !strings.Contains(err.Error(), tc.bad) {
t.Fatalf("encode: %v, want it to name %q", err, tc.bad)
}
return
}
if err != nil {
t.Fatal(err)
}
back, err := DecodeHave(raw)
if err != nil {
t.Fatal(err)
}
tc.have.V = keys.Version
if !SameHave(back, tc.have) {
t.Fatalf("round trip differs: %+v", back)
}
})
}
if _, err := DecodeHave([]byte(`{"v":2,"phase":"running","health":"ok"}`)); !errors.Is(err, keys.ErrUnknownVersion) {
t.Fatalf("version 2: %v", err)
}
if _, err := DecodeHave([]byte(`{"v":1,"phase":"running","health":"ok","extra":1}`)); err == nil {
t.Fatal("an unknown field is read")
}
}
func TestSameHaveComparesTimesAsInstants(t *testing.T) {
at := time.Date(2026, 11, 5, 12, 0, 0, 0, time.UTC)
zone := time.FixedZone("x", 3600)
mk := func(tm time.Time) seat.HaveByNodeModuleValue {
return seat.HaveByNodeModuleValue{Phase: PhaseFailed, Health: HealthFailed,
PullWait: &seat.PullWait{Image: "i", Holder: "h", Began: tm},
UserList: &seat.UserListWritten{Source: "s", At: tm}}
}
if !SameHave(mk(at), mk(at.In(zone))) {
t.Fatal("the same instant in another zone differs")
}
if SameHave(mk(at), mk(at.Add(time.Second))) {
t.Fatal("another instant is the same")
}
}
func TestHaveNodeCodec(t *testing.T) {
n := seat.HaveByNodeNodeValue{Composed: digestA, Composes: ComposesOwn,
Candidates: map[string]seat.CandidateAnswer{"g": {Proposal: "p", Verdict: seat.CandidateAnswerVerdictSame}}}
raw, err := EncodeHaveNode(n)
if err != nil {
t.Fatal(err)
}
back, err := DecodeHaveNode(raw)
if err != nil {
t.Fatal(err)
}
n.V = keys.Version
if !SameHaveNode(back, n) {
t.Fatalf("round trip differs: %+v", back)
}
for name, bad := range map[string]seat.HaveByNodeNodeValue{
"composes": {Composes: "other"},
"no group": {Candidates: map[string]seat.CandidateAnswer{"": {Verdict: "same"}}},
"a verdict": {Candidates: map[string]seat.CandidateAnswer{"g": {Verdict: "maybe"}}},
} {
if _, err := EncodeHaveNode(bad); err == nil {
t.Errorf("%s: encoded", name)
}
}
a, b := seat.NodeRecord{Node: "n", V: 1}, seat.NodeRecord{Node: "n", V: 2}
if !SameNodeRecord(a, b) {
t.Error("a record differs by its version")
}
}
@@ -1,63 +0,0 @@
// Package npmpackageregistryclient is the npm-package-registry seat's client (novox/hq ADR 0627 §1, §2; ADR 0611, design 51
// *Publishing*): it publishes a file in parts to the seat's holder. `publish` opens the transfer naming every part,
// the holder answers the parts it lacks, and only those travel by `publish-part`, in chunks a bus message carries; a
// cut transfer goes on from what the holder answers when the same transfer is opened again. The sending in parts is
// mesh-sdk's seat-neutral runtime (parts); this client binds it to this seat's verbs and types alone. The call is the
// caller's own (a bundle's stdio.Ask, a process's call of a seat verb), so it holds no transport.
package npmpackageregistryclient
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
seat "git.novox.be/novox/mesh-contracts/go/seats/npmpackageregistry"
"git.novox.be/novox/mesh-sdk/go/parts"
)
// Call asks one verb of the seat, `seat:<seat>.<verb>`, with a body, and answers its JSON.
type Call func(key string, body any) (json.RawMessage, error)
// Sent is what a Publish did: the transfer, whether the holder held its digest already, the parts it lacked and were
// sent, and the chunks they took.
type Sent struct {
Transfer string
parts.Sent
}
// Publish opens (or opens again) the transfer in on the seat and sends the parts the holder answers it lacks, each in
// chunks of at most parts.MaxChunk, in sequence, the last marked. in.Parts is written from parts. A part whose bytes
// do not hash to its digest is refused before anything of it is sent; a part the holder does not name is never read.
// Its outcome, published or refused, is the holder's event, which the caller waits for.
func Publish(ctx context.Context, call Call, in seat.PublishInput, ps []parts.Part) (Sent, error) {
open := func(_ context.Context, ps []parts.Part) (parts.Opened, error) {
in.Parts = make([]seat.Part, 0, len(ps))
for _, p := range ps {
in.Parts = append(in.Parts, seat.Part{Digest: p.Digest, Size: p.Size})
}
raw, err := call("seat:"+seat.Seat+"."+seat.VerbPublish, in)
if err != nil {
return parts.Opened{}, fmt.Errorf("%s's publish of %s: %w", seat.Seat, in.Name, err)
}
var a seat.PublishAnswer
if err := json.Unmarshal(raw, &a); err != nil {
return parts.Opened{}, fmt.Errorf("%s's answer to publish: %w", seat.Seat, err)
}
return parts.Opened{Held: a.Held, Lacks: a.Lacks}, nil
}
chunk := func(_ context.Context, part string, sequence int, last bool, data []byte) error {
raw, err := call("seat:"+seat.Seat+"."+seat.VerbPublishPart, seat.PublishPartInput{Transfer: in.Transfer, Part: part,
Sequence: int64(sequence), Last: last, Data: base64.StdEncoding.EncodeToString(data)})
if err != nil {
return fmt.Errorf("%s's publish-part: %w", seat.Seat, err)
}
var a seat.PublishPartAnswer
if err := json.Unmarshal(raw, &a); err != nil {
return fmt.Errorf("%s's answer to publish-part: %w", seat.Seat, err)
}
return nil
}
sent, err := parts.Send(ctx, open, chunk, ps)
return Sent{Transfer: in.Transfer, Sent: sent}, err
}
@@ -1,57 +0,0 @@
package npmpackageregistryclient
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"io"
"testing"
seat "git.novox.be/novox/mesh-contracts/go/seats/npmpackageregistry"
"git.novox.be/novox/mesh-sdk/go/parts"
)
// The client publishes over its own seat's verbs alone (ADR 0627 §1): publish names every part, and only the part the
// holder lacks travels by publish-part, its bytes whole, the last chunk marked.
func TestPublishTalksToItsOwnSeat(t *testing.T) {
held, lacked := []byte("held"), []byte("lacked")
part := func(b []byte) parts.Part {
sum := sha256.Sum256(b)
return parts.Part{Digest: "sha256:" + hex.EncodeToString(sum[:]), Size: int64(len(b)),
Open: func() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(b)), nil }}
}
ps := []parts.Part{part(held), part(lacked)}
var asked []string
var got []byte
call := func(key string, body any) (json.RawMessage, error) {
asked = append(asked, key)
raw, _ := json.Marshal(body)
switch key {
case "seat:npm-package-registry.publish":
var in seat.PublishInput
_ = json.Unmarshal(raw, &in)
if len(in.Parts) != 2 {
t.Errorf("publish names %d parts, want 2", len(in.Parts))
}
return json.Marshal(seat.PublishAnswer{Transfer: in.Transfer, Lacks: []string{ps[1].Digest}})
case "seat:npm-package-registry.publish-part":
var in seat.PublishPartInput
_ = json.Unmarshal(raw, &in)
data, _ := base64.StdEncoding.DecodeString(in.Data)
if in.Part != ps[1].Digest || !in.Last || in.Transfer != "t1" {
t.Errorf("publish-part %+v", in)
}
got = append(got, data...)
return json.Marshal(seat.PublishPartAnswer{Transfer: in.Transfer, Part: in.Part})
}
t.Fatalf("asked %s", key)
return nil, nil
}
sent, err := Publish(context.Background(), call, seat.PublishInput{Transfer: "t1", Name: "x"}, ps)
if err != nil || sent.Transfer != "t1" || sent.Chunks != 1 || len(sent.Parts) != 1 || !bytes.Equal(got, lacked) || len(asked) != 2 {
t.Errorf("sent %+v, %q arrived, asked %v, %v", sent, got, asked, err)
}
}
@@ -1,17 +0,0 @@
module git.novox.be/novox/mesh-contracts/go/clients/npmpackageregistryclient
go 1.26.0
require (
git.novox.be/novox/mesh-contracts/go/seats/npmpackageregistry v0.0.0-20261104172218-347a3053580a
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef
)
require (
github.com/klauspost/compress v1.20.1 // indirect
github.com/nats-io/nats.go v1.54.0 // indirect
github.com/nats-io/nkeys v0.4.16 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
golang.org/x/crypto v0.57.0 // indirect
golang.org/x/sys v0.48.0 // indirect
)
@@ -1,18 +0,0 @@
git.novox.be/novox/mesh-contracts/go v0.0.0-20261104172218-347a3053580a h1:E9ERPqR4uZXypudHGxv2/wNIOYcder9torVqJwJq/DI=
git.novox.be/novox/mesh-contracts/go v0.0.0-20261104172218-347a3053580a/go.mod h1:0dD1XEJBJ0G5UYDQxSZI84nuujb6m3tOpJl4C8rQVvg=
git.novox.be/novox/mesh-contracts/go/seats/npmpackageregistry v0.0.0-20261104172218-347a3053580a h1:JdEqNAv+s0ut6JEcCtXN5RIoGpuYg0jIVteFZSJJ36s=
git.novox.be/novox/mesh-contracts/go/seats/npmpackageregistry v0.0.0-20261104172218-347a3053580a/go.mod h1:JRtTjIjMTkzn59IN4vCYei9ZwJGFnN1Puwame4V/sD0=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef h1:/Jic5ho0xz32Z9DH2NSUqVxCF1KyfIOWuRTrX1aLjus=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef/go.mod h1:2wHG7ntLCG8Tpm/SCfgp524a5emUJm1gAC4KrRYsU9s=
github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ=
github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
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.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.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
@@ -1,63 +0,0 @@
// Package ociartifactregistryclient is the oci-artifact-registry seat's client (novox/hq ADR 0627 §1, §2; ADR 0611, design 51
// *Publishing*): it publishes a file in parts to the seat's holder. `publish` opens the transfer naming every part,
// the holder answers the parts it lacks, and only those travel by `publish-part`, in chunks a bus message carries; a
// cut transfer goes on from what the holder answers when the same transfer is opened again. The sending in parts is
// mesh-sdk's seat-neutral runtime (parts); this client binds it to this seat's verbs and types alone. The call is the
// caller's own (a bundle's stdio.Ask, a process's call of a seat verb), so it holds no transport.
package ociartifactregistryclient
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
seat "git.novox.be/novox/mesh-contracts/go/seats/ociartifactregistry"
"git.novox.be/novox/mesh-sdk/go/parts"
)
// Call asks one verb of the seat, `seat:<seat>.<verb>`, with a body, and answers its JSON.
type Call func(key string, body any) (json.RawMessage, error)
// Sent is what a Publish did: the transfer, whether the holder held its digest already, the parts it lacked and were
// sent, and the chunks they took.
type Sent struct {
Transfer string
parts.Sent
}
// Publish opens (or opens again) the transfer in on the seat and sends the parts the holder answers it lacks, each in
// chunks of at most parts.MaxChunk, in sequence, the last marked. in.Parts is written from parts. A part whose bytes
// do not hash to its digest is refused before anything of it is sent; a part the holder does not name is never read.
// Its outcome, published or refused, is the holder's event, which the caller waits for.
func Publish(ctx context.Context, call Call, in seat.PublishInput, ps []parts.Part) (Sent, error) {
open := func(_ context.Context, ps []parts.Part) (parts.Opened, error) {
in.Parts = make([]seat.Part, 0, len(ps))
for _, p := range ps {
in.Parts = append(in.Parts, seat.Part{Digest: p.Digest, Size: p.Size})
}
raw, err := call("seat:"+seat.Seat+"."+seat.VerbPublish, in)
if err != nil {
return parts.Opened{}, fmt.Errorf("%s's publish of %s: %w", seat.Seat, in.Name, err)
}
var a seat.PublishAnswer
if err := json.Unmarshal(raw, &a); err != nil {
return parts.Opened{}, fmt.Errorf("%s's answer to publish: %w", seat.Seat, err)
}
return parts.Opened{Held: a.Held, Lacks: a.Lacks}, nil
}
chunk := func(_ context.Context, part string, sequence int, last bool, data []byte) error {
raw, err := call("seat:"+seat.Seat+"."+seat.VerbPublishPart, seat.PublishPartInput{Transfer: in.Transfer, Part: part,
Sequence: int64(sequence), Last: last, Data: base64.StdEncoding.EncodeToString(data)})
if err != nil {
return fmt.Errorf("%s's publish-part: %w", seat.Seat, err)
}
var a seat.PublishPartAnswer
if err := json.Unmarshal(raw, &a); err != nil {
return fmt.Errorf("%s's answer to publish-part: %w", seat.Seat, err)
}
return nil
}
sent, err := parts.Send(ctx, open, chunk, ps)
return Sent{Transfer: in.Transfer, Sent: sent}, err
}
@@ -1,57 +0,0 @@
package ociartifactregistryclient
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"io"
"testing"
seat "git.novox.be/novox/mesh-contracts/go/seats/ociartifactregistry"
"git.novox.be/novox/mesh-sdk/go/parts"
)
// The client publishes over its own seat's verbs alone (ADR 0627 §1): publish names every part, and only the part the
// holder lacks travels by publish-part, its bytes whole, the last chunk marked.
func TestPublishTalksToItsOwnSeat(t *testing.T) {
held, lacked := []byte("held"), []byte("lacked")
part := func(b []byte) parts.Part {
sum := sha256.Sum256(b)
return parts.Part{Digest: "sha256:" + hex.EncodeToString(sum[:]), Size: int64(len(b)),
Open: func() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(b)), nil }}
}
ps := []parts.Part{part(held), part(lacked)}
var asked []string
var got []byte
call := func(key string, body any) (json.RawMessage, error) {
asked = append(asked, key)
raw, _ := json.Marshal(body)
switch key {
case "seat:oci-artifact-registry.publish":
var in seat.PublishInput
_ = json.Unmarshal(raw, &in)
if len(in.Parts) != 2 {
t.Errorf("publish names %d parts, want 2", len(in.Parts))
}
return json.Marshal(seat.PublishAnswer{Transfer: in.Transfer, Lacks: []string{ps[1].Digest}})
case "seat:oci-artifact-registry.publish-part":
var in seat.PublishPartInput
_ = json.Unmarshal(raw, &in)
data, _ := base64.StdEncoding.DecodeString(in.Data)
if in.Part != ps[1].Digest || !in.Last || in.Transfer != "t1" {
t.Errorf("publish-part %+v", in)
}
got = append(got, data...)
return json.Marshal(seat.PublishPartAnswer{Transfer: in.Transfer, Part: in.Part})
}
t.Fatalf("asked %s", key)
return nil, nil
}
sent, err := Publish(context.Background(), call, seat.PublishInput{Transfer: "t1", Name: "x"}, ps)
if err != nil || sent.Transfer != "t1" || sent.Chunks != 1 || len(sent.Parts) != 1 || !bytes.Equal(got, lacked) || len(asked) != 2 {
t.Errorf("sent %+v, %q arrived, asked %v, %v", sent, got, asked, err)
}
}
@@ -1,17 +0,0 @@
module git.novox.be/novox/mesh-contracts/go/clients/ociartifactregistryclient
go 1.26.0
require (
git.novox.be/novox/mesh-contracts/go/seats/ociartifactregistry v0.0.0-20261104172218-347a3053580a
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef
)
require (
github.com/klauspost/compress v1.20.1 // indirect
github.com/nats-io/nats.go v1.54.0 // indirect
github.com/nats-io/nkeys v0.4.16 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
golang.org/x/crypto v0.57.0 // indirect
golang.org/x/sys v0.48.0 // indirect
)
@@ -1,18 +0,0 @@
git.novox.be/novox/mesh-contracts/go v0.0.0-20261104172218-347a3053580a h1:E9ERPqR4uZXypudHGxv2/wNIOYcder9torVqJwJq/DI=
git.novox.be/novox/mesh-contracts/go v0.0.0-20261104172218-347a3053580a/go.mod h1:0dD1XEJBJ0G5UYDQxSZI84nuujb6m3tOpJl4C8rQVvg=
git.novox.be/novox/mesh-contracts/go/seats/ociartifactregistry v0.0.0-20261104172218-347a3053580a h1:fhQ+q40fnPwuBBU+7Bpv13ktzoPxHtQiO6mpHR9oVoo=
git.novox.be/novox/mesh-contracts/go/seats/ociartifactregistry v0.0.0-20261104172218-347a3053580a/go.mod h1:ooQa2CiP8JOvhP0bdQvwurV5wskRE7Cm68ecURBbCwU=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef h1:/Jic5ho0xz32Z9DH2NSUqVxCF1KyfIOWuRTrX1aLjus=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261104174118-f94abb95aaef/go.mod h1:2wHG7ntLCG8Tpm/SCfgp524a5emUJm1gAC4KrRYsU9s=
github.com/klauspost/compress v1.20.1 h1:T7kKElXUMXrUJ2E9QhQhxFtcK5rPyLdsGZvdbLMPdiQ=
github.com/klauspost/compress v1.20.1/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI=
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.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.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
-403
View File
@@ -1,403 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package containerimageregistry is the contract of the seat "container-image-registry", defined whole (seats/container-image-registry/seat.json): The mesh's container images, in the one artifact store: the OCI distribution protocol's read side, an image's tags and mirroring an outside image.
package containerimageregistry
// Seat is the seat's name.
const Seat = "container-image-registry"
const (
VerbPublish = "publish"
VerbPublishPart = "publish-part"
VerbVersions = "versions"
VerbRemove = "remove"
VerbMirror = "mirror"
VerbTags = "tags"
VerbHold = "hold"
VerbRelease = "release"
VerbList = "list"
)
const (
EventPublished = "published"
EventRefused = "refused"
EventRemoved = "removed"
EventKept = "kept"
EventHeld = "held"
EventReleased = "released"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbPublish, VerbPublishPart, VerbVersions, VerbRemove, VerbMirror, VerbTags, VerbHold, VerbRelease, VerbList}
}
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventPublished, EventRefused, EventRemoved, EventKept, EventHeld, EventReleased}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
const (
Family = "container-image-registry.events"
FamilyMaxAgeDays = 7
)
// SubjectPublished is where published is published.
const SubjectPublished = "mesh.seat.container-image-registry.event.published"
// SubjectRefused is where refused is published.
const SubjectRefused = "mesh.seat.container-image-registry.event.refused"
// SubjectRemoved is where removed is published.
const SubjectRemoved = "mesh.seat.container-image-registry.event.removed"
// SubjectKept is where kept is published.
const SubjectKept = "mesh.seat.container-image-registry.event.kept"
// SubjectHeld is where held is published.
const SubjectHeld = "mesh.seat.container-image-registry.event.held"
// SubjectReleased is where released is published.
const SubjectReleased = "mesh.seat.container-image-registry.event.released"
// Artifact is one published thing, as every registry event and answer names it.
type Artifact struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// what it is
Kind string `json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of Artifact's kind.
const (
ArtifactKindPackage = "package"
ArtifactKindImage = "image"
ArtifactKindBundle = "bundle"
ArtifactKindArchive = "archive"
ArtifactKindUpstream = "upstream"
)
// Hold is the body of held and released.
type Hold struct {
// when, RFC 3339
At string `json:"at,omitempty"`
// the caller the holder proved
By string `json:"by,omitempty"`
// the digest
Digest string `json:"digest"`
// the module holding the seat
Holder string `json:"holder"`
// the name
Name string `json:"name"`
// why
Reason string `json:"reason,omitempty"`
}
// Listed is a type of the contract.
type Listed struct {
// for a manifest keeping one bundle or archive, the digest of that blob: what a reference names it by
Artifact string `json:"artifact,omitempty"`
// the manifest's digest, sha256:<hex>
Digest string `json:"digest"`
// a hold keeps it from retention
Held bool `json:"held"`
// it is an index, naming a manifest per platform
Index bool `json:"index"`
// for an index, the digests of the manifests it names
Platforms []string `json:"platforms,omitempty"`
// its bytes: its own content and every blob it names
Size int64 `json:"size"`
// the tags naming it, none for an untagged one
Tags []string `json:"tags,omitempty"`
}
// Outcome is the body of published, refused and removed.
type Outcome struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// the module holding the seat that said it
Holder string `json:"holder"`
// what it is
Kind string `json:"kind"`
// the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact
Module string `json:"module,omitempty"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest)
Reason string `json:"reason,omitempty"`
// the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9)
Reference string `json:"reference,omitempty"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// for kept: the other tags still naming its digest
Tags []string `json:"tags,omitempty"`
// the transfer it ends, when it ended one
Transfer string `json:"transfer,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of Outcome's kind.
const (
OutcomeKindPackage = "package"
OutcomeKindImage = "image"
OutcomeKindBundle = "bundle"
OutcomeKindArchive = "archive"
OutcomeKindUpstream = "upstream"
)
// Part is one part of a transfer.
type Part struct {
// the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob
Digest string `json:"digest"`
// its size in bytes
Size int64 `json:"size"`
}
// Repository is a type of the contract.
type Repository struct {
// each manifest it holds, by digest
Manifests []Listed `json:"manifests"`
// the repository
Name string `json:"name"`
}
// PublishInput is what publish takes.
type PublishInput struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// what it is
Kind string `json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// every part's digest and size; none when the digest is already held
Parts []Part `json:"parts,omitempty"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// the transfer's name, the caller's own; the same name opens the same transfer again
Transfer string `json:"transfer"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of PublishInput's kind.
const (
PublishInputKindPackage = "package"
PublishInputKindImage = "image"
PublishInputKindBundle = "bundle"
PublishInputKindArchive = "archive"
PublishInputKindUpstream = "upstream"
)
// PublishAnswer is what publish answers.
type PublishAnswer struct {
// the digest is held already: nothing to send; the outcome follows as an event
Held bool `json:"held,omitempty"`
// the digests of the parts the holder lacks, to send by publish-part
Lacks []string `json:"lacks,omitempty"`
// the transfer
Transfer string `json:"transfer"`
}
// PublishPartInput is what publish-part takes.
type PublishPartInput struct {
// the chunk's bytes, base64 (at most 760 KiB before encoding)
Data string `json:"data"`
// this chunk is the part's last
Last bool `json:"last"`
// the part's digest
Part string `json:"part"`
// the chunk's place in its part, from 0
Sequence int64 `json:"sequence"`
// the transfer
Transfer string `json:"transfer"`
}
// PublishPartAnswer is what publish-part answers.
type PublishPartAnswer struct {
// the part is whole and its bytes match its digest
Complete bool `json:"complete,omitempty"`
// the part
Part string `json:"part"`
// the chunks of the part held so far
Received int64 `json:"received,omitempty"`
// the transfer
Transfer string `json:"transfer"`
}
// VersionsInput is what versions takes.
type VersionsInput struct {
// narrowed to one kind (optional)
Kind string `json:"kind,omitempty"`
// the name
Name string `json:"name"`
}
// VersionsAnswer is what versions answers.
type VersionsAnswer struct {
// the name
Name string `json:"name"`
// newest first
Versions []Artifact `json:"versions"`
}
// RemoveInput is what remove takes.
type RemoveInput struct {
// the digest (for a bundle, archive or copied base)
Digest string `json:"digest,omitempty"`
// the name
Name string `json:"name"`
// why it goes
Reason string `json:"reason"`
// the tag (for a tagged version)
Tag string `json:"tag,omitempty"`
// the version
Version string `json:"version,omitempty"`
}
// The values of RemoveInput's reason.
const (
RemoveInputReasonTagGone = "tag-gone"
RemoveInputReasonRetention = "retention"
)
// RemoveAnswer is what remove answers.
type RemoveAnswer struct {
Artifact *Artifact `json:"artifact,omitempty"`
// it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags)
Kept bool `json:"kept,omitempty"`
// why it was kept: shared-digest, another tag names its digest
Reason string `json:"reason,omitempty"`
// it is gone
Removed bool `json:"removed"`
// the other tags still naming its digest, when kept
Tags []string `json:"tags,omitempty"`
}
// The values of RemoveAnswer's reason.
const (
RemoveAnswerReasonSharedDigest = "shared-digest"
)
// MirrorInput is what mirror takes.
type MirrorInput struct {
// its pinned digest, sha256:<hex>
Digest string `json:"digest"`
// the name it is kept under
Name string `json:"name"`
// the outside image's reference
Source string `json:"source"`
}
// MirrorAnswer is what mirror answers.
type MirrorAnswer struct {
// the digest stored
Digest string `json:"digest"`
// the reference the seat answers
Reference string `json:"reference"`
}
// TagsInput is what tags takes.
type TagsInput struct {
// the image
Name string `json:"name"`
}
// TagsAnswerTagsItem is a type of the contract.
type TagsAnswerTagsItem struct {
// its digest
Digest string `json:"digest"`
// the tag
Tag string `json:"tag"`
}
// TagsAnswer is what tags answers.
type TagsAnswer struct {
// the image
Name string `json:"name"`
// every tag
Tags []TagsAnswerTagsItem `json:"tags"`
}
// HoldInput is what hold takes.
type HoldInput struct {
// the digest
Digest string `json:"digest"`
// the name
Name string `json:"name"`
// which of the sweep's rules keeps it
Reason string `json:"reason"`
}
// HoldAnswer is what hold answers.
type HoldAnswer struct {
// it is held
Held bool `json:"held"`
// when the hold began, RFC 3339
Since string `json:"since,omitempty"`
}
// ReleaseInput is what release takes.
type ReleaseInput struct {
// the digest
Digest string `json:"digest"`
// the name
Name string `json:"name"`
// why it is let go
Reason string `json:"reason"`
}
// ReleaseAnswer is what release answers.
type ReleaseAnswer struct {
// a hold was let go; false when there was none
Released bool `json:"released"`
}
// ListInput is what list takes.
type ListInput struct {
// the repository, <module>/<artifact>; every repository of the seat when not given
Name string `json:"name,omitempty"`
}
// ListAnswer is what list answers.
type ListAnswer struct {
// each repository named, in order of its name
Repositories []Repository `json:"repositories"`
}
// PublishedEvent is the body of the event published.
type PublishedEvent = Outcome
// RefusedEvent is the body of the event refused.
type RefusedEvent = Outcome
// RemovedEvent is the body of the event removed.
type RemovedEvent = Outcome
// KeptEvent is the body of the event kept.
type KeptEvent = Outcome
// HeldEvent is the body of the event held.
type HeldEvent = Hold
// ReleasedEvent is the body of the event released.
type ReleasedEvent = Hold
@@ -1,74 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
package containerimageregistry
import (
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/container-image-registry/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
func TestFixtures(t *testing.T) {
cases := []struct {
name, subject, given, wire string
decode func([]byte) (any, error)
subjectIs *regexp.Regexp
}{
{name: "published on the seat's subject", subject: "mesh.seat.container-image-registry.event.published", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.container-image-registry\\.event\\.published$")},
{name: "refused on the seat's subject", subject: "mesh.seat.container-image-registry.event.refused", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v RefusedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.container-image-registry\\.event\\.refused$")},
{name: "removed on the seat's subject", subject: "mesh.seat.container-image-registry.event.removed", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v RemovedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.container-image-registry\\.event\\.removed$")},
{name: "kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it", subject: "mesh.seat.container-image-registry.event.kept", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",
decode: func(b []byte) (any, error) { var v KeptEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.container-image-registry\\.event\\.kept$")},
{name: "held on the seat's subject", subject: "mesh.seat.container-image-registry.event.held", given: "{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}", wire: "{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",
decode: func(b []byte) (any, error) { var v HeldEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.container-image-registry\\.event\\.held$")},
{name: "released on the seat's subject", subject: "mesh.seat.container-image-registry.event.released", given: "{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}", wire: "{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",
decode: func(b []byte) (any, error) { var v ReleasedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.container-image-registry\\.event\\.released$")},
{name: "publish opens a transfer", subject: "", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a field the reader does not know is dropped", subject: "", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"image\",\"later\":{\"x\":1},\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"image\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "publish answers what it lacks", subject: "", given: "{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}", wire: "{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",
decode: func(b []byte) (any, error) { var v PublishAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a chunk of a part", subject: "", given: "{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}", wire: "{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",
decode: func(b []byte) (any, error) { var v PublishPartInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "the versions held", subject: "", given: "{\"name\":\"mesh-sdk\",\"versions\":[{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"mesh-sdk\",\"version\":\"0.1.19\"}]}", wire: "{\"name\":\"mesh-sdk\",\"versions\":[{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"mesh-sdk\",\"version\":\"0.1.19\"}]}",
decode: func(b []byte) (any, error) { var v VersionsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a release of what is not held answers released false", subject: "", given: "{\"released\":false}", wire: "{\"released\":false}",
decode: func(b []byte) (any, error) { var v ReleaseAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a tagged version sharing its digest with another tag is kept, not removed", subject: "", given: "{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}", wire: "{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",
decode: func(b []byte) (any, error) { var v RemoveAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "list answers an index with its platforms, its tag and its hold", subject: "", given: "{\"repositories\":[{\"manifests\":[{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"held\":false,\"index\":true,\"platforms\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"size\":2048,\"tags\":[\"3\"]},{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"held\":false,\"index\":false,\"size\":1024}],\"name\":\"mail/server\"}]}", wire: "{\"repositories\":[{\"manifests\":[{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"held\":false,\"index\":true,\"platforms\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"size\":2048,\"tags\":[\"3\"]},{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"held\":false,\"index\":false,\"size\":1024}],\"name\":\"mail/server\"}]}",
decode: func(b []byte) (any, error) { var v ListAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))
if err != nil {
t.Errorf("%s: does not decode: %v", c.name, err)
continue
}
back, err := json.Marshal(v)
if err != nil {
t.Errorf("%s: does not encode: %v", c.name, err)
continue
}
var got, want any
if err := json.Unmarshal(back, &got); err != nil {
t.Fatal(err)
}
if err := json.Unmarshal([]byte(c.wire), &want); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("%s: reads back as %s, want %s", c.name, back, c.wire)
}
if c.subjectIs != nil && !c.subjectIs.MatchString(c.subject) {
t.Errorf("%s: subject %q is not the contract's %s", c.name, c.subject, c.subjectIs)
}
}
}
-3
View File
@@ -1,3 +0,0 @@
module git.novox.be/novox/mesh-contracts/go/seats/containerimageregistry
go 1.26.0
-262
View File
@@ -1,262 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package gopackageregistry is the contract of the seat "go-package-registry", defined whole (seats/go-package-registry/seat.json): The mesh's Go modules: Go's module proxy protocol's read side, and publishing over the bus.
package gopackageregistry
// Seat is the seat's name.
const Seat = "go-package-registry"
const (
VerbPublish = "publish"
VerbPublishPart = "publish-part"
VerbVersions = "versions"
VerbRemove = "remove"
)
const (
EventPublished = "published"
EventRefused = "refused"
EventRemoved = "removed"
EventKept = "kept"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbPublish, VerbPublishPart, VerbVersions, VerbRemove}
}
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventPublished, EventRefused, EventRemoved, EventKept}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
const (
Family = "go-package-registry.events"
FamilyMaxAgeDays = 7
)
// SubjectPublished is where published is published.
const SubjectPublished = "mesh.seat.go-package-registry.event.published"
// SubjectRefused is where refused is published.
const SubjectRefused = "mesh.seat.go-package-registry.event.refused"
// SubjectRemoved is where removed is published.
const SubjectRemoved = "mesh.seat.go-package-registry.event.removed"
// SubjectKept is where kept is published.
const SubjectKept = "mesh.seat.go-package-registry.event.kept"
// Artifact is one published thing, as every registry event and answer names it.
type Artifact struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// what it is
Kind string `json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of Artifact's kind.
const (
ArtifactKindPackage = "package"
ArtifactKindImage = "image"
ArtifactKindBundle = "bundle"
ArtifactKindArchive = "archive"
ArtifactKindUpstream = "upstream"
)
// Outcome is the body of published, refused and removed.
type Outcome struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// the module holding the seat that said it
Holder string `json:"holder"`
// what it is
Kind string `json:"kind"`
// the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact
Module string `json:"module,omitempty"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest)
Reason string `json:"reason,omitempty"`
// the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9)
Reference string `json:"reference,omitempty"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// for kept: the other tags still naming its digest
Tags []string `json:"tags,omitempty"`
// the transfer it ends, when it ended one
Transfer string `json:"transfer,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of Outcome's kind.
const (
OutcomeKindPackage = "package"
OutcomeKindImage = "image"
OutcomeKindBundle = "bundle"
OutcomeKindArchive = "archive"
OutcomeKindUpstream = "upstream"
)
// Part is one part of a transfer.
type Part struct {
// the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob
Digest string `json:"digest"`
// its size in bytes
Size int64 `json:"size"`
}
// PublishInput is what publish takes.
type PublishInput struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// what it is
Kind string `json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// every part's digest and size; none when the digest is already held
Parts []Part `json:"parts,omitempty"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// the transfer's name, the caller's own; the same name opens the same transfer again
Transfer string `json:"transfer"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of PublishInput's kind.
const (
PublishInputKindPackage = "package"
PublishInputKindImage = "image"
PublishInputKindBundle = "bundle"
PublishInputKindArchive = "archive"
PublishInputKindUpstream = "upstream"
)
// PublishAnswer is what publish answers.
type PublishAnswer struct {
// the digest is held already: nothing to send; the outcome follows as an event
Held bool `json:"held,omitempty"`
// the digests of the parts the holder lacks, to send by publish-part
Lacks []string `json:"lacks,omitempty"`
// the transfer
Transfer string `json:"transfer"`
}
// PublishPartInput is what publish-part takes.
type PublishPartInput struct {
// the chunk's bytes, base64 (at most 760 KiB before encoding)
Data string `json:"data"`
// this chunk is the part's last
Last bool `json:"last"`
// the part's digest
Part string `json:"part"`
// the chunk's place in its part, from 0
Sequence int64 `json:"sequence"`
// the transfer
Transfer string `json:"transfer"`
}
// PublishPartAnswer is what publish-part answers.
type PublishPartAnswer struct {
// the part is whole and its bytes match its digest
Complete bool `json:"complete,omitempty"`
// the part
Part string `json:"part"`
// the chunks of the part held so far
Received int64 `json:"received,omitempty"`
// the transfer
Transfer string `json:"transfer"`
}
// VersionsInput is what versions takes.
type VersionsInput struct {
// narrowed to one kind (optional)
Kind string `json:"kind,omitempty"`
// the name
Name string `json:"name"`
}
// VersionsAnswer is what versions answers.
type VersionsAnswer struct {
// the name
Name string `json:"name"`
// newest first
Versions []Artifact `json:"versions"`
}
// RemoveInput is what remove takes.
type RemoveInput struct {
// the digest (for a bundle, archive or copied base)
Digest string `json:"digest,omitempty"`
// the name
Name string `json:"name"`
// why it goes
Reason string `json:"reason"`
// the tag (for a tagged version)
Tag string `json:"tag,omitempty"`
// the version
Version string `json:"version,omitempty"`
}
// The values of RemoveInput's reason.
const (
RemoveInputReasonTagGone = "tag-gone"
RemoveInputReasonRetention = "retention"
)
// RemoveAnswer is what remove answers.
type RemoveAnswer struct {
Artifact *Artifact `json:"artifact,omitempty"`
// it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags)
Kept bool `json:"kept,omitempty"`
// why it was kept: shared-digest, another tag names its digest
Reason string `json:"reason,omitempty"`
// it is gone
Removed bool `json:"removed"`
// the other tags still naming its digest, when kept
Tags []string `json:"tags,omitempty"`
}
// The values of RemoveAnswer's reason.
const (
RemoveAnswerReasonSharedDigest = "shared-digest"
)
// PublishedEvent is the body of the event published.
type PublishedEvent = Outcome
// RefusedEvent is the body of the event refused.
type RefusedEvent = Outcome
// RemovedEvent is the body of the event removed.
type RemovedEvent = Outcome
// KeptEvent is the body of the event kept.
type KeptEvent = Outcome
// GoPackageRegistryForm is the form of the provision go-package-registry.
type GoPackageRegistryForm struct {
// the read side's address
URL string `json:"url"`
}
@@ -1,66 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
package gopackageregistry
import (
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/go-package-registry/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
func TestFixtures(t *testing.T) {
cases := []struct {
name, subject, given, wire string
decode func([]byte) (any, error)
subjectIs *regexp.Regexp
}{
{name: "published on the seat's subject", subject: "mesh.seat.go-package-registry.event.published", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"module\":\"git.novox.be/novox/mesh-sdk/go\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"module\":\"git.novox.be/novox/mesh-sdk/go\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.go-package-registry\\.event\\.published$")},
{name: "refused on the seat's subject", subject: "mesh.seat.go-package-registry.event.refused", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"retention\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"retention\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v RefusedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.go-package-registry\\.event\\.refused$")},
{name: "removed on the seat's subject", subject: "mesh.seat.go-package-registry.event.removed", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"retention\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"retention\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v RemovedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.go-package-registry\\.event\\.removed$")},
{name: "kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it", subject: "mesh.seat.go-package-registry.event.kept", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"shared-digest\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"reason\":\"shared-digest\",\"reference\":\"git.novox.be/novox/mesh-sdk/go@0.1.19\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",
decode: func(b []byte) (any, error) { var v KeptEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.go-package-registry\\.event\\.kept$")},
{name: "publish opens a transfer", subject: "", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a field the reader does not know is dropped", subject: "", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"later\":{\"x\":1},\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "publish answers what it lacks", subject: "", given: "{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}", wire: "{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",
decode: func(b []byte) (any, error) { var v PublishAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a chunk of a part", subject: "", given: "{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}", wire: "{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",
decode: func(b []byte) (any, error) { var v PublishPartInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "the versions held", subject: "", given: "{\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"versions\":[{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"version\":\"0.1.19\"}]}", wire: "{\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"versions\":[{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"git.novox.be/novox/mesh-sdk/go\",\"version\":\"0.1.19\"}]}",
decode: func(b []byte) (any, error) { var v VersionsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a tagged version sharing its digest with another tag is kept, not removed", subject: "", given: "{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}", wire: "{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",
decode: func(b []byte) (any, error) { var v RemoveAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))
if err != nil {
t.Errorf("%s: does not decode: %v", c.name, err)
continue
}
back, err := json.Marshal(v)
if err != nil {
t.Errorf("%s: does not encode: %v", c.name, err)
continue
}
var got, want any
if err := json.Unmarshal(back, &got); err != nil {
t.Fatal(err)
}
if err := json.Unmarshal([]byte(c.wire), &want); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("%s: reads back as %s, want %s", c.name, back, c.wire)
}
if c.subjectIs != nil && !c.subjectIs.MatchString(c.subject) {
t.Errorf("%s: subject %q is not the contract's %s", c.name, c.subject, c.subjectIs)
}
}
}
-3
View File
@@ -1,3 +0,0 @@
module git.novox.be/novox/mesh-contracts/go/seats/gopackageregistry
go 1.26.0
-131
View File
@@ -1,131 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package meshdeliverychecker is the contract of the seat "mesh-delivery-checker", defined whole (seats/mesh-delivery-checker/seat.json): The merge check's tries: start one, read one, end one. The checker's own events stay under its own subjects (ADR 0620 §2).
package meshdeliverychecker
// Seat is the seat's name.
const Seat = "mesh-delivery-checker"
const (
VerbTry = "try"
VerbTryRead = "try-read"
VerbTryEnd = "try-end"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbTry, VerbTryRead, VerbTryEnd}
}
// The holder's own events, listed beside the seat and published under the holder's subjects (ADR 0620 §2).
const (
HolderEventVerdict = "verdict"
HolderEventTagWanted = "tag-wanted"
HolderEventPreviewWritten = "preview.written"
)
// HolderSubjectVerdict is where the holder publishes verdict, kept in checker.asks.
func HolderSubjectVerdict(holder string) string { return "mesh.stream." + holder + ".event.verdict" }
// HolderSubjectTagWanted is where the holder publishes tag-wanted, kept in checker.asks.
func HolderSubjectTagWanted(holder string) string {
return "mesh.stream." + holder + ".event.tag-wanted"
}
// HolderSubjectPreviewWritten is where the holder publishes preview.written, kept in checks.
func HolderSubjectPreviewWritten(holder string) string {
return "mesh.stream." + holder + ".event.preview.written"
}
// TryInput is what try takes.
type TryInput struct {
// the full commit to try, 40 or 64 hex digits
Head string `json:"head"`
// unit or integration: only this level; both when absent
Level string `json:"level,omitempty"`
// <owner>/<name>
Repository string `json:"repository"`
// a go test -run pattern: only those tests run, and nothing is kept
Tests string `json:"tests,omitempty"`
// the trunk commit to merge it onto, or the trunk's branch for its head now; the trunk's head when absent
Trunk string `json:"trunk,omitempty"`
}
// TryAnswer is what try answers.
type TryAnswer struct {
// the try's id
ID string `json:"id"`
// its state
State string `json:"state,omitempty"`
}
// TryReadInput is what try-read takes.
type TryReadInput struct {
// the try's id, try-<digits>
ID string `json:"id"`
}
// TryReadAnswer is what try-read answers.
type TryReadAnswer = map[string]any
// TryEndInput is what try-end takes.
type TryEndInput struct {
// the try's id, try-<digits>
ID string `json:"id"`
// why it is ended, in words
Why string `json:"why"`
}
// TryEndAnswer is what try-end answers.
type TryEndAnswer struct {
// it is ended
Ended bool `json:"ended"`
// the try
ID string `json:"id"`
}
// VerdictHolderEventSeriesItem is a type of the contract.
type VerdictHolderEventSeriesItem struct {
// its artifact, or the package's ecosystem name as the module's packages name it
Artifact string `json:"artifact"`
// the series on trunk
From string `json:"from"`
// the module whose artifact's series changes
Module string `json:"module"`
// the series the checked head gives it
To string `json:"to"`
}
// VerdictHolderEvent is the body of the holder's event verdict.
type VerdictHolderEvent struct {
// the commit checked
Head string `json:"head"`
// the generated files out of step with their seat definitions, each path (design 26)
OutOfStep []string `json:"out-of-step,omitempty"`
// the pull request's number, for a pull request's check
Pull int64 `json:"pull,omitempty"`
// owner/repo
Repository string `json:"repository"`
// each change of an artifact's series the checked head makes against trunk's manifests, once each (design 32); absent when it changes none
Series []VerdictHolderEventSeriesItem `json:"series,omitempty"`
// pass or fail
Verdict string `json:"verdict"`
}
// TagWantedHolderEvent is the body of the holder's event tag-wanted.
type TagWantedHolderEvent struct {
// the pull request's branch: its tag is removed when the branch ends
Branch string `json:"branch"`
// its head
Head string `json:"head"`
// the group member
Module string `json:"module"`
// the package it declares
Package string `json:"package"`
// the pull request
Pull int64 `json:"pull,omitempty"`
// owner/repo
Repository string `json:"repository"`
// the tag wanted
Tag string `json:"tag,omitempty"`
}
@@ -1,52 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
package meshdeliverychecker
import (
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/mesh-delivery-checker/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
func TestFixtures(t *testing.T) {
cases := []struct {
name, subject, given, wire string
decode func([]byte) (any, error)
subjectIs *regexp.Regexp
}{
{name: "verdict on the checker's own family", subject: "mesh.stream.mesh-delivery-checker.event.verdict", given: "{\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"out-of-step\":[\"go/seats/meshbroker/contract.go\"],\"pull\":3,\"repository\":\"novox/mesh-contracts\",\"series\":[{\"artifact\":\"go\",\"from\":\"0.1\",\"module\":\"mesh-contracts\",\"to\":\"0.2\"}],\"verdict\":\"fail\"}", wire: "{\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"out-of-step\":[\"go/seats/meshbroker/contract.go\"],\"pull\":3,\"repository\":\"novox/mesh-contracts\",\"series\":[{\"artifact\":\"go\",\"from\":\"0.1\",\"module\":\"mesh-contracts\",\"to\":\"0.2\"}],\"verdict\":\"fail\"}",
decode: func(b []byte) (any, error) { var v VerdictHolderEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.stream\\.[a-z0-9-]+\\.event\\.verdict$")},
{name: "tag-wanted on the checker's own family", subject: "mesh.stream.mesh-delivery-checker.event.tag-wanted", given: "{\"branch\":\"feat/registry\",\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"module\":\"mesh-sdk\",\"package\":\"go\",\"pull\":170,\"repository\":\"novox/mesh-sdk\",\"tag\":\"registry-1966\"}", wire: "{\"branch\":\"feat/registry\",\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"module\":\"mesh-sdk\",\"package\":\"go\",\"pull\":170,\"repository\":\"novox/mesh-sdk\",\"tag\":\"registry-1966\"}",
decode: func(b []byte) (any, error) { var v TagWantedHolderEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.stream\\.[a-z0-9-]+\\.event\\.tag-wanted$")},
{name: "preview.written on the checker's stream", subject: "mesh.stream.mesh-delivery-checker.event.preview.written", given: "{}", wire: "{}",
decode: func(b []byte) (any, error) { var v map[string]any; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.stream\\.[a-z0-9-]+\\.event\\.preview\\.written$")},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))
if err != nil {
t.Errorf("%s: does not decode: %v", c.name, err)
continue
}
back, err := json.Marshal(v)
if err != nil {
t.Errorf("%s: does not encode: %v", c.name, err)
continue
}
var got, want any
if err := json.Unmarshal(back, &got); err != nil {
t.Fatal(err)
}
if err := json.Unmarshal([]byte(c.wire), &want); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("%s: reads back as %s, want %s", c.name, back, c.wire)
}
if c.subjectIs != nil && !c.subjectIs.MatchString(c.subject) {
t.Errorf("%s: subject %q is not the contract's %s", c.name, c.subject, c.subjectIs)
}
}
}
-3
View File
@@ -1,3 +0,0 @@
module git.novox.be/novox/mesh-contracts/go/seats/meshdeliverychecker
go 1.26.0
-262
View File
@@ -1,262 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package npmpackageregistry is the contract of the seat "npm-package-registry", defined whole (seats/npm-package-registry/seat.json): The mesh's npm packages: the npm registry protocol's read side, and publishing over the bus.
package npmpackageregistry
// Seat is the seat's name.
const Seat = "npm-package-registry"
const (
VerbPublish = "publish"
VerbPublishPart = "publish-part"
VerbVersions = "versions"
VerbRemove = "remove"
)
const (
EventPublished = "published"
EventRefused = "refused"
EventRemoved = "removed"
EventKept = "kept"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbPublish, VerbPublishPart, VerbVersions, VerbRemove}
}
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventPublished, EventRefused, EventRemoved, EventKept}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
const (
Family = "npm-package-registry.events"
FamilyMaxAgeDays = 7
)
// SubjectPublished is where published is published.
const SubjectPublished = "mesh.seat.npm-package-registry.event.published"
// SubjectRefused is where refused is published.
const SubjectRefused = "mesh.seat.npm-package-registry.event.refused"
// SubjectRemoved is where removed is published.
const SubjectRemoved = "mesh.seat.npm-package-registry.event.removed"
// SubjectKept is where kept is published.
const SubjectKept = "mesh.seat.npm-package-registry.event.kept"
// Artifact is one published thing, as every registry event and answer names it.
type Artifact struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// what it is
Kind string `json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of Artifact's kind.
const (
ArtifactKindPackage = "package"
ArtifactKindImage = "image"
ArtifactKindBundle = "bundle"
ArtifactKindArchive = "archive"
ArtifactKindUpstream = "upstream"
)
// Outcome is the body of published, refused and removed.
type Outcome struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// the module holding the seat that said it
Holder string `json:"holder"`
// what it is
Kind string `json:"kind"`
// the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact
Module string `json:"module,omitempty"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest)
Reason string `json:"reason,omitempty"`
// the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9)
Reference string `json:"reference,omitempty"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// for kept: the other tags still naming its digest
Tags []string `json:"tags,omitempty"`
// the transfer it ends, when it ended one
Transfer string `json:"transfer,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of Outcome's kind.
const (
OutcomeKindPackage = "package"
OutcomeKindImage = "image"
OutcomeKindBundle = "bundle"
OutcomeKindArchive = "archive"
OutcomeKindUpstream = "upstream"
)
// Part is one part of a transfer.
type Part struct {
// the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob
Digest string `json:"digest"`
// its size in bytes
Size int64 `json:"size"`
}
// PublishInput is what publish takes.
type PublishInput struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// what it is
Kind string `json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// every part's digest and size; none when the digest is already held
Parts []Part `json:"parts,omitempty"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// the transfer's name, the caller's own; the same name opens the same transfer again
Transfer string `json:"transfer"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of PublishInput's kind.
const (
PublishInputKindPackage = "package"
PublishInputKindImage = "image"
PublishInputKindBundle = "bundle"
PublishInputKindArchive = "archive"
PublishInputKindUpstream = "upstream"
)
// PublishAnswer is what publish answers.
type PublishAnswer struct {
// the digest is held already: nothing to send; the outcome follows as an event
Held bool `json:"held,omitempty"`
// the digests of the parts the holder lacks, to send by publish-part
Lacks []string `json:"lacks,omitempty"`
// the transfer
Transfer string `json:"transfer"`
}
// PublishPartInput is what publish-part takes.
type PublishPartInput struct {
// the chunk's bytes, base64 (at most 760 KiB before encoding)
Data string `json:"data"`
// this chunk is the part's last
Last bool `json:"last"`
// the part's digest
Part string `json:"part"`
// the chunk's place in its part, from 0
Sequence int64 `json:"sequence"`
// the transfer
Transfer string `json:"transfer"`
}
// PublishPartAnswer is what publish-part answers.
type PublishPartAnswer struct {
// the part is whole and its bytes match its digest
Complete bool `json:"complete,omitempty"`
// the part
Part string `json:"part"`
// the chunks of the part held so far
Received int64 `json:"received,omitempty"`
// the transfer
Transfer string `json:"transfer"`
}
// VersionsInput is what versions takes.
type VersionsInput struct {
// narrowed to one kind (optional)
Kind string `json:"kind,omitempty"`
// the name
Name string `json:"name"`
}
// VersionsAnswer is what versions answers.
type VersionsAnswer struct {
// the name
Name string `json:"name"`
// newest first
Versions []Artifact `json:"versions"`
}
// RemoveInput is what remove takes.
type RemoveInput struct {
// the digest (for a bundle, archive or copied base)
Digest string `json:"digest,omitempty"`
// the name
Name string `json:"name"`
// why it goes
Reason string `json:"reason"`
// the tag (for a tagged version)
Tag string `json:"tag,omitempty"`
// the version
Version string `json:"version,omitempty"`
}
// The values of RemoveInput's reason.
const (
RemoveInputReasonTagGone = "tag-gone"
RemoveInputReasonRetention = "retention"
)
// RemoveAnswer is what remove answers.
type RemoveAnswer struct {
Artifact *Artifact `json:"artifact,omitempty"`
// it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags)
Kept bool `json:"kept,omitempty"`
// why it was kept: shared-digest, another tag names its digest
Reason string `json:"reason,omitempty"`
// it is gone
Removed bool `json:"removed"`
// the other tags still naming its digest, when kept
Tags []string `json:"tags,omitempty"`
}
// The values of RemoveAnswer's reason.
const (
RemoveAnswerReasonSharedDigest = "shared-digest"
)
// PublishedEvent is the body of the event published.
type PublishedEvent = Outcome
// RefusedEvent is the body of the event refused.
type RefusedEvent = Outcome
// RemovedEvent is the body of the event removed.
type RemovedEvent = Outcome
// KeptEvent is the body of the event kept.
type KeptEvent = Outcome
// NpmPackageRegistryForm is the form of the provision npm-package-registry.
type NpmPackageRegistryForm struct {
// the read side's address
URL string `json:"url"`
}
@@ -1,66 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
package npmpackageregistry
import (
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/npm-package-registry/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
func TestFixtures(t *testing.T) {
cases := []struct {
name, subject, given, wire string
decode func([]byte) (any, error)
subjectIs *regexp.Regexp
}{
{name: "published on the seat's subject", subject: "mesh.seat.npm-package-registry.event.published", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.npm-package-registry\\.event\\.published$")},
{name: "refused on the seat's subject", subject: "mesh.seat.npm-package-registry.event.refused", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"retention\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"retention\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v RefusedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.npm-package-registry\\.event\\.refused$")},
{name: "removed on the seat's subject", subject: "mesh.seat.npm-package-registry.event.removed", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"retention\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"retention\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v RemovedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.npm-package-registry\\.event\\.removed$")},
{name: "kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it", subject: "mesh.seat.npm-package-registry.event.kept", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"gitea\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"@novox/mesh-sdk@0.1.19\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",
decode: func(b []byte) (any, error) { var v KeptEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.npm-package-registry\\.event\\.kept$")},
{name: "publish opens a transfer", subject: "", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a field the reader does not know is dropped", subject: "", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"later\":{\"x\":1},\"name\":\"@novox/mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "publish answers what it lacks", subject: "", given: "{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}", wire: "{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",
decode: func(b []byte) (any, error) { var v PublishAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a chunk of a part", subject: "", given: "{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}", wire: "{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",
decode: func(b []byte) (any, error) { var v PublishPartInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "the versions held", subject: "", given: "{\"name\":\"@novox/mesh-sdk\",\"versions\":[{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"version\":\"0.1.19\"}]}", wire: "{\"name\":\"@novox/mesh-sdk\",\"versions\":[{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"@novox/mesh-sdk\",\"version\":\"0.1.19\"}]}",
decode: func(b []byte) (any, error) { var v VersionsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a tagged version sharing its digest with another tag is kept, not removed", subject: "", given: "{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}", wire: "{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",
decode: func(b []byte) (any, error) { var v RemoveAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))
if err != nil {
t.Errorf("%s: does not decode: %v", c.name, err)
continue
}
back, err := json.Marshal(v)
if err != nil {
t.Errorf("%s: does not encode: %v", c.name, err)
continue
}
var got, want any
if err := json.Unmarshal(back, &got); err != nil {
t.Fatal(err)
}
if err := json.Unmarshal([]byte(c.wire), &want); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("%s: reads back as %s, want %s", c.name, back, c.wire)
}
if c.subjectIs != nil && !c.subjectIs.MatchString(c.subject) {
t.Errorf("%s: subject %q is not the contract's %s", c.name, c.subject, c.subjectIs)
}
}
}
-3
View File
@@ -1,3 +0,0 @@
module git.novox.be/novox/mesh-contracts/go/seats/npmpackageregistry
go 1.26.0
-361
View File
@@ -1,361 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package ociartifactregistry is the contract of the seat "oci-artifact-registry", defined whole (seats/oci-artifact-registry/seat.json): The mesh's bundles and archives, by digest, in the one artifact store: the OCI distribution protocol's read side.
package ociartifactregistry
// Seat is the seat's name.
const Seat = "oci-artifact-registry"
const (
VerbPublish = "publish"
VerbPublishPart = "publish-part"
VerbVersions = "versions"
VerbRemove = "remove"
VerbHold = "hold"
VerbRelease = "release"
VerbList = "list"
)
const (
EventPublished = "published"
EventRefused = "refused"
EventRemoved = "removed"
EventKept = "kept"
EventHeld = "held"
EventReleased = "released"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbPublish, VerbPublishPart, VerbVersions, VerbRemove, VerbHold, VerbRelease, VerbList}
}
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventPublished, EventRefused, EventRemoved, EventKept, EventHeld, EventReleased}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
const (
Family = "oci-artifact-registry.events"
FamilyMaxAgeDays = 7
)
// SubjectPublished is where published is published.
const SubjectPublished = "mesh.seat.oci-artifact-registry.event.published"
// SubjectRefused is where refused is published.
const SubjectRefused = "mesh.seat.oci-artifact-registry.event.refused"
// SubjectRemoved is where removed is published.
const SubjectRemoved = "mesh.seat.oci-artifact-registry.event.removed"
// SubjectKept is where kept is published.
const SubjectKept = "mesh.seat.oci-artifact-registry.event.kept"
// SubjectHeld is where held is published.
const SubjectHeld = "mesh.seat.oci-artifact-registry.event.held"
// SubjectReleased is where released is published.
const SubjectReleased = "mesh.seat.oci-artifact-registry.event.released"
// Artifact is one published thing, as every registry event and answer names it.
type Artifact struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// what it is
Kind string `json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of Artifact's kind.
const (
ArtifactKindPackage = "package"
ArtifactKindImage = "image"
ArtifactKindBundle = "bundle"
ArtifactKindArchive = "archive"
ArtifactKindUpstream = "upstream"
)
// Hold is the body of held and released.
type Hold struct {
// when, RFC 3339
At string `json:"at,omitempty"`
// the caller the holder proved
By string `json:"by,omitempty"`
// the digest
Digest string `json:"digest"`
// the module holding the seat
Holder string `json:"holder"`
// the name
Name string `json:"name"`
// why
Reason string `json:"reason,omitempty"`
}
// Listed is a type of the contract.
type Listed struct {
// for a manifest keeping one bundle or archive, the digest of that blob: what a reference names it by
Artifact string `json:"artifact,omitempty"`
// the manifest's digest, sha256:<hex>
Digest string `json:"digest"`
// a hold keeps it from retention
Held bool `json:"held"`
// it is an index, naming a manifest per platform
Index bool `json:"index"`
// for an index, the digests of the manifests it names
Platforms []string `json:"platforms,omitempty"`
// its bytes: its own content and every blob it names
Size int64 `json:"size"`
// the tags naming it, none for an untagged one
Tags []string `json:"tags,omitempty"`
}
// Outcome is the body of published, refused and removed.
type Outcome struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// the module holding the seat that said it
Holder string `json:"holder"`
// what it is
Kind string `json:"kind"`
// the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact
Module string `json:"module,omitempty"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest)
Reason string `json:"reason,omitempty"`
// the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9)
Reference string `json:"reference,omitempty"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// for kept: the other tags still naming its digest
Tags []string `json:"tags,omitempty"`
// the transfer it ends, when it ended one
Transfer string `json:"transfer,omitempty"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of Outcome's kind.
const (
OutcomeKindPackage = "package"
OutcomeKindImage = "image"
OutcomeKindBundle = "bundle"
OutcomeKindArchive = "archive"
OutcomeKindUpstream = "upstream"
)
// Part is one part of a transfer.
type Part struct {
// the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob
Digest string `json:"digest"`
// its size in bytes
Size int64 `json:"size"`
}
// Repository is a type of the contract.
type Repository struct {
// each manifest it holds, by digest
Manifests []Listed `json:"manifests"`
// the repository
Name string `json:"name"`
}
// PublishInput is what publish takes.
type PublishInput struct {
// the source commit it was built from
Commit string `json:"commit,omitempty"`
// its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record)
Digest string `json:"digest"`
// the build's fingerprint
Fingerprint string `json:"fingerprint,omitempty"`
// what it is
Kind string `json:"kind"`
// the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk)
Name string `json:"name"`
// every part's digest and size; none when the digest is already held
Parts []Part `json:"parts,omitempty"`
// the tag it carries, for a tagged version
Tag string `json:"tag,omitempty"`
// the transfer's name, the caller's own; the same name opens the same transfer again
Transfer string `json:"transfer"`
// the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone
Version string `json:"version,omitempty"`
}
// The values of PublishInput's kind.
const (
PublishInputKindPackage = "package"
PublishInputKindImage = "image"
PublishInputKindBundle = "bundle"
PublishInputKindArchive = "archive"
PublishInputKindUpstream = "upstream"
)
// PublishAnswer is what publish answers.
type PublishAnswer struct {
// the digest is held already: nothing to send; the outcome follows as an event
Held bool `json:"held,omitempty"`
// the digests of the parts the holder lacks, to send by publish-part
Lacks []string `json:"lacks,omitempty"`
// the transfer
Transfer string `json:"transfer"`
}
// PublishPartInput is what publish-part takes.
type PublishPartInput struct {
// the chunk's bytes, base64 (at most 760 KiB before encoding)
Data string `json:"data"`
// this chunk is the part's last
Last bool `json:"last"`
// the part's digest
Part string `json:"part"`
// the chunk's place in its part, from 0
Sequence int64 `json:"sequence"`
// the transfer
Transfer string `json:"transfer"`
}
// PublishPartAnswer is what publish-part answers.
type PublishPartAnswer struct {
// the part is whole and its bytes match its digest
Complete bool `json:"complete,omitempty"`
// the part
Part string `json:"part"`
// the chunks of the part held so far
Received int64 `json:"received,omitempty"`
// the transfer
Transfer string `json:"transfer"`
}
// VersionsInput is what versions takes.
type VersionsInput struct {
// narrowed to one kind (optional)
Kind string `json:"kind,omitempty"`
// the name
Name string `json:"name"`
}
// VersionsAnswer is what versions answers.
type VersionsAnswer struct {
// the name
Name string `json:"name"`
// newest first
Versions []Artifact `json:"versions"`
}
// RemoveInput is what remove takes.
type RemoveInput struct {
// the digest (for a bundle, archive or copied base)
Digest string `json:"digest,omitempty"`
// the name
Name string `json:"name"`
// why it goes
Reason string `json:"reason"`
// the tag (for a tagged version)
Tag string `json:"tag,omitempty"`
// the version
Version string `json:"version,omitempty"`
}
// The values of RemoveInput's reason.
const (
RemoveInputReasonTagGone = "tag-gone"
RemoveInputReasonRetention = "retention"
)
// RemoveAnswer is what remove answers.
type RemoveAnswer struct {
Artifact *Artifact `json:"artifact,omitempty"`
// it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags)
Kept bool `json:"kept,omitempty"`
// why it was kept: shared-digest, another tag names its digest
Reason string `json:"reason,omitempty"`
// it is gone
Removed bool `json:"removed"`
// the other tags still naming its digest, when kept
Tags []string `json:"tags,omitempty"`
}
// The values of RemoveAnswer's reason.
const (
RemoveAnswerReasonSharedDigest = "shared-digest"
)
// HoldInput is what hold takes.
type HoldInput struct {
// the digest
Digest string `json:"digest"`
// the name
Name string `json:"name"`
// which of the sweep's rules keeps it
Reason string `json:"reason"`
}
// HoldAnswer is what hold answers.
type HoldAnswer struct {
// it is held
Held bool `json:"held"`
// when the hold began, RFC 3339
Since string `json:"since,omitempty"`
}
// ReleaseInput is what release takes.
type ReleaseInput struct {
// the digest
Digest string `json:"digest"`
// the name
Name string `json:"name"`
// why it is let go
Reason string `json:"reason"`
}
// ReleaseAnswer is what release answers.
type ReleaseAnswer struct {
// a hold was let go; false when there was none
Released bool `json:"released"`
}
// ListInput is what list takes.
type ListInput struct {
// the repository, <module>/<artifact>; every repository of the seat when not given
Name string `json:"name,omitempty"`
}
// ListAnswer is what list answers.
type ListAnswer struct {
// each repository named, in order of its name
Repositories []Repository `json:"repositories"`
}
// PublishedEvent is the body of the event published.
type PublishedEvent = Outcome
// RefusedEvent is the body of the event refused.
type RefusedEvent = Outcome
// RemovedEvent is the body of the event removed.
type RemovedEvent = Outcome
// KeptEvent is the body of the event kept.
type KeptEvent = Outcome
// HeldEvent is the body of the event held.
type HeldEvent = Hold
// ReleasedEvent is the body of the event released.
type ReleasedEvent = Hold
@@ -1,74 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
package ociartifactregistry
import (
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/oci-artifact-registry/fixtures: each decodes into its type, a field the type does not
// know is dropped (ADR 0608 §6), and it reads back as its wire says; each subject named is the contract's.
func TestFixtures(t *testing.T) {
cases := []struct {
name, subject, given, wire string
decode func([]byte) (any, error)
subjectIs *regexp.Regexp
}{
{name: "published on the seat's subject", subject: "mesh.seat.oci-artifact-registry.event.published", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.oci-artifact-registry\\.event\\.published$")},
{name: "refused on the seat's subject", subject: "mesh.seat.oci-artifact-registry.event.refused", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v RefusedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.oci-artifact-registry\\.event\\.refused$")},
{name: "removed on the seat's subject", subject: "mesh.seat.oci-artifact-registry.event.removed", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"retention\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v RemovedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.oci-artifact-registry\\.event\\.removed$")},
{name: "kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it", subject: "mesh.seat.oci-artifact-registry.event.kept", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"holder\":\"distribution\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"reason\":\"shared-digest\",\"reference\":\"oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"tag\":\"0.1.19-feat-x.2\",\"tags\":[\"0.1.19\"],\"version\":\"0.1.19-feat-x.2\"}",
decode: func(b []byte) (any, error) { var v KeptEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.oci-artifact-registry\\.event\\.kept$")},
{name: "held on the seat's subject", subject: "mesh.seat.oci-artifact-registry.event.held", given: "{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}", wire: "{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",
decode: func(b []byte) (any, error) { var v HeldEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.oci-artifact-registry\\.event\\.held$")},
{name: "released on the seat's subject", subject: "mesh.seat.oci-artifact-registry.event.released", given: "{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}", wire: "{\"at\":\"2026-11-04T12:00:00Z\",\"by\":\"mesh-artifact-sweep\",\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"holder\":\"distribution\",\"name\":\"mesh-sdk\",\"reason\":\"kept by the sweep's rule\"}",
decode: func(b []byte) (any, error) { var v ReleasedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.oci-artifact-registry\\.event\\.released$")},
{name: "publish opens a transfer", subject: "", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a field the reader does not know is dropped", subject: "", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"bundle\",\"later\":{\"x\":1},\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"bundle\",\"name\":\"mesh-sdk\",\"parts\":[{\"digest\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"size\":1048576}],\"transfer\":\"t1\",\"version\":\"0.1.19\"}",
decode: func(b []byte) (any, error) { var v PublishInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "publish answers what it lacks", subject: "", given: "{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}", wire: "{\"lacks\":[\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\"],\"transfer\":\"t1\"}",
decode: func(b []byte) (any, error) { var v PublishAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a chunk of a part", subject: "", given: "{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}", wire: "{\"data\":\"aGVsbG8=\",\"last\":true,\"part\":\"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\",\"sequence\":0,\"transfer\":\"t1\"}",
decode: func(b []byte) (any, error) { var v PublishPartInput; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "the versions held", subject: "", given: "{\"name\":\"mesh-sdk\",\"versions\":[{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"mesh-sdk\",\"version\":\"0.1.19\"}]}", wire: "{\"name\":\"mesh-sdk\",\"versions\":[{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"fingerprint\":\"f1\",\"kind\":\"package\",\"name\":\"mesh-sdk\",\"version\":\"0.1.19\"}]}",
decode: func(b []byte) (any, error) { var v VersionsAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a release of what is not held answers released false", subject: "", given: "{\"released\":false}", wire: "{\"released\":false}",
decode: func(b []byte) (any, error) { var v ReleaseAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a tagged version sharing its digest with another tag is kept, not removed", subject: "", given: "{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}", wire: "{\"kept\":true,\"reason\":\"shared-digest\",\"removed\":false,\"tags\":[\"0.1.19\"]}",
decode: func(b []byte) (any, error) { var v RemoveAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "list answers an untagged archive by the blob it keeps", subject: "", given: "{\"repositories\":[{\"manifests\":[{\"artifact\":\"sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"held\":true,\"index\":false,\"size\":4096}],\"name\":\"mail/files\"}]}", wire: "{\"repositories\":[{\"manifests\":[{\"artifact\":\"sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"held\":true,\"index\":false,\"size\":4096}],\"name\":\"mail/files\"}]}",
decode: func(b []byte) (any, error) { var v ListAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
}
for _, c := range cases {
v, err := c.decode([]byte(c.given))
if err != nil {
t.Errorf("%s: does not decode: %v", c.name, err)
continue
}
back, err := json.Marshal(v)
if err != nil {
t.Errorf("%s: does not encode: %v", c.name, err)
continue
}
var got, want any
if err := json.Unmarshal(back, &got); err != nil {
t.Fatal(err)
}
if err := json.Unmarshal([]byte(c.wire), &want); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("%s: reads back as %s, want %s", c.name, back, c.wire)
}
if c.subjectIs != nil && !c.subjectIs.MatchString(c.subject) {
t.Errorf("%s: subject %q is not the contract's %s", c.name, c.subject, c.subjectIs)
}
}
}
-3
View File
@@ -1,3 +0,0 @@
module git.novox.be/novox/mesh-contracts/go/seats/ociartifactregistry
go 1.26.0
@@ -1,98 +0,0 @@
[
{
"name": "published on the seat's subject",
"of": "event:published",
"subject": "mesh.seat.container-image-registry.event.published",
"given": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "image",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "distribution",
"transfer": "t1",
"reference": "container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
},
{
"name": "refused on the seat's subject",
"of": "event:refused",
"subject": "mesh.seat.container-image-registry.event.refused",
"given": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "image",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "distribution",
"transfer": "t1",
"reference": "container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"reason": "retention"
}
},
{
"name": "removed on the seat's subject",
"of": "event:removed",
"subject": "mesh.seat.container-image-registry.event.removed",
"given": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "image",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "distribution",
"transfer": "t1",
"reference": "container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"reason": "retention"
}
},
{
"name": "kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it",
"of": "event:kept",
"subject": "mesh.seat.container-image-registry.event.kept",
"given": {
"name": "mesh-sdk",
"version": "0.1.19-feat-x.2",
"kind": "image",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "distribution",
"reference": "container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"reason": "shared-digest",
"tag": "0.1.19-feat-x.2",
"tags": [
"0.1.19"
]
}
},
{
"name": "held on the seat's subject",
"of": "event:held",
"subject": "mesh.seat.container-image-registry.event.held",
"given": {
"name": "mesh-sdk",
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"reason": "kept by the sweep's rule",
"holder": "distribution",
"by": "mesh-artifact-sweep",
"at": "2026-11-04T12:00:00Z"
}
},
{
"name": "released on the seat's subject",
"of": "event:released",
"subject": "mesh.seat.container-image-registry.event.released",
"given": {
"name": "mesh-sdk",
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"reason": "kept by the sweep's rule",
"holder": "distribution",
"by": "mesh-artifact-sweep",
"at": "2026-11-04T12:00:00Z"
}
}
]
@@ -1,149 +0,0 @@
[
{
"name": "publish opens a transfer",
"of": "verb:publish.input",
"given": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "image",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
]
}
},
{
"name": "a field the reader does not know is dropped",
"of": "verb:publish.input",
"why": "ADR 0608 §6: a reader ignores a field it does not know",
"given": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "image",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
],
"later": {
"x": 1
}
},
"wire": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "image",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
]
}
},
{
"name": "publish answers what it lacks",
"of": "verb:publish.answer",
"given": {
"transfer": "t1",
"lacks": [
"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
]
}
},
{
"name": "a chunk of a part",
"of": "verb:publish-part.input",
"given": {
"transfer": "t1",
"part": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"sequence": 0,
"last": true,
"data": "aGVsbG8="
}
},
{
"name": "the versions held",
"of": "verb:versions.answer",
"given": {
"name": "mesh-sdk",
"versions": [
{
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc"
}
]
}
},
{
"name": "a release of what is not held answers released false",
"of": "verb:release.answer",
"why": "A3t: the outcome asked holds already, so it is no error",
"given": {
"released": false
}
},
{
"name": "a tagged version sharing its digest with another tag is kept, not removed",
"of": "verb:remove.answer",
"why": "G-sdk-contracts 3: the store cannot remove the tag alone, so the answer says what holds",
"given": {
"removed": false,
"kept": true,
"reason": "shared-digest",
"tags": [
"0.1.19"
]
}
},
{
"name": "list answers an index with its platforms, its tag and its hold",
"of": "verb:list.answer",
"given": {
"repositories": [
{
"name": "mail/server",
"manifests": [
{
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"index": true,
"platforms": [
"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
],
"tags": [
"3"
],
"size": 2048,
"held": false
},
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"index": false,
"size": 1024,
"held": false
}
]
}
]
}
}
]
-345
View File
@@ -1,345 +0,0 @@
{
"format": 1,
"seat": "container-image-registry",
"scope": "mesh",
"grain": "whole",
"domain": "Delivery",
"decision": "novox/hq ADR 0605",
"description": "The mesh's container images, in the one artifact store: the OCI distribution protocol's read side, an image's tags and mirroring an outside image.",
"includes": [
"registry"
],
"verbs": [
{
"name": "mirror",
"description": "Copy an outside image into the store by its pinned digest; emits published or refused.",
"callers": "mesh-build-image's holder of the image build seat",
"input": {
"type": "object",
"properties": {
"source": {
"type": "string",
"description": "the outside image's reference"
},
"digest": {
"type": "string",
"description": "its pinned digest, sha256:<hex>"
},
"name": {
"type": "string",
"description": "the name it is kept under"
}
},
"required": [
"source",
"digest",
"name"
]
},
"answer": {
"type": "object",
"properties": {
"reference": {
"type": "string",
"description": "the reference the seat answers"
},
"digest": {
"type": "string",
"description": "the digest stored"
}
},
"required": [
"reference",
"digest"
]
},
"optional": true
},
{
"name": "tags",
"description": "The tags of one image and the digest each names.",
"callers": "any caller whose role grants it",
"input": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the image"
}
},
"required": [
"name"
]
},
"answer": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the image"
},
"tags": {
"type": "array",
"items": {
"type": "object",
"properties": {
"tag": {
"type": "string",
"description": "the tag"
},
"digest": {
"type": "string",
"description": "its digest"
}
},
"required": [
"tag",
"digest"
]
},
"description": "every tag"
}
},
"required": [
"name",
"tags"
]
},
"optional": true
},
{
"name": "hold",
"description": "Keep one untagged bundle, archive or copied base from removal by retention, as the artifact sweep's rules keep it (ADR 0617 §2); never an image of the holder's own. Emits held.",
"callers": "the module that runs the artifact sweep alone",
"input": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the name"
},
"digest": {
"type": "string",
"description": "the digest"
},
"reason": {
"type": "string",
"description": "which of the sweep's rules keeps it"
}
},
"required": [
"name",
"digest",
"reason"
]
},
"answer": {
"type": "object",
"properties": {
"held": {
"type": "boolean",
"description": "it is held"
},
"since": {
"type": "string",
"description": "when the hold began, RFC 3339"
}
},
"required": [
"held"
]
},
"optional": true
},
{
"name": "release",
"description": "Let a hold go; emits released. A release of what is not held answers released false and emits nothing, never an error: the outcome asked holds already. By hand only through the holder's own tool, the operator's session as the proved caller, recorded as a hand act.",
"callers": "the module that runs the artifact sweep; the operator's session through the holder's tool",
"input": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the name"
},
"digest": {
"type": "string",
"description": "the digest"
},
"reason": {
"type": "string",
"description": "why it is let go"
}
},
"required": [
"name",
"digest",
"reason"
]
},
"answer": {
"type": "object",
"properties": {
"released": {
"type": "boolean",
"description": "a hold was let go; false when there was none"
}
},
"required": [
"released"
]
},
"optional": true
},
{
"name": "list",
"description": "What the store holds of one repository, or of every repository the seat holds when none is named: every image manifest and index, each with its digest, whether it is an index (and the manifests an index names), the tags naming it, its size and whether it is held. Read from the store itself, so a manifest no tag names is listed too; it reads only (ADR 0632 §3).",
"callers": "any caller whose role grants it",
"input": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the repository, <module>/<artifact>; every repository of the seat when not given"
}
}
},
"answer": {
"type": "object",
"properties": {
"repositories": {
"type": "array",
"items": {
"$ref": "#/defs/Repository"
},
"description": "each repository named, in order of its name"
}
},
"required": [
"repositories"
]
},
"optional": true
}
],
"events": [
{
"name": "held",
"body": {
"$ref": "#/defs/Hold"
}
},
{
"name": "released",
"body": {
"$ref": "#/defs/Hold"
}
}
],
"family": {
"name": "container-image-registry.events",
"max-age-days": 7
},
"defs": {
"Hold": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the name"
},
"digest": {
"type": "string",
"description": "the digest"
},
"reason": {
"type": "string",
"description": "why"
},
"holder": {
"type": "string",
"description": "the module holding the seat"
},
"by": {
"type": "string",
"description": "the caller the holder proved"
},
"at": {
"type": "string",
"description": "when, RFC 3339"
}
},
"required": [
"name",
"digest",
"holder"
],
"description": "the body of held and released"
},
"Repository": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the repository"
},
"manifests": {
"type": "array",
"items": {
"$ref": "#/defs/Listed"
},
"description": "each manifest it holds, by digest"
}
},
"required": [
"name",
"manifests"
]
},
"Listed": {
"type": "object",
"properties": {
"digest": {
"type": "string",
"description": "the manifest's digest, sha256:<hex>"
},
"index": {
"type": "boolean",
"description": "it is an index, naming a manifest per platform"
},
"platforms": {
"type": "array",
"items": {
"type": "string"
},
"description": "for an index, the digests of the manifests it names"
},
"artifact": {
"type": "string",
"description": "for a manifest keeping one bundle or archive, the digest of that blob: what a reference names it by"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "the tags naming it, none for an untagged one"
},
"size": {
"type": "integer",
"description": "its bytes: its own content and every blob it names"
},
"held": {
"type": "boolean",
"description": "a hold keeps it from retention"
}
},
"required": [
"digest",
"index",
"size",
"held"
]
}
}
}
-9
View File
@@ -1,9 +0,0 @@
{
"format": 1,
"seat": "git",
"scope": "mesh",
"grain": "seat-list",
"domain": "Delivery",
"decision": "novox/hq ADR 0111",
"delivers": "git"
}
@@ -1,73 +0,0 @@
[
{
"name": "published on the seat's subject",
"of": "event:published",
"subject": "mesh.seat.go-package-registry.event.published",
"given": {
"name": "git.novox.be/novox/mesh-sdk/go",
"module": "git.novox.be/novox/mesh-sdk/go",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "gitea",
"transfer": "t1",
"reference": "git.novox.be/novox/mesh-sdk/go@0.1.19"
}
},
{
"name": "refused on the seat's subject",
"of": "event:refused",
"subject": "mesh.seat.go-package-registry.event.refused",
"given": {
"name": "git.novox.be/novox/mesh-sdk/go",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "gitea",
"transfer": "t1",
"reference": "git.novox.be/novox/mesh-sdk/go@0.1.19",
"reason": "retention"
}
},
{
"name": "removed on the seat's subject",
"of": "event:removed",
"subject": "mesh.seat.go-package-registry.event.removed",
"given": {
"name": "git.novox.be/novox/mesh-sdk/go",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "gitea",
"transfer": "t1",
"reference": "git.novox.be/novox/mesh-sdk/go@0.1.19",
"reason": "retention"
}
},
{
"name": "kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it",
"of": "event:kept",
"subject": "mesh.seat.go-package-registry.event.kept",
"given": {
"name": "git.novox.be/novox/mesh-sdk/go",
"version": "0.1.19-feat-x.2",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "gitea",
"reference": "git.novox.be/novox/mesh-sdk/go@0.1.19",
"reason": "shared-digest",
"tag": "0.1.19-feat-x.2",
"tags": [
"0.1.19"
]
}
}
]
@@ -1,110 +0,0 @@
[
{
"name": "publish opens a transfer",
"of": "verb:publish.input",
"given": {
"name": "git.novox.be/novox/mesh-sdk/go",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
]
}
},
{
"name": "a field the reader does not know is dropped",
"of": "verb:publish.input",
"why": "ADR 0608 §6: a reader ignores a field it does not know",
"given": {
"name": "git.novox.be/novox/mesh-sdk/go",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
],
"later": {
"x": 1
}
},
"wire": {
"name": "git.novox.be/novox/mesh-sdk/go",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
]
}
},
{
"name": "publish answers what it lacks",
"of": "verb:publish.answer",
"given": {
"transfer": "t1",
"lacks": [
"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
]
}
},
{
"name": "a chunk of a part",
"of": "verb:publish-part.input",
"given": {
"transfer": "t1",
"part": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"sequence": 0,
"last": true,
"data": "aGVsbG8="
}
},
{
"name": "the versions held",
"of": "verb:versions.answer",
"given": {
"name": "git.novox.be/novox/mesh-sdk/go",
"versions": [
{
"name": "git.novox.be/novox/mesh-sdk/go",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc"
}
]
}
},
{
"name": "a tagged version sharing its digest with another tag is kept, not removed",
"of": "verb:remove.answer",
"why": "G-sdk-contracts 3: the store cannot remove the tag alone, so the answer says what holds",
"given": {
"removed": false,
"kept": true,
"reason": "shared-digest",
"tags": [
"0.1.19"
]
}
}
]
-35
View File
@@ -1,35 +0,0 @@
{
"format": 1,
"seat": "go-package-registry",
"scope": "mesh",
"grain": "whole",
"domain": "Delivery",
"decision": "novox/hq ADR 0605",
"description": "The mesh's Go modules: Go's module proxy protocol's read side, and publishing over the bus.",
"delivers": "go-package-registry",
"includes": [
"registry"
],
"family": {
"name": "go-package-registry.events",
"max-age-days": 7
},
"provisions": [
{
"name": "go-package-registry",
"form": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "the read side's address"
}
},
"required": [
"url"
],
"description": "form none: the Go module proxy's read side, answered anonymously, with no credential (design 51)"
}
}
]
}
-8
View File
@@ -1,8 +0,0 @@
{
"format": 1,
"seat": "mesh-artifact-store",
"scope": "mesh",
"grain": "seat-list",
"domain": "Delivery",
"decision": "novox/hq ADR 0075"
}
-104
View File
@@ -1,104 +0,0 @@
{
"format": 1,
"seat": "mesh-artifact-sweep",
"scope": "mesh",
"grain": "seat-list",
"domain": "Delivery",
"decision": "novox/hq ADR 0571",
"verbs": [
{
"name": "artifacts",
"description": "Every artifact the mesh made that lives in its artifact store, each with its repository, digest, kind (image or archive) and state: kept, and why (a want names it, or one of the five newest builds of its module in the builder's log), eligible (made, kept for no reason, not yet let go), or unrecorded (in the store and named by nothing the mesh made: never removed). Reads only.",
"input": {
"properties": {
"collected": {
"description": "\"true\": list the collected references too (counted always)",
"enum": [
"true",
"false"
],
"type": "string"
},
"repository": {
"description": "only this repository's references, as \u003cmodule\u003e/\u003cartifact\u003e (the counts stay whole)",
"type": "string"
}
},
"type": "object"
}
},
{
"name": "held",
"description": "Whether the artifact store holds each reference given, asked with one HEAD each: held, gone (the store answered 404) or unknown with why. The builder asks it before it reuses a done key. Reads only.",
"input": {
"properties": {
"references": {
"description": "the artifacts' references, artifact-store://\u003cmodule\u003e/\u003cartifact\u003e/blobs/sha256:\u003chex\u003e: a list, or one text separated by commas",
"items": {
"type": "string"
},
"type": "array"
}
},
"required": [
"references"
],
"type": "object"
}
},
{
"name": "collect",
"description": "The artifact store's sweep, now: what is eligible is let go of. Without confirm a dry run: what would be let go, nothing held or deleted. With confirm and why: every kept archive held first, then each eligible artifact let go of, oldest first, an index with the platform manifests no kept index names, each deletion recorded in the hand-act log. Bounded by most (500 by default, at most 5000) and 45 seconds; what is left is said. Never touches a digest the mesh did not make.",
"input": {
"properties": {
"confirm": {
"description": "\"true\": let go of what is eligible (needs why); without it nothing is done",
"enum": [
"true",
"false"
],
"type": "string"
},
"most": {
"description": "let go of at most this many (500 by default, at most 5000)",
"type": "string"
},
"why": {
"description": "with confirm: why, required and recorded",
"type": "string"
}
},
"type": "object"
}
},
{
"name": "mirrors",
"description": "The bases the mesh copied into its artifact store, each kept (a kept build stood on it), eligible (only builds no longer kept stood on it) or unrecorded (no build the builder's log holds stood on it: never removed), by what the builder's log says each build stood on. Records nothing by hand.",
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "images",
"description": "Every container image one machine's want and have name, each with the resources naming it: what the machine keeps when it prunes its images. Reads only.",
"input": {
"properties": {
"node": {
"description": "the machine's name",
"type": "string"
}
},
"required": [
"node"
],
"type": "object"
}
}
],
"events": [
{
"name": "artifacts-gone"
}
]
}
-70
View File
@@ -1,70 +0,0 @@
{
"format": 1,
"seat": "mesh-catalog",
"scope": "mesh",
"grain": "seat-list",
"domain": "Delivery",
"decision": "novox/hq ADR 0604",
"verbs": [
{
"name": "modules",
"description": "Every module the trunk holds, each with its repository, its directory there, the merge commit it was last changed at and its fingerprint (or why it has none): the catalog of the mesh, read from its holder's state. Reads only.",
"optional": true,
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "module",
"description": "One module whole: its repository, directory, commit and fingerprint, and its manifest as the trunk holds it. Older versions are in its repository's history. Reads only.",
"optional": true,
"input": {
"properties": {
"module": {
"description": "the module's name",
"type": "string"
}
},
"required": [
"module"
],
"type": "object"
}
},
{
"name": "provides",
"description": "Which modules provide a provision (a module provides its own name too) and which require it, from the module graph's provision edges. Reads only.",
"optional": true,
"input": {
"properties": {
"provision": {
"description": "the provision, such as postgres-database",
"type": "string"
}
},
"required": [
"provision"
],
"type": "object"
}
},
{
"name": "dependents",
"description": "The modules whose build edges reach a module, directly or through others (a base, a mesh package it publishes, the build module that builds them): what a change of it builds again, from the module graph. Reads only.",
"optional": true,
"input": {
"properties": {
"module": {
"description": "the module's name",
"type": "string"
}
},
"required": [
"module"
],
"type": "object"
}
}
]
}
@@ -1,44 +0,0 @@
[
{
"name": "verdict on the checker's own family",
"of": "holder-event:verdict",
"subject": "mesh.stream.mesh-delivery-checker.event.verdict",
"given": {
"repository": "novox/mesh-contracts",
"pull": 3,
"head": "cccccccccccccccccccccccccccccccccccccccc",
"verdict": "fail",
"out-of-step": [
"go/seats/meshbroker/contract.go"
],
"series": [
{
"module": "mesh-contracts",
"artifact": "go",
"from": "0.1",
"to": "0.2"
}
]
}
},
{
"name": "tag-wanted on the checker's own family",
"of": "holder-event:tag-wanted",
"subject": "mesh.stream.mesh-delivery-checker.event.tag-wanted",
"given": {
"repository": "novox/mesh-sdk",
"pull": 170,
"head": "cccccccccccccccccccccccccccccccccccccccc",
"branch": "feat/registry",
"module": "mesh-sdk",
"package": "go",
"tag": "registry-1966"
}
},
{
"name": "preview.written on the checker's stream",
"of": "holder-event:preview.written",
"subject": "mesh.stream.mesh-delivery-checker.event.preview.written",
"given": {}
}
]
-246
View File
@@ -1,246 +0,0 @@
{
"format": 1,
"seat": "mesh-delivery-checker",
"scope": "mesh",
"grain": "whole",
"domain": "Delivery",
"decision": "novox/hq ADR 0547",
"verbs": [
{
"name": "try",
"description": "Try a pushed head before its pull request is opened: the checker judges it as it judges a pull request's head, merged onto its trunk's head, its unit and integration levels through the build modules, and owes the forge nothing. Answers the try's id at once; try-read reads where it stands. A try of the same head that waits or runs is the answer to a second ask; at most 4 wait or run at once, mesh-wide.",
"optional": true,
"replaces": [
"sh merge-check.sh",
"docker run postgres"
],
"input": {
"properties": {
"head": {
"description": "the full commit to try, 40 or 64 hex digits",
"type": "string"
},
"level": {
"description": "unit or integration: only this level; both when absent",
"type": "string"
},
"repository": {
"description": "<owner>/<name>",
"type": "string"
},
"tests": {
"description": "a go test -run pattern: only those tests run, and nothing is kept",
"type": "string"
},
"trunk": {
"description": "the trunk commit to merge it onto, or the trunk's branch for its head now; the trunk's head when absent",
"type": "string"
}
},
"required": [
"repository",
"head"
],
"type": "object"
},
"answer": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "the try's id"
},
"state": {
"type": "string",
"description": "its state"
}
},
"required": [
"id"
]
}
},
{
"name": "try-read",
"description": "Where a try stands, as stored: queued, running, or its end (pass, fail, or error when it could not run), with what was said of it, the head and the trunk commit it was merged onto, the time it took and what failed first. Read-only.",
"optional": true,
"input": {
"properties": {
"id": {
"description": "the try's id, try-<digits>",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"answer": {
"type": "object",
"description": "the try: its state, its steps and its verdict when it has one"
}
},
{
"name": "try-end",
"description": "End a try that waits or runs, as error, by hand: say why (kept in what it says). Its place among the tries is free at once and the next try of its head asks anew with a new id. A try that ended already is refused.",
"optional": true,
"input": {
"properties": {
"id": {
"description": "the try's id, try-<digits>",
"type": "string"
},
"why": {
"description": "why it is ended, in words",
"type": "string"
}
},
"required": [
"id",
"why"
],
"type": "object"
},
"answer": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "the try"
},
"ended": {
"type": "boolean",
"description": "it is ended"
}
},
"required": [
"id",
"ended"
]
}
}
],
"description": "The merge check's tries: start one, read one, end one. The checker's own events stay under its own subjects (ADR 0620 §2).",
"holder-events": [
{
"name": "verdict",
"subject": "mesh.stream.<holder>.event.verdict",
"family": "checker.asks",
"body": {
"type": "object",
"properties": {
"repository": {
"type": "string",
"description": "owner/repo"
},
"pull": {
"type": "integer",
"description": "the pull request's number, for a pull request's check"
},
"head": {
"type": "string",
"description": "the commit checked"
},
"verdict": {
"type": "string",
"description": "pass or fail"
},
"out-of-step": {
"type": "array",
"items": {
"type": "string"
},
"description": "the generated files out of step with their seat definitions, each path (design 26)"
},
"series": {
"type": "array",
"items": {
"type": "object",
"properties": {
"module": {
"type": "string",
"description": "the module whose artifact's series changes"
},
"artifact": {
"type": "string",
"description": "its artifact, or the package's ecosystem name as the module's packages name it"
},
"from": {
"type": "string",
"description": "the series on trunk"
},
"to": {
"type": "string",
"description": "the series the checked head gives it"
}
},
"required": [
"module",
"artifact",
"from",
"to"
]
},
"description": "each change of an artifact's series the checked head makes against trunk's manifests, once each (design 32); absent when it changes none"
}
},
"required": [
"repository",
"head",
"verdict"
]
}
},
{
"name": "tag-wanted",
"subject": "mesh.stream.<holder>.event.tag-wanted",
"family": "checker.asks",
"body": {
"type": "object",
"properties": {
"repository": {
"type": "string",
"description": "owner/repo"
},
"pull": {
"type": "integer",
"description": "the pull request"
},
"head": {
"type": "string",
"description": "its head"
},
"branch": {
"type": "string",
"description": "the pull request's branch: its tag is removed when the branch ends"
},
"module": {
"type": "string",
"description": "the group member"
},
"package": {
"type": "string",
"description": "the package it declares"
},
"tag": {
"type": "string",
"description": "the tag wanted"
}
},
"required": [
"repository",
"head",
"branch",
"module",
"package"
]
}
},
{
"name": "preview.written",
"subject": "mesh.stream.<holder>.event.preview.written",
"family": "checks"
}
]
}
-227
View File
@@ -1,227 +0,0 @@
{
"format": 1,
"seat": "mesh-delivery",
"scope": "mesh",
"grain": "seat-list",
"domain": "Delivery",
"decision": "novox/hq ADR 0239",
"verbs": [
{
"name": "deliveries",
"description": "Every delivery not final, and those that ended in the last day, one line each: its id (owner/repository@commit), its state, its group, what it waits for and since when. Narrowed by state, repository or group.",
"input": {
"properties": {
"all": {
"description": "\"true\": the final ones of the last thirty days too",
"enum": [
"true",
"false"
],
"type": "string"
},
"group": {
"description": "a group's id (its branch name)",
"type": "string"
},
"repository": {
"description": "owner/repository",
"type": "string"
},
"state": {
"description": "one state, e.g. delivering or held",
"type": "string"
}
},
"type": "object"
}
},
{
"name": "times",
"description": "Removed in R6 (ADR 0539): refused by name, naming its replacement: the delivery view (nox-delivery): each machine's want and have, and since when",
"optional": true,
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "show",
"description": "One delivery or group whole: its delivery plan (what it builds, what each machine receives, what is not an ordinary send), every transition with when and why, the machine steps of its walk, its group and its order.",
"input": {
"properties": {
"id": {
"description": "a delivery's id, or a group's",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
}
},
{
"name": "groups",
"description": "Every delivery group: its members in order, why each pair is ordered (declared, built by, version skew, engine before controller, by name), its composed check and its state, derived from its members.",
"input": {
"properties": {
"all": {
"description": "\"true\": the groups that ended too",
"enum": [
"true",
"false"
],
"type": "string"
}
},
"type": "object"
}
},
{
"name": "what-if",
"description": "Removed in R6 (ADR 0539): refused by name, naming its replacement: the merge check's composition, which composes every machine a change touches",
"optional": true,
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "checks",
"description": "What the mesh's checks said of a pull request's head or of one commit: each of the commit's mesh statuses (mesh/check, the one a main requires from R4e, hq's mesh/repo-check, mesh/delivery, …) with its state, description and when it was set; the merge check's full verdict as the controller said it — each layer's summary, the machine that ran it, when, its build id and its report; and whether the branch's protection would let it merge, every required status being success.",
"optional": true,
"input": {
"properties": {
"commit": {
"description": "a commit's sha, or the start of one, instead of a pull request",
"type": "string"
},
"number": {
"description": "a pull request's number: its head is read",
"type": "string"
},
"repository": {
"description": "owner/repository",
"type": "string"
}
},
"required": [
"repository"
],
"type": "object"
}
},
{
"name": "table",
"description": "The state table every delivery runs by: each transition with its guard, each state's bound and what healer H2 may do once it has passed; and the machine steps' table.",
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "stalled",
"description": "Every delivery held past its state's bound, with the transition the table lets healer H2 take for it, or none.",
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "recheck",
"description": "Check a rejected or ready delivery again: it goes back to proposed and the controller is asked for its check. With why.",
"input": {
"properties": {
"id": {
"description": "the delivery's id",
"type": "string"
},
"why": {
"description": "why, kept with the transition",
"type": "string"
}
},
"required": [
"id",
"why"
],
"type": "object"
}
},
{
"name": "release",
"description": "Removed in R6 (ADR 0539): refused by name, naming its replacement: the assigner's asks (hold, restore, backup, record), answered on the phone or in the delivery view",
"optional": true,
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "stop",
"description": "Removed in R6 (ADR 0539): refused by name, naming its replacement: a bad fingerprint is held and its canary set back by the assigner (ADR 0429 §6, ADR 0539 clause 18)",
"optional": true,
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "close",
"description": "Healer H2's verb: take the one transition the table names for a delivery held past its bound. Refused for any other.",
"input": {
"properties": {
"id": {
"description": "the delivery's id",
"type": "string"
},
"why": {
"description": "the condition it answers",
"type": "string"
}
},
"required": [
"id",
"why"
],
"type": "object"
}
},
{
"name": "retire-history",
"description": "Removed in R6 (ADR 0539): refused by name, naming its replacement: nothing to retire: the gate keeps no delivery after its merge",
"optional": true,
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "settle",
"description": "Ask the operator to settle deliveries held because their merge reached the trunk without a passing check: one ask on the operator's channel for all of them, as an Approve is asked. The verb moves nothing; on the operator's answer each goes to merged, and whether it is on the machines is derived as for any merge (novox/hq ADR 0556). Refused for a delivery not held, or held for another reason, naming why.",
"optional": true,
"input": {
"additionalProperties": false,
"properties": {
"ids": {
"description": "the held deliveries' ids (owner/repository@commit)",
"items": {
"type": "string"
},
"minItems": 1,
"type": "array"
},
"why": {
"description": "why they may be settled, shown to the operator",
"type": "string"
}
},
"required": [
"ids",
"why"
],
"type": "object"
}
}
]
}
-47
View File
@@ -1,47 +0,0 @@
{
"format": 1,
"seat": "node-build-go",
"scope": "node",
"grain": "seat-list",
"domain": "Delivery",
"decision": "novox/hq ADR 0525, ADR 0536, ADR 0553",
"pulled-by-kind": true,
"yields": true,
"verbs": [
{
"name": "current",
"description": "The Go asks this node runs now (each ask's id, kind, module and when it started), its build capacity, and whether it is paused, taking no new ask.",
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "pause",
"description": "Take no new Go ask on this node until resumed; an ask running here ends in its place. Kept across a restart of the build module (its pause key). A capacity of 0 is the lasting way to keep a node from building.",
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "resume",
"description": "Take Go asks again on this node.",
"input": {
"properties": {},
"type": "object"
}
}
],
"accepts": [
{
"name": "delivery"
},
{
"name": "check"
},
{
"name": "recheck"
}
]
}
-47
View File
@@ -1,47 +0,0 @@
{
"format": 1,
"seat": "node-build-image",
"scope": "node",
"grain": "seat-list",
"domain": "Delivery",
"decision": "novox/hq ADR 0525, ADR 0536, ADR 0553",
"pulled-by-kind": true,
"yields": true,
"verbs": [
{
"name": "current",
"description": "The image asks this node runs now (each ask's id, kind, module and when it started), its build capacity, and whether it is paused, taking no new ask.",
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "pause",
"description": "Take no new image ask on this node until resumed; an ask running here ends in its place. Kept across a restart of the build module (its pause key). A capacity of 0 is the lasting way to keep a node from building.",
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "resume",
"description": "Take image asks again on this node.",
"input": {
"properties": {},
"type": "object"
}
}
],
"accepts": [
{
"name": "delivery"
},
{
"name": "check"
},
{
"name": "recheck"
}
]
}
-47
View File
@@ -1,47 +0,0 @@
{
"format": 1,
"seat": "node-build-node",
"scope": "node",
"grain": "seat-list",
"domain": "Delivery",
"decision": "novox/hq ADR 0525, ADR 0536, ADR 0553",
"pulled-by-kind": true,
"yields": true,
"verbs": [
{
"name": "current",
"description": "The Node asks this node runs now (each ask's id, kind, module and when it started), its build capacity, and whether it is paused, taking no new ask.",
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "pause",
"description": "Take no new Node ask on this node until resumed; an ask running here ends in its place. Kept across a restart of the build module (its pause key). A capacity of 0 is the lasting way to keep a node from building.",
"input": {
"properties": {},
"type": "object"
}
},
{
"name": "resume",
"description": "Take Node asks again on this node.",
"input": {
"properties": {},
"type": "object"
}
}
],
"accepts": [
{
"name": "delivery"
},
{
"name": "check"
},
{
"name": "recheck"
}
]
}
@@ -1,72 +0,0 @@
[
{
"name": "published on the seat's subject",
"of": "event:published",
"subject": "mesh.seat.npm-package-registry.event.published",
"given": {
"name": "@novox/mesh-sdk",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "gitea",
"transfer": "t1",
"reference": "@novox/mesh-sdk@0.1.19"
}
},
{
"name": "refused on the seat's subject",
"of": "event:refused",
"subject": "mesh.seat.npm-package-registry.event.refused",
"given": {
"name": "@novox/mesh-sdk",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "gitea",
"transfer": "t1",
"reference": "@novox/mesh-sdk@0.1.19",
"reason": "retention"
}
},
{
"name": "removed on the seat's subject",
"of": "event:removed",
"subject": "mesh.seat.npm-package-registry.event.removed",
"given": {
"name": "@novox/mesh-sdk",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "gitea",
"transfer": "t1",
"reference": "@novox/mesh-sdk@0.1.19",
"reason": "retention"
}
},
{
"name": "kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it",
"of": "event:kept",
"subject": "mesh.seat.npm-package-registry.event.kept",
"given": {
"name": "@novox/mesh-sdk",
"version": "0.1.19-feat-x.2",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "gitea",
"reference": "@novox/mesh-sdk@0.1.19",
"reason": "shared-digest",
"tag": "0.1.19-feat-x.2",
"tags": [
"0.1.19"
]
}
}
]
@@ -1,110 +0,0 @@
[
{
"name": "publish opens a transfer",
"of": "verb:publish.input",
"given": {
"name": "@novox/mesh-sdk",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
]
}
},
{
"name": "a field the reader does not know is dropped",
"of": "verb:publish.input",
"why": "ADR 0608 §6: a reader ignores a field it does not know",
"given": {
"name": "@novox/mesh-sdk",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
],
"later": {
"x": 1
}
},
"wire": {
"name": "@novox/mesh-sdk",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
]
}
},
{
"name": "publish answers what it lacks",
"of": "verb:publish.answer",
"given": {
"transfer": "t1",
"lacks": [
"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
]
}
},
{
"name": "a chunk of a part",
"of": "verb:publish-part.input",
"given": {
"transfer": "t1",
"part": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"sequence": 0,
"last": true,
"data": "aGVsbG8="
}
},
{
"name": "the versions held",
"of": "verb:versions.answer",
"given": {
"name": "@novox/mesh-sdk",
"versions": [
{
"name": "@novox/mesh-sdk",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc"
}
]
}
},
{
"name": "a tagged version sharing its digest with another tag is kept, not removed",
"of": "verb:remove.answer",
"why": "G-sdk-contracts 3: the store cannot remove the tag alone, so the answer says what holds",
"given": {
"removed": false,
"kept": true,
"reason": "shared-digest",
"tags": [
"0.1.19"
]
}
}
]
-35
View File
@@ -1,35 +0,0 @@
{
"format": 1,
"seat": "npm-package-registry",
"scope": "mesh",
"grain": "whole",
"domain": "Delivery",
"decision": "novox/hq ADR 0109",
"description": "The mesh's npm packages: the npm registry protocol's read side, and publishing over the bus.",
"delivers": "npm-package-registry",
"includes": [
"registry"
],
"family": {
"name": "npm-package-registry.events",
"max-age-days": 7
},
"provisions": [
{
"name": "npm-package-registry",
"form": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "the read side's address"
}
},
"required": [
"url"
],
"description": "form none: the npm registry's read side, answered anonymously, with no credential (design 51)"
}
}
]
}
@@ -1,98 +0,0 @@
[
{
"name": "published on the seat's subject",
"of": "event:published",
"subject": "mesh.seat.oci-artifact-registry.event.published",
"given": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "bundle",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "distribution",
"transfer": "t1",
"reference": "oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
},
{
"name": "refused on the seat's subject",
"of": "event:refused",
"subject": "mesh.seat.oci-artifact-registry.event.refused",
"given": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "bundle",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "distribution",
"transfer": "t1",
"reference": "oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"reason": "retention"
}
},
{
"name": "removed on the seat's subject",
"of": "event:removed",
"subject": "mesh.seat.oci-artifact-registry.event.removed",
"given": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "bundle",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "distribution",
"transfer": "t1",
"reference": "oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"reason": "retention"
}
},
{
"name": "kept on the seat's subject: a tagged version sharing its digest stays, naming the tags on it",
"of": "event:kept",
"subject": "mesh.seat.oci-artifact-registry.event.kept",
"given": {
"name": "mesh-sdk",
"version": "0.1.19-feat-x.2",
"kind": "bundle",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"holder": "distribution",
"reference": "oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"reason": "shared-digest",
"tag": "0.1.19-feat-x.2",
"tags": [
"0.1.19"
]
}
},
{
"name": "held on the seat's subject",
"of": "event:held",
"subject": "mesh.seat.oci-artifact-registry.event.held",
"given": {
"name": "mesh-sdk",
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"reason": "kept by the sweep's rule",
"holder": "distribution",
"by": "mesh-artifact-sweep",
"at": "2026-11-04T12:00:00Z"
}
},
{
"name": "released on the seat's subject",
"of": "event:released",
"subject": "mesh.seat.oci-artifact-registry.event.released",
"given": {
"name": "mesh-sdk",
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"reason": "kept by the sweep's rule",
"holder": "distribution",
"by": "mesh-artifact-sweep",
"at": "2026-11-04T12:00:00Z"
}
}
]
@@ -1,138 +0,0 @@
[
{
"name": "publish opens a transfer",
"of": "verb:publish.input",
"given": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "bundle",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
]
}
},
{
"name": "a field the reader does not know is dropped",
"of": "verb:publish.input",
"why": "ADR 0608 §6: a reader ignores a field it does not know",
"given": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "bundle",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
],
"later": {
"x": 1
}
},
"wire": {
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "bundle",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc",
"transfer": "t1",
"parts": [
{
"digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"size": 1048576
}
]
}
},
{
"name": "publish answers what it lacks",
"of": "verb:publish.answer",
"given": {
"transfer": "t1",
"lacks": [
"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
]
}
},
{
"name": "a chunk of a part",
"of": "verb:publish-part.input",
"given": {
"transfer": "t1",
"part": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"sequence": 0,
"last": true,
"data": "aGVsbG8="
}
},
{
"name": "the versions held",
"of": "verb:versions.answer",
"given": {
"name": "mesh-sdk",
"versions": [
{
"name": "mesh-sdk",
"version": "0.1.19",
"kind": "package",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"fingerprint": "f1",
"commit": "cccccccccccccccccccccccccccccccccccccccc"
}
]
}
},
{
"name": "a release of what is not held answers released false",
"of": "verb:release.answer",
"why": "A3t: the outcome asked holds already, so it is no error",
"given": {
"released": false
}
},
{
"name": "a tagged version sharing its digest with another tag is kept, not removed",
"of": "verb:remove.answer",
"why": "G-sdk-contracts 3: the store cannot remove the tag alone, so the answer says what holds",
"given": {
"removed": false,
"kept": true,
"reason": "shared-digest",
"tags": [
"0.1.19"
]
}
},
{
"name": "list answers an untagged archive by the blob it keeps",
"of": "verb:list.answer",
"given": {
"repositories": [
{
"name": "mail/files",
"manifests": [
{
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"index": false,
"artifact": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"size": 4096,
"held": true
}
]
}
]
}
}
]
-248
View File
@@ -1,248 +0,0 @@
{
"format": 1,
"seat": "oci-artifact-registry",
"scope": "mesh",
"grain": "whole",
"domain": "Delivery",
"decision": "novox/hq ADR 0605",
"description": "The mesh's bundles and archives, by digest, in the one artifact store: the OCI distribution protocol's read side.",
"includes": [
"registry"
],
"verbs": [
{
"name": "hold",
"description": "Keep one untagged bundle, archive or copied base from removal by retention, as the artifact sweep's rules keep it (ADR 0617 §2); never an image of the holder's own. Emits held.",
"callers": "the module that runs the artifact sweep alone",
"input": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the name"
},
"digest": {
"type": "string",
"description": "the digest"
},
"reason": {
"type": "string",
"description": "which of the sweep's rules keeps it"
}
},
"required": [
"name",
"digest",
"reason"
]
},
"answer": {
"type": "object",
"properties": {
"held": {
"type": "boolean",
"description": "it is held"
},
"since": {
"type": "string",
"description": "when the hold began, RFC 3339"
}
},
"required": [
"held"
]
},
"optional": true
},
{
"name": "release",
"description": "Let a hold go; emits released. A release of what is not held answers released false and emits nothing, never an error: the outcome asked holds already. By hand only through the holder's own tool, the operator's session as the proved caller, recorded as a hand act.",
"callers": "the module that runs the artifact sweep; the operator's session through the holder's tool",
"input": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the name"
},
"digest": {
"type": "string",
"description": "the digest"
},
"reason": {
"type": "string",
"description": "why it is let go"
}
},
"required": [
"name",
"digest",
"reason"
]
},
"answer": {
"type": "object",
"properties": {
"released": {
"type": "boolean",
"description": "a hold was let go; false when there was none"
}
},
"required": [
"released"
]
},
"optional": true
},
{
"name": "list",
"description": "What the store holds of one repository, or of every repository the seat holds when none is named: every manifest keeping one bundle or archive, each with its digest, whether it is an index (and the manifests an index names), the tags naming it, its size and whether it is held. Read from the store itself, so a manifest no tag names is listed too; it reads only (ADR 0632 §3).",
"callers": "any caller whose role grants it",
"input": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the repository, <module>/<artifact>; every repository of the seat when not given"
}
}
},
"answer": {
"type": "object",
"properties": {
"repositories": {
"type": "array",
"items": {
"$ref": "#/defs/Repository"
},
"description": "each repository named, in order of its name"
}
},
"required": [
"repositories"
]
},
"optional": true
}
],
"events": [
{
"name": "held",
"body": {
"$ref": "#/defs/Hold"
}
},
{
"name": "released",
"body": {
"$ref": "#/defs/Hold"
}
}
],
"family": {
"name": "oci-artifact-registry.events",
"max-age-days": 7
},
"defs": {
"Hold": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the name"
},
"digest": {
"type": "string",
"description": "the digest"
},
"reason": {
"type": "string",
"description": "why"
},
"holder": {
"type": "string",
"description": "the module holding the seat"
},
"by": {
"type": "string",
"description": "the caller the holder proved"
},
"at": {
"type": "string",
"description": "when, RFC 3339"
}
},
"required": [
"name",
"digest",
"holder"
],
"description": "the body of held and released"
},
"Repository": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "the repository"
},
"manifests": {
"type": "array",
"items": {
"$ref": "#/defs/Listed"
},
"description": "each manifest it holds, by digest"
}
},
"required": [
"name",
"manifests"
]
},
"Listed": {
"type": "object",
"properties": {
"digest": {
"type": "string",
"description": "the manifest's digest, sha256:<hex>"
},
"index": {
"type": "boolean",
"description": "it is an index, naming a manifest per platform"
},
"platforms": {
"type": "array",
"items": {
"type": "string"
},
"description": "for an index, the digests of the manifests it names"
},
"artifact": {
"type": "string",
"description": "for a manifest keeping one bundle or archive, the digest of that blob: what a reference names it by"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "the tags naming it, none for an untagged one"
},
"size": {
"type": "integer",
"description": "its bytes: its own content and every blob it names"
},
"held": {
"type": "boolean",
"description": "a hold keeps it from retention"
}
},
"required": [
"digest",
"index",
"size",
"held"
]
}
}
}
-12
View File
@@ -1,12 +0,0 @@
{
"lockfileVersion": 3,
"name": "@novox/mesh-contracts-container-image-registry",
"packages": {
"": {
"name": "@novox/mesh-contracts-container-image-registry",
"version": "0.1.0"
}
},
"requires": true,
"version": "0.1.0"
}
@@ -1,13 +0,0 @@
{
"description": "The contract of the seat container-image-registry, generated from its definition.",
"exports": {
".": "./src/index.ts"
},
"files": [
"src"
],
"name": "@novox/mesh-contracts-container-image-registry",
"type": "module",
"types": "./src/index.ts",
"version": "0.1.0"
}
@@ -1,190 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "container-image-registry", defined whole (seats/container-image-registry/seat.json): The mesh's container images, in the one artifact store: the OCI distribution protocol's read side, an image's tags and mirroring an outside image.
import type * as registry from "./parts/registry.js";
export const seat = "container-image-registry";
export const verbs = {
publish: "publish",
publishPart: "publish-part",
versions: "versions",
remove: "remove",
mirror: "mirror",
tags: "tags",
hold: "hold",
release: "release",
list: "list",
} as const;
export const events = {
published: "published",
refused: "refused",
removed: "removed",
kept: "kept",
held: "held",
released: "released",
} as const;
export const family = { name: "container-image-registry.events", maxAgeDays: 7 } as const;
export const publishedSubject = "mesh.seat.container-image-registry.event.published";
export const refusedSubject = "mesh.seat.container-image-registry.event.refused";
export const removedSubject = "mesh.seat.container-image-registry.event.removed";
export const keptSubject = "mesh.seat.container-image-registry.event.kept";
export const heldSubject = "mesh.seat.container-image-registry.event.held";
export const releasedSubject = "mesh.seat.container-image-registry.event.released";
export type Artifact = registry.Artifact;
export type KeptEvent = registry.KeptEvent;
export type Outcome = registry.Outcome;
export type Part = registry.Part;
export type PublishAnswer = registry.PublishAnswer;
export type PublishInput = registry.PublishInput;
export type PublishPartAnswer = registry.PublishPartAnswer;
export type PublishPartInput = registry.PublishPartInput;
export type PublishedEvent = registry.PublishedEvent;
export type RefusedEvent = registry.RefusedEvent;
export type RemoveAnswer = registry.RemoveAnswer;
export type RemoveInput = registry.RemoveInput;
export type RemovedEvent = registry.RemovedEvent;
export type VersionsAnswer = registry.VersionsAnswer;
export type VersionsInput = registry.VersionsInput;
/** the body of held and released */
export interface Hold {
/** when, RFC 3339 */
"at"?: string;
/** the caller the holder proved */
"by"?: string;
/** the digest */
"digest": string;
/** the module holding the seat */
"holder": string;
/** the name */
"name": string;
/** why */
"reason"?: string;
}
export interface Listed {
/** for a manifest keeping one bundle or archive, the digest of that blob: what a reference names it by */
"artifact"?: string;
/** the manifest's digest, sha256:<hex> */
"digest": string;
/** a hold keeps it from retention */
"held": boolean;
/** it is an index, naming a manifest per platform */
"index": boolean;
/** for an index, the digests of the manifests it names */
"platforms"?: string[];
/** its bytes: its own content and every blob it names */
"size": number;
/** the tags naming it, none for an untagged one */
"tags"?: string[];
}
export interface Repository {
/** each manifest it holds, by digest */
"manifests": Listed[];
/** the repository */
"name": string;
}
/** is what mirror takes. */
export interface MirrorInput {
/** its pinned digest, sha256:<hex> */
"digest": string;
/** the name it is kept under */
"name": string;
/** the outside image's reference */
"source": string;
}
/** is what mirror answers. */
export interface MirrorAnswer {
/** the digest stored */
"digest": string;
/** the reference the seat answers */
"reference": string;
}
/** is what tags takes. */
export interface TagsInput {
/** the image */
"name": string;
}
export interface TagsAnswerTagsItem {
/** its digest */
"digest": string;
/** the tag */
"tag": string;
}
/** is what tags answers. */
export interface TagsAnswer {
/** the image */
"name": string;
/** every tag */
"tags": TagsAnswerTagsItem[];
}
/** is what hold takes. */
export interface HoldInput {
/** the digest */
"digest": string;
/** the name */
"name": string;
/** which of the sweep's rules keeps it */
"reason": string;
}
/** is what hold answers. */
export interface HoldAnswer {
/** it is held */
"held": boolean;
/** when the hold began, RFC 3339 */
"since"?: string;
}
/** is what release takes. */
export interface ReleaseInput {
/** the digest */
"digest": string;
/** the name */
"name": string;
/** why it is let go */
"reason": string;
}
/** is what release answers. */
export interface ReleaseAnswer {
/** a hold was let go; false when there was none */
"released": boolean;
}
/** is what list takes. */
export interface ListInput {
/** the repository, <module>/<artifact>; every repository of the seat when not given */
"name"?: string;
}
/** is what list answers. */
export interface ListAnswer {
/** each repository named, in order of its name */
"repositories": Repository[];
}
/** is the body of the event held. */
export type HeldEvent = Hold;
/** is the body of the event released. */
export type ReleasedEvent = Hold;
@@ -1,187 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The part "registry" several seats include whole: The verbs and events every registry seat shares, written once so the four cannot drift (design 51, design 26). Who may call each verb is the holder's trusted config value listing its callers (ADR 0363's form), checked against the caller the tool runner proved.
export const verbs = {
publish: "publish",
publishPart: "publish-part",
versions: "versions",
remove: "remove",
} as const;
export const events = {
published: "published",
refused: "refused",
removed: "removed",
kept: "kept",
} as const;
/** one published thing, as every registry event and answer names it */
export interface Artifact {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** the tag it carries, for a tagged version */
"tag"?: string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** the body of published, refused and removed */
export interface Outcome {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** the module holding the seat that said it */
"holder": string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact */
"module"?: string;
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest) */
"reason"?: string;
/** the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9) */
"reference"?: string;
/** the tag it carries, for a tagged version */
"tag"?: string;
/** for kept: the other tags still naming its digest */
"tags"?: string[];
/** the transfer it ends, when it ended one */
"transfer"?: string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** one part of a transfer */
export interface Part {
/** the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob */
"digest": string;
/** its size in bytes */
"size": number;
}
/** is what publish takes. */
export interface PublishInput {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** every part's digest and size; none when the digest is already held */
"parts"?: Part[];
/** the tag it carries, for a tagged version */
"tag"?: string;
/** the transfer's name, the caller's own; the same name opens the same transfer again */
"transfer": string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** is what publish answers. */
export interface PublishAnswer {
/** the digest is held already: nothing to send; the outcome follows as an event */
"held"?: boolean;
/** the digests of the parts the holder lacks, to send by publish-part */
"lacks"?: string[];
/** the transfer */
"transfer": string;
}
/** is what publish-part takes. */
export interface PublishPartInput {
/** the chunk's bytes, base64 (at most 760 KiB before encoding) */
"data": string;
/** this chunk is the part's last */
"last": boolean;
/** the part's digest */
"part": string;
/** the chunk's place in its part, from 0 */
"sequence": number;
/** the transfer */
"transfer": string;
}
/** is what publish-part answers. */
export interface PublishPartAnswer {
/** the part is whole and its bytes match its digest */
"complete"?: boolean;
/** the part */
"part": string;
/** the chunks of the part held so far */
"received"?: number;
/** the transfer */
"transfer": string;
}
/** is what versions takes. */
export interface VersionsInput {
/** narrowed to one kind (optional) */
"kind"?: string;
/** the name */
"name": string;
}
/** is what versions answers. */
export interface VersionsAnswer {
/** the name */
"name": string;
/** newest first */
"versions": Artifact[];
}
/** is what remove takes. */
export interface RemoveInput {
/** the digest (for a bundle, archive or copied base) */
"digest"?: string;
/** the name */
"name": string;
/** why it goes */
"reason": "tag-gone" | "retention";
/** the tag (for a tagged version) */
"tag"?: string;
/** the version */
"version"?: string;
}
/** is what remove answers. */
export interface RemoveAnswer {
"artifact"?: Artifact;
/** it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags) */
"kept"?: boolean;
/** why it was kept: shared-digest, another tag names its digest */
"reason"?: "shared-digest";
/** it is gone */
"removed": boolean;
/** the other tags still naming its digest, when kept */
"tags"?: string[];
}
/** is the body of the event published. */
export type PublishedEvent = Outcome;
/** is the body of the event refused. */
export type RefusedEvent = Outcome;
/** is the body of the event removed. */
export type RemovedEvent = Outcome;
/** is the body of the event kept. */
export type KeptEvent = Outcome;
@@ -1,12 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
-12
View File
@@ -1,12 +0,0 @@
{
"lockfileVersion": 3,
"name": "@novox/mesh-contracts-go-package-registry",
"packages": {
"": {
"name": "@novox/mesh-contracts-go-package-registry",
"version": "0.1.0"
}
},
"requires": true,
"version": "0.1.0"
}
-13
View File
@@ -1,13 +0,0 @@
{
"description": "The contract of the seat go-package-registry, generated from its definition.",
"exports": {
".": "./src/index.ts"
},
"files": [
"src"
],
"name": "@novox/mesh-contracts-go-package-registry",
"type": "module",
"types": "./src/index.ts",
"version": "0.1.0"
}
-54
View File
@@ -1,54 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "go-package-registry", defined whole (seats/go-package-registry/seat.json): The mesh's Go modules: Go's module proxy protocol's read side, and publishing over the bus.
import type * as registry from "./parts/registry.js";
export const seat = "go-package-registry";
export const verbs = {
publish: "publish",
publishPart: "publish-part",
versions: "versions",
remove: "remove",
} as const;
export const events = {
published: "published",
refused: "refused",
removed: "removed",
kept: "kept",
} as const;
export const family = { name: "go-package-registry.events", maxAgeDays: 7 } as const;
export const publishedSubject = "mesh.seat.go-package-registry.event.published";
export const refusedSubject = "mesh.seat.go-package-registry.event.refused";
export const removedSubject = "mesh.seat.go-package-registry.event.removed";
export const keptSubject = "mesh.seat.go-package-registry.event.kept";
export type Artifact = registry.Artifact;
export type KeptEvent = registry.KeptEvent;
export type Outcome = registry.Outcome;
export type Part = registry.Part;
export type PublishAnswer = registry.PublishAnswer;
export type PublishInput = registry.PublishInput;
export type PublishPartAnswer = registry.PublishPartAnswer;
export type PublishPartInput = registry.PublishPartInput;
export type PublishedEvent = registry.PublishedEvent;
export type RefusedEvent = registry.RefusedEvent;
export type RemoveAnswer = registry.RemoveAnswer;
export type RemoveInput = registry.RemoveInput;
export type RemovedEvent = registry.RemovedEvent;
export type VersionsAnswer = registry.VersionsAnswer;
export type VersionsInput = registry.VersionsInput;
/** is the form of the provision go-package-registry. */
export interface GoPackageRegistryForm {
/** the read side's address */
"url": string;
}
@@ -1,187 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The part "registry" several seats include whole: The verbs and events every registry seat shares, written once so the four cannot drift (design 51, design 26). Who may call each verb is the holder's trusted config value listing its callers (ADR 0363's form), checked against the caller the tool runner proved.
export const verbs = {
publish: "publish",
publishPart: "publish-part",
versions: "versions",
remove: "remove",
} as const;
export const events = {
published: "published",
refused: "refused",
removed: "removed",
kept: "kept",
} as const;
/** one published thing, as every registry event and answer names it */
export interface Artifact {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** the tag it carries, for a tagged version */
"tag"?: string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** the body of published, refused and removed */
export interface Outcome {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** the module holding the seat that said it */
"holder": string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact */
"module"?: string;
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest) */
"reason"?: string;
/** the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9) */
"reference"?: string;
/** the tag it carries, for a tagged version */
"tag"?: string;
/** for kept: the other tags still naming its digest */
"tags"?: string[];
/** the transfer it ends, when it ended one */
"transfer"?: string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** one part of a transfer */
export interface Part {
/** the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob */
"digest": string;
/** its size in bytes */
"size": number;
}
/** is what publish takes. */
export interface PublishInput {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** every part's digest and size; none when the digest is already held */
"parts"?: Part[];
/** the tag it carries, for a tagged version */
"tag"?: string;
/** the transfer's name, the caller's own; the same name opens the same transfer again */
"transfer": string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** is what publish answers. */
export interface PublishAnswer {
/** the digest is held already: nothing to send; the outcome follows as an event */
"held"?: boolean;
/** the digests of the parts the holder lacks, to send by publish-part */
"lacks"?: string[];
/** the transfer */
"transfer": string;
}
/** is what publish-part takes. */
export interface PublishPartInput {
/** the chunk's bytes, base64 (at most 760 KiB before encoding) */
"data": string;
/** this chunk is the part's last */
"last": boolean;
/** the part's digest */
"part": string;
/** the chunk's place in its part, from 0 */
"sequence": number;
/** the transfer */
"transfer": string;
}
/** is what publish-part answers. */
export interface PublishPartAnswer {
/** the part is whole and its bytes match its digest */
"complete"?: boolean;
/** the part */
"part": string;
/** the chunks of the part held so far */
"received"?: number;
/** the transfer */
"transfer": string;
}
/** is what versions takes. */
export interface VersionsInput {
/** narrowed to one kind (optional) */
"kind"?: string;
/** the name */
"name": string;
}
/** is what versions answers. */
export interface VersionsAnswer {
/** the name */
"name": string;
/** newest first */
"versions": Artifact[];
}
/** is what remove takes. */
export interface RemoveInput {
/** the digest (for a bundle, archive or copied base) */
"digest"?: string;
/** the name */
"name": string;
/** why it goes */
"reason": "tag-gone" | "retention";
/** the tag (for a tagged version) */
"tag"?: string;
/** the version */
"version"?: string;
}
/** is what remove answers. */
export interface RemoveAnswer {
"artifact"?: Artifact;
/** it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags) */
"kept"?: boolean;
/** why it was kept: shared-digest, another tag names its digest */
"reason"?: "shared-digest";
/** it is gone */
"removed": boolean;
/** the other tags still naming its digest, when kept */
"tags"?: string[];
}
/** is the body of the event published. */
export type PublishedEvent = Outcome;
/** is the body of the event refused. */
export type RefusedEvent = Outcome;
/** is the body of the event removed. */
export type RemovedEvent = Outcome;
/** is the body of the event kept. */
export type KeptEvent = Outcome;
-12
View File
@@ -1,12 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
-12
View File
@@ -1,12 +0,0 @@
{
"lockfileVersion": 3,
"name": "@novox/mesh-contracts-mesh-delivery-checker",
"packages": {
"": {
"name": "@novox/mesh-contracts-mesh-delivery-checker",
"version": "0.1.0"
}
},
"requires": true,
"version": "0.1.0"
}
-13
View File
@@ -1,13 +0,0 @@
{
"description": "The contract of the seat mesh-delivery-checker, generated from its definition.",
"exports": {
".": "./src/index.ts"
},
"files": [
"src"
],
"name": "@novox/mesh-contracts-mesh-delivery-checker",
"type": "module",
"types": "./src/index.ts",
"version": "0.1.0"
}
-122
View File
@@ -1,122 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "mesh-delivery-checker", defined whole (seats/mesh-delivery-checker/seat.json): The merge check's tries: start one, read one, end one. The checker's own events stay under its own subjects (ADR 0620 §2).
export const seat = "mesh-delivery-checker";
export const verbs = {
try: "try",
tryRead: "try-read",
tryEnd: "try-end",
} as const;
export const holderEvents = {
verdict: "verdict",
tagWanted: "tag-wanted",
previewWritten: "preview.written",
} as const;
export function verdictHolderSubject(holder: string): string {
return "mesh.stream." + holder + ".event.verdict";
}
export function tagWantedHolderSubject(holder: string): string {
return "mesh.stream." + holder + ".event.tag-wanted";
}
export function previewWrittenHolderSubject(holder: string): string {
return "mesh.stream." + holder + ".event.preview.written";
}
/** is what try takes. */
export interface TryInput {
/** the full commit to try, 40 or 64 hex digits */
"head": string;
/** unit or integration: only this level; both when absent */
"level"?: string;
/** <owner>/<name> */
"repository": string;
/** a go test -run pattern: only those tests run, and nothing is kept */
"tests"?: string;
/** the trunk commit to merge it onto, or the trunk's branch for its head now; the trunk's head when absent */
"trunk"?: string;
}
/** is what try answers. */
export interface TryAnswer {
/** the try's id */
"id": string;
/** its state */
"state"?: string;
}
/** is what try-read takes. */
export interface TryReadInput {
/** the try's id, try-<digits> */
"id": string;
}
/** is what try-read answers. */
export type TryReadAnswer = Record<string, unknown>;
/** is what try-end takes. */
export interface TryEndInput {
/** the try's id, try-<digits> */
"id": string;
/** why it is ended, in words */
"why": string;
}
/** is what try-end answers. */
export interface TryEndAnswer {
/** it is ended */
"ended": boolean;
/** the try */
"id": string;
}
export interface VerdictHolderEventSeriesItem {
/** its artifact, or the package's ecosystem name as the module's packages name it */
"artifact": string;
/** the series on trunk */
"from": string;
/** the module whose artifact's series changes */
"module": string;
/** the series the checked head gives it */
"to": string;
}
/** is the body of the holder's event verdict. */
export interface VerdictHolderEvent {
/** the commit checked */
"head": string;
/** the generated files out of step with their seat definitions, each path (design 26) */
"out-of-step"?: string[];
/** the pull request's number, for a pull request's check */
"pull"?: number;
/** owner/repo */
"repository": string;
/** each change of an artifact's series the checked head makes against trunk's manifests, once each (design 32); absent when it changes none */
"series"?: VerdictHolderEventSeriesItem[];
/** pass or fail */
"verdict": string;
}
/** is the body of the holder's event tag-wanted. */
export interface TagWantedHolderEvent {
/** the pull request's branch: its tag is removed when the branch ends */
"branch": string;
/** its head */
"head": string;
/** the group member */
"module": string;
/** the package it declares */
"package": string;
/** the pull request */
"pull"?: number;
/** owner/repo */
"repository": string;
/** the tag wanted */
"tag"?: string;
}
@@ -1,12 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
-12
View File
@@ -1,12 +0,0 @@
{
"lockfileVersion": 3,
"name": "@novox/mesh-contracts-npm-package-registry",
"packages": {
"": {
"name": "@novox/mesh-contracts-npm-package-registry",
"version": "0.1.0"
}
},
"requires": true,
"version": "0.1.0"
}
-13
View File
@@ -1,13 +0,0 @@
{
"description": "The contract of the seat npm-package-registry, generated from its definition.",
"exports": {
".": "./src/index.ts"
},
"files": [
"src"
],
"name": "@novox/mesh-contracts-npm-package-registry",
"type": "module",
"types": "./src/index.ts",
"version": "0.1.0"
}
-54
View File
@@ -1,54 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "npm-package-registry", defined whole (seats/npm-package-registry/seat.json): The mesh's npm packages: the npm registry protocol's read side, and publishing over the bus.
import type * as registry from "./parts/registry.js";
export const seat = "npm-package-registry";
export const verbs = {
publish: "publish",
publishPart: "publish-part",
versions: "versions",
remove: "remove",
} as const;
export const events = {
published: "published",
refused: "refused",
removed: "removed",
kept: "kept",
} as const;
export const family = { name: "npm-package-registry.events", maxAgeDays: 7 } as const;
export const publishedSubject = "mesh.seat.npm-package-registry.event.published";
export const refusedSubject = "mesh.seat.npm-package-registry.event.refused";
export const removedSubject = "mesh.seat.npm-package-registry.event.removed";
export const keptSubject = "mesh.seat.npm-package-registry.event.kept";
export type Artifact = registry.Artifact;
export type KeptEvent = registry.KeptEvent;
export type Outcome = registry.Outcome;
export type Part = registry.Part;
export type PublishAnswer = registry.PublishAnswer;
export type PublishInput = registry.PublishInput;
export type PublishPartAnswer = registry.PublishPartAnswer;
export type PublishPartInput = registry.PublishPartInput;
export type PublishedEvent = registry.PublishedEvent;
export type RefusedEvent = registry.RefusedEvent;
export type RemoveAnswer = registry.RemoveAnswer;
export type RemoveInput = registry.RemoveInput;
export type RemovedEvent = registry.RemovedEvent;
export type VersionsAnswer = registry.VersionsAnswer;
export type VersionsInput = registry.VersionsInput;
/** is the form of the provision npm-package-registry. */
export interface NpmPackageRegistryForm {
/** the read side's address */
"url": string;
}
@@ -1,187 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The part "registry" several seats include whole: The verbs and events every registry seat shares, written once so the four cannot drift (design 51, design 26). Who may call each verb is the holder's trusted config value listing its callers (ADR 0363's form), checked against the caller the tool runner proved.
export const verbs = {
publish: "publish",
publishPart: "publish-part",
versions: "versions",
remove: "remove",
} as const;
export const events = {
published: "published",
refused: "refused",
removed: "removed",
kept: "kept",
} as const;
/** one published thing, as every registry event and answer names it */
export interface Artifact {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** the tag it carries, for a tagged version */
"tag"?: string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** the body of published, refused and removed */
export interface Outcome {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** the module holding the seat that said it */
"holder": string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact */
"module"?: string;
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest) */
"reason"?: string;
/** the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9) */
"reference"?: string;
/** the tag it carries, for a tagged version */
"tag"?: string;
/** for kept: the other tags still naming its digest */
"tags"?: string[];
/** the transfer it ends, when it ended one */
"transfer"?: string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** one part of a transfer */
export interface Part {
/** the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob */
"digest": string;
/** its size in bytes */
"size": number;
}
/** is what publish takes. */
export interface PublishInput {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** every part's digest and size; none when the digest is already held */
"parts"?: Part[];
/** the tag it carries, for a tagged version */
"tag"?: string;
/** the transfer's name, the caller's own; the same name opens the same transfer again */
"transfer": string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** is what publish answers. */
export interface PublishAnswer {
/** the digest is held already: nothing to send; the outcome follows as an event */
"held"?: boolean;
/** the digests of the parts the holder lacks, to send by publish-part */
"lacks"?: string[];
/** the transfer */
"transfer": string;
}
/** is what publish-part takes. */
export interface PublishPartInput {
/** the chunk's bytes, base64 (at most 760 KiB before encoding) */
"data": string;
/** this chunk is the part's last */
"last": boolean;
/** the part's digest */
"part": string;
/** the chunk's place in its part, from 0 */
"sequence": number;
/** the transfer */
"transfer": string;
}
/** is what publish-part answers. */
export interface PublishPartAnswer {
/** the part is whole and its bytes match its digest */
"complete"?: boolean;
/** the part */
"part": string;
/** the chunks of the part held so far */
"received"?: number;
/** the transfer */
"transfer": string;
}
/** is what versions takes. */
export interface VersionsInput {
/** narrowed to one kind (optional) */
"kind"?: string;
/** the name */
"name": string;
}
/** is what versions answers. */
export interface VersionsAnswer {
/** the name */
"name": string;
/** newest first */
"versions": Artifact[];
}
/** is what remove takes. */
export interface RemoveInput {
/** the digest (for a bundle, archive or copied base) */
"digest"?: string;
/** the name */
"name": string;
/** why it goes */
"reason": "tag-gone" | "retention";
/** the tag (for a tagged version) */
"tag"?: string;
/** the version */
"version"?: string;
}
/** is what remove answers. */
export interface RemoveAnswer {
"artifact"?: Artifact;
/** it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags) */
"kept"?: boolean;
/** why it was kept: shared-digest, another tag names its digest */
"reason"?: "shared-digest";
/** it is gone */
"removed": boolean;
/** the other tags still naming its digest, when kept */
"tags"?: string[];
}
/** is the body of the event published. */
export type PublishedEvent = Outcome;
/** is the body of the event refused. */
export type RefusedEvent = Outcome;
/** is the body of the event removed. */
export type RemovedEvent = Outcome;
/** is the body of the event kept. */
export type KeptEvent = Outcome;
-12
View File
@@ -1,12 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
-12
View File
@@ -1,12 +0,0 @@
{
"lockfileVersion": 3,
"name": "@novox/mesh-contracts-oci-artifact-registry",
"packages": {
"": {
"name": "@novox/mesh-contracts-oci-artifact-registry",
"version": "0.1.0"
}
},
"requires": true,
"version": "0.1.0"
}
-13
View File
@@ -1,13 +0,0 @@
{
"description": "The contract of the seat oci-artifact-registry, generated from its definition.",
"exports": {
".": "./src/index.ts"
},
"files": [
"src"
],
"name": "@novox/mesh-contracts-oci-artifact-registry",
"type": "module",
"types": "./src/index.ts",
"version": "0.1.0"
}
-149
View File
@@ -1,149 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "oci-artifact-registry", defined whole (seats/oci-artifact-registry/seat.json): The mesh's bundles and archives, by digest, in the one artifact store: the OCI distribution protocol's read side.
import type * as registry from "./parts/registry.js";
export const seat = "oci-artifact-registry";
export const verbs = {
publish: "publish",
publishPart: "publish-part",
versions: "versions",
remove: "remove",
hold: "hold",
release: "release",
list: "list",
} as const;
export const events = {
published: "published",
refused: "refused",
removed: "removed",
kept: "kept",
held: "held",
released: "released",
} as const;
export const family = { name: "oci-artifact-registry.events", maxAgeDays: 7 } as const;
export const publishedSubject = "mesh.seat.oci-artifact-registry.event.published";
export const refusedSubject = "mesh.seat.oci-artifact-registry.event.refused";
export const removedSubject = "mesh.seat.oci-artifact-registry.event.removed";
export const keptSubject = "mesh.seat.oci-artifact-registry.event.kept";
export const heldSubject = "mesh.seat.oci-artifact-registry.event.held";
export const releasedSubject = "mesh.seat.oci-artifact-registry.event.released";
export type Artifact = registry.Artifact;
export type KeptEvent = registry.KeptEvent;
export type Outcome = registry.Outcome;
export type Part = registry.Part;
export type PublishAnswer = registry.PublishAnswer;
export type PublishInput = registry.PublishInput;
export type PublishPartAnswer = registry.PublishPartAnswer;
export type PublishPartInput = registry.PublishPartInput;
export type PublishedEvent = registry.PublishedEvent;
export type RefusedEvent = registry.RefusedEvent;
export type RemoveAnswer = registry.RemoveAnswer;
export type RemoveInput = registry.RemoveInput;
export type RemovedEvent = registry.RemovedEvent;
export type VersionsAnswer = registry.VersionsAnswer;
export type VersionsInput = registry.VersionsInput;
/** the body of held and released */
export interface Hold {
/** when, RFC 3339 */
"at"?: string;
/** the caller the holder proved */
"by"?: string;
/** the digest */
"digest": string;
/** the module holding the seat */
"holder": string;
/** the name */
"name": string;
/** why */
"reason"?: string;
}
export interface Listed {
/** for a manifest keeping one bundle or archive, the digest of that blob: what a reference names it by */
"artifact"?: string;
/** the manifest's digest, sha256:<hex> */
"digest": string;
/** a hold keeps it from retention */
"held": boolean;
/** it is an index, naming a manifest per platform */
"index": boolean;
/** for an index, the digests of the manifests it names */
"platforms"?: string[];
/** its bytes: its own content and every blob it names */
"size": number;
/** the tags naming it, none for an untagged one */
"tags"?: string[];
}
export interface Repository {
/** each manifest it holds, by digest */
"manifests": Listed[];
/** the repository */
"name": string;
}
/** is what hold takes. */
export interface HoldInput {
/** the digest */
"digest": string;
/** the name */
"name": string;
/** which of the sweep's rules keeps it */
"reason": string;
}
/** is what hold answers. */
export interface HoldAnswer {
/** it is held */
"held": boolean;
/** when the hold began, RFC 3339 */
"since"?: string;
}
/** is what release takes. */
export interface ReleaseInput {
/** the digest */
"digest": string;
/** the name */
"name": string;
/** why it is let go */
"reason": string;
}
/** is what release answers. */
export interface ReleaseAnswer {
/** a hold was let go; false when there was none */
"released": boolean;
}
/** is what list takes. */
export interface ListInput {
/** the repository, <module>/<artifact>; every repository of the seat when not given */
"name"?: string;
}
/** is what list answers. */
export interface ListAnswer {
/** each repository named, in order of its name */
"repositories": Repository[];
}
/** is the body of the event held. */
export type HeldEvent = Hold;
/** is the body of the event released. */
export type ReleasedEvent = Hold;
@@ -1,187 +0,0 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The part "registry" several seats include whole: The verbs and events every registry seat shares, written once so the four cannot drift (design 51, design 26). Who may call each verb is the holder's trusted config value listing its callers (ADR 0363's form), checked against the caller the tool runner proved.
export const verbs = {
publish: "publish",
publishPart: "publish-part",
versions: "versions",
remove: "remove",
} as const;
export const events = {
published: "published",
refused: "refused",
removed: "removed",
kept: "kept",
} as const;
/** one published thing, as every registry event and answer names it */
export interface Artifact {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** the tag it carries, for a tagged version */
"tag"?: string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** the body of published, refused and removed */
export interface Outcome {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** the module holding the seat that said it */
"holder": string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the Go module path a Go package is fetched under, equal to name for a Go package (go-package-registry's published); empty for every other kind of artifact */
"module"?: string;
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** why: a refusal's cause, a removal's (retention, tag-gone, by-hand), or why a removal was kept (shared-digest) */
"reason"?: string;
/** the reference the seat answers: <registry>/<module>/<artifact>@sha256:<digest>, or <name>@<version> for a package (ADR 0605 §9) */
"reference"?: string;
/** the tag it carries, for a tagged version */
"tag"?: string;
/** for kept: the other tags still naming its digest */
"tags"?: string[];
/** the transfer it ends, when it ended one */
"transfer"?: string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** one part of a transfer */
export interface Part {
/** the part's digest, sha256:<hex>: an image's layer or config, a package's file, a bundle's blob */
"digest": string;
/** its size in bytes */
"size": number;
}
/** is what publish takes. */
export interface PublishInput {
/** the source commit it was built from */
"commit"?: string;
/** its digest, sha256:<hex> (a Go package's h1: hash beside it in the version's record) */
"digest": string;
/** the build's fingerprint */
"fingerprint"?: string;
/** what it is */
"kind": "package" | "image" | "bundle" | "archive" | "upstream";
/** the package's, image's, bundle's or archive's name; a package's is its name in its own language (design 32): a Go package's the go.mod module path (git.novox.be/novox/mesh-sdk/go), an npm package's package.json's name (@novox/mesh-sdk) */
"name": string;
/** every part's digest and size; none when the digest is already held */
"parts"?: Part[];
/** the tag it carries, for a tagged version */
"tag"?: string;
/** the transfer's name, the caller's own; the same name opens the same transfer again */
"transfer": string;
/** the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone */
"version"?: string;
}
/** is what publish answers. */
export interface PublishAnswer {
/** the digest is held already: nothing to send; the outcome follows as an event */
"held"?: boolean;
/** the digests of the parts the holder lacks, to send by publish-part */
"lacks"?: string[];
/** the transfer */
"transfer": string;
}
/** is what publish-part takes. */
export interface PublishPartInput {
/** the chunk's bytes, base64 (at most 760 KiB before encoding) */
"data": string;
/** this chunk is the part's last */
"last": boolean;
/** the part's digest */
"part": string;
/** the chunk's place in its part, from 0 */
"sequence": number;
/** the transfer */
"transfer": string;
}
/** is what publish-part answers. */
export interface PublishPartAnswer {
/** the part is whole and its bytes match its digest */
"complete"?: boolean;
/** the part */
"part": string;
/** the chunks of the part held so far */
"received"?: number;
/** the transfer */
"transfer": string;
}
/** is what versions takes. */
export interface VersionsInput {
/** narrowed to one kind (optional) */
"kind"?: string;
/** the name */
"name": string;
}
/** is what versions answers. */
export interface VersionsAnswer {
/** the name */
"name": string;
/** newest first */
"versions": Artifact[];
}
/** is what remove takes. */
export interface RemoveInput {
/** the digest (for a bundle, archive or copied base) */
"digest"?: string;
/** the name */
"name": string;
/** why it goes */
"reason": "tag-gone" | "retention";
/** the tag (for a tagged version) */
"tag"?: string;
/** the version */
"version"?: string;
}
/** is what remove answers. */
export interface RemoveAnswer {
"artifact"?: Artifact;
/** it stays whole, its tag and its bytes: the store cannot remove the tag alone while another tag names its digest (reason, tags) */
"kept"?: boolean;
/** why it was kept: shared-digest, another tag names its digest */
"reason"?: "shared-digest";
/** it is gone */
"removed": boolean;
/** the other tags still naming its digest, when kept */
"tags"?: string[];
}
/** is the body of the event published. */
export type PublishedEvent = Outcome;
/** is the body of the event refused. */
export type RefusedEvent = Outcome;
/** is the body of the event removed. */
export type RemovedEvent = Outcome;
/** is the body of the event kept. */
export type KeptEvent = Outcome;
@@ -1,12 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}