mesh-delivery-contracts: the part build-step and the three build seats defined whole with their states (D-4, ADR 0634 §6; issue 1966)

This commit is contained in:
2026-11-05 14:11:31 +01:00
parent 07bd0472b9
commit 7b4a469a3f
32 changed files with 3918 additions and 0 deletions
+447
View File
@@ -0,0 +1,447 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package nodebuildgo is the contract of the seat "node-build-go", defined whole (seats/node-build-go/seat.json): The Go build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.
package nodebuildgo
import (
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
const Seat = "node-build-go"
const (
VerbCurrent = "current"
VerbPause = "pause"
VerbResume = "resume"
)
const (
AcceptDelivery = "delivery"
AcceptCheck = "check"
AcceptRecheck = "recheck"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbCurrent, VerbPause, VerbResume}
}
// AcceptSubjectDelivery is where delivery is sent.
const AcceptSubjectDelivery = "mesh.seat.node-build-go.accept.delivery"
// AcceptSubjectCheck is where check is sent.
const AcceptSubjectCheck = "mesh.seat.node-build-go.accept.check"
// AcceptSubjectRecheck is where recheck is sent.
const AcceptSubjectRecheck = "mesh.seat.node-build-go.accept.recheck"
const (
StateSteps = "steps"
StatePauses = "pauses"
StateToolchains = "toolchains"
)
// StepsByNodeIDKey is the key of one value of the state steps under the form "<node>.<id>".
func StepsByNodeIDKey(node, id string) string { return node + "." + id }
// ParseStepsByNodeIDKey reads the parts of a key of the form "<node>.<id>", in the order of the form; the last result is false for a key of another form.
func ParseStepsByNodeIDKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeStepsByNodeIDValue reads one value of the state steps under the form "<node>.<id>", refusing a field StepsByNodeIDValue does not know and any text after the value.
func DecodeStepsByNodeIDValue(raw []byte) (StepsByNodeIDValue, error) {
var v StepsByNodeIDValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// PausesByPausedNodeKey is the key of one value of the state pauses under the form "paused.<node>".
func PausesByPausedNodeKey(node string) string { return "paused." + node }
// ParsePausesByPausedNodeKey reads the parts of a key of the form "paused.<node>", in the order of the form; the last result is false for a key of another form.
func ParsePausesByPausedNodeKey(key string) (string, bool) {
rest := key
if !strings.HasPrefix(rest, "paused.") {
return "", false
}
rest = rest[7:]
if rest == "" {
return "", false
}
v1 := rest
rest = ""
if rest != "" {
return "", false
}
return v1, true
}
// DecodePausesByPausedNodeValue reads one value of the state pauses under the form "paused.<node>", refusing a field PausesByPausedNodeValue does not know and any text after the value.
func DecodePausesByPausedNodeValue(raw []byte) (PausesByPausedNodeValue, error) {
var v PausesByPausedNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// PausesByCapacityNodeKey is the key of one value of the state pauses under the form "capacity.<node>".
func PausesByCapacityNodeKey(node string) string { return "capacity." + node }
// ParsePausesByCapacityNodeKey reads the parts of a key of the form "capacity.<node>", in the order of the form; the last result is false for a key of another form.
func ParsePausesByCapacityNodeKey(key string) (string, bool) {
rest := key
if !strings.HasPrefix(rest, "capacity.") {
return "", false
}
rest = rest[9:]
if rest == "" {
return "", false
}
v1 := rest
rest = ""
if rest != "" {
return "", false
}
return v1, true
}
// DecodePausesByCapacityNodeValue reads one value of the state pauses under the form "capacity.<node>", refusing a field PausesByCapacityNodeValue does not know and any text after the value.
func DecodePausesByCapacityNodeValue(raw []byte) (PausesByCapacityNodeValue, error) {
var v PausesByCapacityNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// ToolchainsByNodeLanguageKey is the key of one value of the state toolchains under the form "<node>.<language>".
func ToolchainsByNodeLanguageKey(node, language string) string { return node + "." + language }
// ParseToolchainsByNodeLanguageKey reads the parts of a key of the form "<node>.<language>", in the order of the form; the last result is false for a key of another form.
func ParseToolchainsByNodeLanguageKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeToolchainsByNodeLanguageValue reads one value of the state toolchains under the form "<node>.<language>", refusing a field ToolchainsByNodeLanguageValue does not know and any text after the value.
func DecodeToolchainsByNodeLanguageValue(raw []byte) (ToolchainsByNodeLanguageValue, error) {
var v ToolchainsByNodeLanguageValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// BuildAnswerArtifactsItem is a type of the contract.
type BuildAnswerArtifactsItem struct {
Artifact string `json:"artifact"`
Digest string `json:"digest"`
Reference string `json:"reference,omitempty"`
}
// BuildAnswerToolchain is a type of the contract.
type BuildAnswerToolchain struct {
Language string `json:"language"`
Recipe string `json:"recipe"`
Version string `json:"version"`
}
// BuildAnswer is a type of the contract.
type BuildAnswer struct {
Artifacts []BuildAnswerArtifactsItem `json:"artifacts"`
Imports []string `json:"imports,omitempty"`
OutOfStep []string `json:"out-of-step,omitempty"`
Toolchain *BuildAnswerToolchain `json:"toolchain,omitempty"`
}
// Capacity is how many steps the node runs at once.
type Capacity struct {
// when (RFC 3339 time)
At string `json:"at,omitempty"`
BuildHours string `json:"build-hours,omitempty"`
BuildHoursFault string `json:"build-hours-fault,omitempty"`
ByCpu int64 `json:"by-cpu,omitempty"`
Configured int64 `json:"configured"`
ConfiguredFrom string `json:"configured-from,omitempty"`
CoresPerStep float64 `json:"cores-per-step,omitempty"`
Effective int64 `json:"effective"`
Ineligible string `json:"ineligible,omitempty"`
OutsideHours bool `json:"outside-hours,omitempty"`
QuotaCores float64 `json:"quota-cores,omitempty"`
QuotaFrom string `json:"quota-from,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
Why string `json:"why"`
}
// CheckAnswerLevelsItemDigestNeedsItem is a type of the contract.
type CheckAnswerLevelsItemDigestNeedsItem struct {
Needs []string `json:"needs,omitempty"`
Package string `json:"package,omitempty"`
}
// CheckAnswerLevelsItemDigestPackagesItem is a type of the contract.
type CheckAnswerLevelsItemDigestPackagesItem struct {
Digest string `json:"digest"`
Package string `json:"package"`
}
// CheckAnswerLevelsItemDigest is a type of the contract.
type CheckAnswerLevelsItemDigest struct {
Beside []string `json:"beside,omitempty"`
JudgedBy string `json:"judged_by,omitempty"`
Level string `json:"level,omitempty"`
Needs []CheckAnswerLevelsItemDigestNeedsItem `json:"needs,omitempty"`
Packages []CheckAnswerLevelsItemDigestPackagesItem `json:"packages,omitempty"`
WithoutTests []string `json:"without_tests,omitempty"`
}
// CheckAnswerLevelsItemKeptItem is a type of the contract.
type CheckAnswerLevelsItemKeptItem struct {
Digest string `json:"digest,omitempty"`
Package string `json:"package,omitempty"`
Tests int64 `json:"tests,omitempty"`
}
// CheckAnswerLevelsItemUnmetItem is a type of the contract.
type CheckAnswerLevelsItemUnmetItem struct {
Needs []string `json:"needs,omitempty"`
Package string `json:"package,omitempty"`
}
// CheckAnswerLevelsItem is a type of the contract.
type CheckAnswerLevelsItem struct {
Digest *CheckAnswerLevelsItemDigest `json:"digest,omitempty"`
Judged string `json:"judged,omitempty"`
Kept []CheckAnswerLevelsItemKeptItem `json:"kept,omitempty"`
Level string `json:"level"`
Tests []any `json:"tests,omitempty"`
Unmet []CheckAnswerLevelsItemUnmetItem `json:"unmet,omitempty"`
}
// CheckAnswer is a type of the contract.
type CheckAnswer struct {
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch"`
Levels []CheckAnswerLevelsItem `json:"levels,omitempty"`
}
// ComposeAnswer is a type of the contract.
type ComposeAnswer struct {
Built bool `json:"built"`
Key string `json:"key,omitempty"`
// the compose-candidate verdict
Verdict any `json:"verdict,omitempty"`
}
// Pause is whether the node takes no new ask.
type Pause struct {
// when (RFC 3339 time)
At string `json:"at,omitempty"`
By string `json:"by,omitempty"`
Paused bool `json:"paused"`
// the layout version
V int64 `json:"v,omitempty"`
}
// Step is one step a build module runs on a node.
type Step struct {
// when (RFC 3339 time)
Ended string `json:"ended,omitempty"`
ID string `json:"id"`
Node string `json:"node"`
Owner string `json:"owner,omitempty"`
Phase string `json:"phase,omitempty"`
// when (RFC 3339 time)
PhaseAt string `json:"phase-at,omitempty"`
Reason string `json:"reason,omitempty"`
// what the step answered
Result any `json:"result,omitempty"`
// when (RFC 3339 time)
Started string `json:"started"`
// running, passed, failed or refused
State string `json:"state"`
Tool string `json:"tool"`
// the layout version
V int64 `json:"v,omitempty"`
What string `json:"what,omitempty"`
}
// StepAskBuildArtifactsItem is a type of the contract.
type StepAskBuildArtifactsItem struct {
Artifact string `json:"artifact"`
From string `json:"from,omitempty"`
Seat string `json:"seat,omitempty"`
Version string `json:"version,omitempty"`
}
// StepAskBuildToolchain is a type of the contract.
type StepAskBuildToolchain struct {
Language string `json:"language"`
Recipe string `json:"recipe"`
Version string `json:"version"`
}
// StepAskBuild is a type of the contract.
type StepAskBuild struct {
Artifacts []StepAskBuildArtifactsItem `json:"artifacts"`
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch,omitempty"`
Fp string `json:"fp,omitempty"`
Module string `json:"module"`
Path string `json:"path,omitempty"`
Publish bool `json:"publish,omitempty"`
Toolchain *StepAskBuildToolchain `json:"toolchain,omitempty"`
}
// StepAskCheck is a type of the contract.
type StepAskCheck struct {
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch"`
Kept bool `json:"kept,omitempty"`
Levels []string `json:"levels"`
Packages []string `json:"packages,omitempty"`
Run string `json:"run,omitempty"`
Runner string `json:"runner,omitempty"`
RunnerWhen string `json:"runner_when,omitempty"`
}
// StepAskCompose is a type of the contract.
type StepAskCompose struct {
Dir string `json:"dir"`
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch"`
Package string `json:"package"`
Reader string `json:"reader,omitempty"`
// the compose-candidate request
Request any `json:"request"`
}
// StepAsk is one ask of a build module.
type StepAsk struct {
Asker string `json:"asker"`
// when (RFC 3339 time)
At string `json:"at,omitempty"`
Build *StepAskBuild `json:"build,omitempty"`
Check *StepAskCheck `json:"check,omitempty"`
Compose *StepAskCompose `json:"compose,omitempty"`
ID string `json:"id"`
// build, check or compose
Kind string `json:"kind"`
// go, typescript or image
Language string `json:"language"`
Needs []string `json:"needs,omitempty"`
// package to the tagged version a build pins
Packages map[string]string `json:"packages,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
}
// Toolchain is the toolchain a node reports.
type Toolchain struct {
// when (RFC 3339 time)
At string `json:"at,omitempty"`
// go or typescript
Language string `json:"language"`
Recipe string `json:"recipe"`
// the layout version
V int64 `json:"v,omitempty"`
Version string `json:"version"`
}
// CurrentInput is what current takes.
type CurrentInput struct {
}
// CurrentAnswer is what current answers.
type CurrentAnswer = map[string]any
// PauseInput is what pause takes.
type PauseInput struct {
}
// PauseAnswer is what pause answers.
type PauseAnswer = map[string]any
// ResumeInput is what resume takes.
type ResumeInput struct {
}
// ResumeAnswer is what resume answers.
type ResumeAnswer = map[string]any
// DeliveryAccept is the body of delivery.
type DeliveryAccept = StepAsk
// CheckAccept is the body of check.
type CheckAccept = StepAsk
// RecheckAccept is the body of recheck.
type RecheckAccept = StepAsk
// StepsByNodeIDValue is one value of the state steps under the key <node>.<id>.
type StepsByNodeIDValue = Step
// PausesByPausedNodeValue is one value of the state pauses under the key paused.<node>.
type PausesByPausedNodeValue = Pause
// PausesByCapacityNodeValue is one value of the state pauses under the key capacity.<node>.
type PausesByCapacityNodeValue = Capacity
// ToolchainsByNodeLanguageValue is one value of the state toolchains under the key <node>.<language>.
type ToolchainsByNodeLanguageValue = Toolchain
@@ -0,0 +1,68 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
package nodebuildgo
import (
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/node-build-go/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: "a running step", subject: "", given: "{\"id\":\"a1b2\",\"node\":\"ace\",\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"running\",\"tool\":\"build\",\"v\":1}", wire: "{\"id\":\"a1b2\",\"node\":\"ace\",\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"running\",\"tool\":\"build\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepsByNodeIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a paused node", subject: "", given: "{\"at\":\"2026-11-05T10:00:00Z\",\"by\":\"operator@shanks\",\"paused\":true,\"v\":1}", wire: "{\"at\":\"2026-11-05T10:00:00Z\",\"by\":\"operator@shanks\",\"paused\":true,\"v\":1}",
decode: func(b []byte) (any, error) {
var v PausesByPausedNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a node's capacity", subject: "", given: "{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}", wire: "{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}",
decode: func(b []byte) (any, error) {
var v PausesByCapacityNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a node's toolchain", subject: "", given: "{\"language\":\"go\",\"recipe\":\"1\",\"v\":1,\"version\":\"1.26.0\"}", wire: "{\"language\":\"go\",\"recipe\":\"1\",\"v\":1,\"version\":\"1.26.0\"}",
decode: func(b []byte) (any, error) {
var v ToolchainsByNodeLanguageValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a build ask", subject: "mesh.seat.node-build-go.accept.delivery", given: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b2\",\"kind\":\"build\",\"language\":\"go\"}", wire: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b2\",\"kind\":\"build\",\"language\":\"go\"}",
decode: func(b []byte) (any, error) { var v DeliveryAccept; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-go\\.accept\\.delivery$")},
}
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
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildgo
go 1.26.0
@@ -0,0 +1,447 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package nodebuildimage is the contract of the seat "node-build-image", defined whole (seats/node-build-image/seat.json): The image build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.
package nodebuildimage
import (
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
const Seat = "node-build-image"
const (
VerbCurrent = "current"
VerbPause = "pause"
VerbResume = "resume"
)
const (
AcceptDelivery = "delivery"
AcceptCheck = "check"
AcceptRecheck = "recheck"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbCurrent, VerbPause, VerbResume}
}
// AcceptSubjectDelivery is where delivery is sent.
const AcceptSubjectDelivery = "mesh.seat.node-build-image.accept.delivery"
// AcceptSubjectCheck is where check is sent.
const AcceptSubjectCheck = "mesh.seat.node-build-image.accept.check"
// AcceptSubjectRecheck is where recheck is sent.
const AcceptSubjectRecheck = "mesh.seat.node-build-image.accept.recheck"
const (
StateSteps = "steps"
StatePauses = "pauses"
StateToolchains = "toolchains"
)
// StepsByNodeIDKey is the key of one value of the state steps under the form "<node>.<id>".
func StepsByNodeIDKey(node, id string) string { return node + "." + id }
// ParseStepsByNodeIDKey reads the parts of a key of the form "<node>.<id>", in the order of the form; the last result is false for a key of another form.
func ParseStepsByNodeIDKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeStepsByNodeIDValue reads one value of the state steps under the form "<node>.<id>", refusing a field StepsByNodeIDValue does not know and any text after the value.
func DecodeStepsByNodeIDValue(raw []byte) (StepsByNodeIDValue, error) {
var v StepsByNodeIDValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// PausesByPausedNodeKey is the key of one value of the state pauses under the form "paused.<node>".
func PausesByPausedNodeKey(node string) string { return "paused." + node }
// ParsePausesByPausedNodeKey reads the parts of a key of the form "paused.<node>", in the order of the form; the last result is false for a key of another form.
func ParsePausesByPausedNodeKey(key string) (string, bool) {
rest := key
if !strings.HasPrefix(rest, "paused.") {
return "", false
}
rest = rest[7:]
if rest == "" {
return "", false
}
v1 := rest
rest = ""
if rest != "" {
return "", false
}
return v1, true
}
// DecodePausesByPausedNodeValue reads one value of the state pauses under the form "paused.<node>", refusing a field PausesByPausedNodeValue does not know and any text after the value.
func DecodePausesByPausedNodeValue(raw []byte) (PausesByPausedNodeValue, error) {
var v PausesByPausedNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// PausesByCapacityNodeKey is the key of one value of the state pauses under the form "capacity.<node>".
func PausesByCapacityNodeKey(node string) string { return "capacity." + node }
// ParsePausesByCapacityNodeKey reads the parts of a key of the form "capacity.<node>", in the order of the form; the last result is false for a key of another form.
func ParsePausesByCapacityNodeKey(key string) (string, bool) {
rest := key
if !strings.HasPrefix(rest, "capacity.") {
return "", false
}
rest = rest[9:]
if rest == "" {
return "", false
}
v1 := rest
rest = ""
if rest != "" {
return "", false
}
return v1, true
}
// DecodePausesByCapacityNodeValue reads one value of the state pauses under the form "capacity.<node>", refusing a field PausesByCapacityNodeValue does not know and any text after the value.
func DecodePausesByCapacityNodeValue(raw []byte) (PausesByCapacityNodeValue, error) {
var v PausesByCapacityNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// ToolchainsByNodeLanguageKey is the key of one value of the state toolchains under the form "<node>.<language>".
func ToolchainsByNodeLanguageKey(node, language string) string { return node + "." + language }
// ParseToolchainsByNodeLanguageKey reads the parts of a key of the form "<node>.<language>", in the order of the form; the last result is false for a key of another form.
func ParseToolchainsByNodeLanguageKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeToolchainsByNodeLanguageValue reads one value of the state toolchains under the form "<node>.<language>", refusing a field ToolchainsByNodeLanguageValue does not know and any text after the value.
func DecodeToolchainsByNodeLanguageValue(raw []byte) (ToolchainsByNodeLanguageValue, error) {
var v ToolchainsByNodeLanguageValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// BuildAnswerArtifactsItem is a type of the contract.
type BuildAnswerArtifactsItem struct {
Artifact string `json:"artifact"`
Digest string `json:"digest"`
Reference string `json:"reference,omitempty"`
}
// BuildAnswerToolchain is a type of the contract.
type BuildAnswerToolchain struct {
Language string `json:"language"`
Recipe string `json:"recipe"`
Version string `json:"version"`
}
// BuildAnswer is a type of the contract.
type BuildAnswer struct {
Artifacts []BuildAnswerArtifactsItem `json:"artifacts"`
Imports []string `json:"imports,omitempty"`
OutOfStep []string `json:"out-of-step,omitempty"`
Toolchain *BuildAnswerToolchain `json:"toolchain,omitempty"`
}
// Capacity is how many steps the node runs at once.
type Capacity struct {
// when (RFC 3339 time)
At string `json:"at,omitempty"`
BuildHours string `json:"build-hours,omitempty"`
BuildHoursFault string `json:"build-hours-fault,omitempty"`
ByCpu int64 `json:"by-cpu,omitempty"`
Configured int64 `json:"configured"`
ConfiguredFrom string `json:"configured-from,omitempty"`
CoresPerStep float64 `json:"cores-per-step,omitempty"`
Effective int64 `json:"effective"`
Ineligible string `json:"ineligible,omitempty"`
OutsideHours bool `json:"outside-hours,omitempty"`
QuotaCores float64 `json:"quota-cores,omitempty"`
QuotaFrom string `json:"quota-from,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
Why string `json:"why"`
}
// CheckAnswerLevelsItemDigestNeedsItem is a type of the contract.
type CheckAnswerLevelsItemDigestNeedsItem struct {
Needs []string `json:"needs,omitempty"`
Package string `json:"package,omitempty"`
}
// CheckAnswerLevelsItemDigestPackagesItem is a type of the contract.
type CheckAnswerLevelsItemDigestPackagesItem struct {
Digest string `json:"digest"`
Package string `json:"package"`
}
// CheckAnswerLevelsItemDigest is a type of the contract.
type CheckAnswerLevelsItemDigest struct {
Beside []string `json:"beside,omitempty"`
JudgedBy string `json:"judged_by,omitempty"`
Level string `json:"level,omitempty"`
Needs []CheckAnswerLevelsItemDigestNeedsItem `json:"needs,omitempty"`
Packages []CheckAnswerLevelsItemDigestPackagesItem `json:"packages,omitempty"`
WithoutTests []string `json:"without_tests,omitempty"`
}
// CheckAnswerLevelsItemKeptItem is a type of the contract.
type CheckAnswerLevelsItemKeptItem struct {
Digest string `json:"digest,omitempty"`
Package string `json:"package,omitempty"`
Tests int64 `json:"tests,omitempty"`
}
// CheckAnswerLevelsItemUnmetItem is a type of the contract.
type CheckAnswerLevelsItemUnmetItem struct {
Needs []string `json:"needs,omitempty"`
Package string `json:"package,omitempty"`
}
// CheckAnswerLevelsItem is a type of the contract.
type CheckAnswerLevelsItem struct {
Digest *CheckAnswerLevelsItemDigest `json:"digest,omitempty"`
Judged string `json:"judged,omitempty"`
Kept []CheckAnswerLevelsItemKeptItem `json:"kept,omitempty"`
Level string `json:"level"`
Tests []any `json:"tests,omitempty"`
Unmet []CheckAnswerLevelsItemUnmetItem `json:"unmet,omitempty"`
}
// CheckAnswer is a type of the contract.
type CheckAnswer struct {
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch"`
Levels []CheckAnswerLevelsItem `json:"levels,omitempty"`
}
// ComposeAnswer is a type of the contract.
type ComposeAnswer struct {
Built bool `json:"built"`
Key string `json:"key,omitempty"`
// the compose-candidate verdict
Verdict any `json:"verdict,omitempty"`
}
// Pause is whether the node takes no new ask.
type Pause struct {
// when (RFC 3339 time)
At string `json:"at,omitempty"`
By string `json:"by,omitempty"`
Paused bool `json:"paused"`
// the layout version
V int64 `json:"v,omitempty"`
}
// Step is one step a build module runs on a node.
type Step struct {
// when (RFC 3339 time)
Ended string `json:"ended,omitempty"`
ID string `json:"id"`
Node string `json:"node"`
Owner string `json:"owner,omitempty"`
Phase string `json:"phase,omitempty"`
// when (RFC 3339 time)
PhaseAt string `json:"phase-at,omitempty"`
Reason string `json:"reason,omitempty"`
// what the step answered
Result any `json:"result,omitempty"`
// when (RFC 3339 time)
Started string `json:"started"`
// running, passed, failed or refused
State string `json:"state"`
Tool string `json:"tool"`
// the layout version
V int64 `json:"v,omitempty"`
What string `json:"what,omitempty"`
}
// StepAskBuildArtifactsItem is a type of the contract.
type StepAskBuildArtifactsItem struct {
Artifact string `json:"artifact"`
From string `json:"from,omitempty"`
Seat string `json:"seat,omitempty"`
Version string `json:"version,omitempty"`
}
// StepAskBuildToolchain is a type of the contract.
type StepAskBuildToolchain struct {
Language string `json:"language"`
Recipe string `json:"recipe"`
Version string `json:"version"`
}
// StepAskBuild is a type of the contract.
type StepAskBuild struct {
Artifacts []StepAskBuildArtifactsItem `json:"artifacts"`
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch,omitempty"`
Fp string `json:"fp,omitempty"`
Module string `json:"module"`
Path string `json:"path,omitempty"`
Publish bool `json:"publish,omitempty"`
Toolchain *StepAskBuildToolchain `json:"toolchain,omitempty"`
}
// StepAskCheck is a type of the contract.
type StepAskCheck struct {
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch"`
Kept bool `json:"kept,omitempty"`
Levels []string `json:"levels"`
Packages []string `json:"packages,omitempty"`
Run string `json:"run,omitempty"`
Runner string `json:"runner,omitempty"`
RunnerWhen string `json:"runner_when,omitempty"`
}
// StepAskCompose is a type of the contract.
type StepAskCompose struct {
Dir string `json:"dir"`
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch"`
Package string `json:"package"`
Reader string `json:"reader,omitempty"`
// the compose-candidate request
Request any `json:"request"`
}
// StepAsk is one ask of a build module.
type StepAsk struct {
Asker string `json:"asker"`
// when (RFC 3339 time)
At string `json:"at,omitempty"`
Build *StepAskBuild `json:"build,omitempty"`
Check *StepAskCheck `json:"check,omitempty"`
Compose *StepAskCompose `json:"compose,omitempty"`
ID string `json:"id"`
// build, check or compose
Kind string `json:"kind"`
// go, typescript or image
Language string `json:"language"`
Needs []string `json:"needs,omitempty"`
// package to the tagged version a build pins
Packages map[string]string `json:"packages,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
}
// Toolchain is the toolchain a node reports.
type Toolchain struct {
// when (RFC 3339 time)
At string `json:"at,omitempty"`
// go or typescript
Language string `json:"language"`
Recipe string `json:"recipe"`
// the layout version
V int64 `json:"v,omitempty"`
Version string `json:"version"`
}
// CurrentInput is what current takes.
type CurrentInput struct {
}
// CurrentAnswer is what current answers.
type CurrentAnswer = map[string]any
// PauseInput is what pause takes.
type PauseInput struct {
}
// PauseAnswer is what pause answers.
type PauseAnswer = map[string]any
// ResumeInput is what resume takes.
type ResumeInput struct {
}
// ResumeAnswer is what resume answers.
type ResumeAnswer = map[string]any
// DeliveryAccept is the body of delivery.
type DeliveryAccept = StepAsk
// CheckAccept is the body of check.
type CheckAccept = StepAsk
// RecheckAccept is the body of recheck.
type RecheckAccept = StepAsk
// StepsByNodeIDValue is one value of the state steps under the key <node>.<id>.
type StepsByNodeIDValue = Step
// PausesByPausedNodeValue is one value of the state pauses under the key paused.<node>.
type PausesByPausedNodeValue = Pause
// PausesByCapacityNodeValue is one value of the state pauses under the key capacity.<node>.
type PausesByCapacityNodeValue = Capacity
// ToolchainsByNodeLanguageValue is one value of the state toolchains under the key <node>.<language>.
type ToolchainsByNodeLanguageValue = Toolchain
@@ -0,0 +1,68 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
package nodebuildimage
import (
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/node-build-image/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: "a running step", subject: "", given: "{\"id\":\"a1b2\",\"node\":\"ace\",\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"running\",\"tool\":\"build\",\"v\":1}", wire: "{\"id\":\"a1b2\",\"node\":\"ace\",\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"running\",\"tool\":\"build\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepsByNodeIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a paused node", subject: "", given: "{\"at\":\"2026-11-05T10:00:00Z\",\"by\":\"operator@shanks\",\"paused\":true,\"v\":1}", wire: "{\"at\":\"2026-11-05T10:00:00Z\",\"by\":\"operator@shanks\",\"paused\":true,\"v\":1}",
decode: func(b []byte) (any, error) {
var v PausesByPausedNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a node's capacity", subject: "", given: "{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}", wire: "{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}",
decode: func(b []byte) (any, error) {
var v PausesByCapacityNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a node's toolchain", subject: "", given: "{\"language\":\"go\",\"recipe\":\"1\",\"v\":1,\"version\":\"1.26.0\"}", wire: "{\"language\":\"go\",\"recipe\":\"1\",\"v\":1,\"version\":\"1.26.0\"}",
decode: func(b []byte) (any, error) {
var v ToolchainsByNodeLanguageValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a build ask", subject: "mesh.seat.node-build-image.accept.delivery", given: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b2\",\"kind\":\"build\",\"language\":\"go\"}", wire: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b2\",\"kind\":\"build\",\"language\":\"go\"}",
decode: func(b []byte) (any, error) { var v DeliveryAccept; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-image\\.accept\\.delivery$")},
}
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
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildimage
go 1.26.0
@@ -0,0 +1,447 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// Package nodebuildnode is the contract of the seat "node-build-node", defined whole (seats/node-build-node/seat.json): The Node build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.
package nodebuildnode
import (
"bytes"
"encoding/json"
"errors"
"strings"
)
// Seat is the seat's name.
const Seat = "node-build-node"
const (
VerbCurrent = "current"
VerbPause = "pause"
VerbResume = "resume"
)
const (
AcceptDelivery = "delivery"
AcceptCheck = "check"
AcceptRecheck = "recheck"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
func Verbs() []string {
return []string{VerbCurrent, VerbPause, VerbResume}
}
// AcceptSubjectDelivery is where delivery is sent.
const AcceptSubjectDelivery = "mesh.seat.node-build-node.accept.delivery"
// AcceptSubjectCheck is where check is sent.
const AcceptSubjectCheck = "mesh.seat.node-build-node.accept.check"
// AcceptSubjectRecheck is where recheck is sent.
const AcceptSubjectRecheck = "mesh.seat.node-build-node.accept.recheck"
const (
StateSteps = "steps"
StatePauses = "pauses"
StateToolchains = "toolchains"
)
// StepsByNodeIDKey is the key of one value of the state steps under the form "<node>.<id>".
func StepsByNodeIDKey(node, id string) string { return node + "." + id }
// ParseStepsByNodeIDKey reads the parts of a key of the form "<node>.<id>", in the order of the form; the last result is false for a key of another form.
func ParseStepsByNodeIDKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeStepsByNodeIDValue reads one value of the state steps under the form "<node>.<id>", refusing a field StepsByNodeIDValue does not know and any text after the value.
func DecodeStepsByNodeIDValue(raw []byte) (StepsByNodeIDValue, error) {
var v StepsByNodeIDValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// PausesByPausedNodeKey is the key of one value of the state pauses under the form "paused.<node>".
func PausesByPausedNodeKey(node string) string { return "paused." + node }
// ParsePausesByPausedNodeKey reads the parts of a key of the form "paused.<node>", in the order of the form; the last result is false for a key of another form.
func ParsePausesByPausedNodeKey(key string) (string, bool) {
rest := key
if !strings.HasPrefix(rest, "paused.") {
return "", false
}
rest = rest[7:]
if rest == "" {
return "", false
}
v1 := rest
rest = ""
if rest != "" {
return "", false
}
return v1, true
}
// DecodePausesByPausedNodeValue reads one value of the state pauses under the form "paused.<node>", refusing a field PausesByPausedNodeValue does not know and any text after the value.
func DecodePausesByPausedNodeValue(raw []byte) (PausesByPausedNodeValue, error) {
var v PausesByPausedNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// PausesByCapacityNodeKey is the key of one value of the state pauses under the form "capacity.<node>".
func PausesByCapacityNodeKey(node string) string { return "capacity." + node }
// ParsePausesByCapacityNodeKey reads the parts of a key of the form "capacity.<node>", in the order of the form; the last result is false for a key of another form.
func ParsePausesByCapacityNodeKey(key string) (string, bool) {
rest := key
if !strings.HasPrefix(rest, "capacity.") {
return "", false
}
rest = rest[9:]
if rest == "" {
return "", false
}
v1 := rest
rest = ""
if rest != "" {
return "", false
}
return v1, true
}
// DecodePausesByCapacityNodeValue reads one value of the state pauses under the form "capacity.<node>", refusing a field PausesByCapacityNodeValue does not know and any text after the value.
func DecodePausesByCapacityNodeValue(raw []byte) (PausesByCapacityNodeValue, error) {
var v PausesByCapacityNodeValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// ToolchainsByNodeLanguageKey is the key of one value of the state toolchains under the form "<node>.<language>".
func ToolchainsByNodeLanguageKey(node, language string) string { return node + "." + language }
// ParseToolchainsByNodeLanguageKey reads the parts of a key of the form "<node>.<language>", in the order of the form; the last result is false for a key of another form.
func ParseToolchainsByNodeLanguageKey(key string) (string, string, bool) {
rest := key
v0, after0, found0 := strings.Cut(rest, ".")
if !found0 || v0 == "" {
return "", "", false
}
rest = after0
if rest == "" {
return "", "", false
}
v2 := rest
rest = ""
if rest != "" {
return "", "", false
}
return v0, v2, true
}
// DecodeToolchainsByNodeLanguageValue reads one value of the state toolchains under the form "<node>.<language>", refusing a field ToolchainsByNodeLanguageValue does not know and any text after the value.
func DecodeToolchainsByNodeLanguageValue(raw []byte) (ToolchainsByNodeLanguageValue, error) {
var v ToolchainsByNodeLanguageValue
dec := json.NewDecoder(bytes.NewReader(raw))
dec.DisallowUnknownFields()
if err := dec.Decode(&v); err != nil {
return v, err
}
if dec.More() {
return v, errors.New("text after the value")
}
return v, nil
}
// BuildAnswerArtifactsItem is a type of the contract.
type BuildAnswerArtifactsItem struct {
Artifact string `json:"artifact"`
Digest string `json:"digest"`
Reference string `json:"reference,omitempty"`
}
// BuildAnswerToolchain is a type of the contract.
type BuildAnswerToolchain struct {
Language string `json:"language"`
Recipe string `json:"recipe"`
Version string `json:"version"`
}
// BuildAnswer is a type of the contract.
type BuildAnswer struct {
Artifacts []BuildAnswerArtifactsItem `json:"artifacts"`
Imports []string `json:"imports,omitempty"`
OutOfStep []string `json:"out-of-step,omitempty"`
Toolchain *BuildAnswerToolchain `json:"toolchain,omitempty"`
}
// Capacity is how many steps the node runs at once.
type Capacity struct {
// when (RFC 3339 time)
At string `json:"at,omitempty"`
BuildHours string `json:"build-hours,omitempty"`
BuildHoursFault string `json:"build-hours-fault,omitempty"`
ByCpu int64 `json:"by-cpu,omitempty"`
Configured int64 `json:"configured"`
ConfiguredFrom string `json:"configured-from,omitempty"`
CoresPerStep float64 `json:"cores-per-step,omitempty"`
Effective int64 `json:"effective"`
Ineligible string `json:"ineligible,omitempty"`
OutsideHours bool `json:"outside-hours,omitempty"`
QuotaCores float64 `json:"quota-cores,omitempty"`
QuotaFrom string `json:"quota-from,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
Why string `json:"why"`
}
// CheckAnswerLevelsItemDigestNeedsItem is a type of the contract.
type CheckAnswerLevelsItemDigestNeedsItem struct {
Needs []string `json:"needs,omitempty"`
Package string `json:"package,omitempty"`
}
// CheckAnswerLevelsItemDigestPackagesItem is a type of the contract.
type CheckAnswerLevelsItemDigestPackagesItem struct {
Digest string `json:"digest"`
Package string `json:"package"`
}
// CheckAnswerLevelsItemDigest is a type of the contract.
type CheckAnswerLevelsItemDigest struct {
Beside []string `json:"beside,omitempty"`
JudgedBy string `json:"judged_by,omitempty"`
Level string `json:"level,omitempty"`
Needs []CheckAnswerLevelsItemDigestNeedsItem `json:"needs,omitempty"`
Packages []CheckAnswerLevelsItemDigestPackagesItem `json:"packages,omitempty"`
WithoutTests []string `json:"without_tests,omitempty"`
}
// CheckAnswerLevelsItemKeptItem is a type of the contract.
type CheckAnswerLevelsItemKeptItem struct {
Digest string `json:"digest,omitempty"`
Package string `json:"package,omitempty"`
Tests int64 `json:"tests,omitempty"`
}
// CheckAnswerLevelsItemUnmetItem is a type of the contract.
type CheckAnswerLevelsItemUnmetItem struct {
Needs []string `json:"needs,omitempty"`
Package string `json:"package,omitempty"`
}
// CheckAnswerLevelsItem is a type of the contract.
type CheckAnswerLevelsItem struct {
Digest *CheckAnswerLevelsItemDigest `json:"digest,omitempty"`
Judged string `json:"judged,omitempty"`
Kept []CheckAnswerLevelsItemKeptItem `json:"kept,omitempty"`
Level string `json:"level"`
Tests []any `json:"tests,omitempty"`
Unmet []CheckAnswerLevelsItemUnmetItem `json:"unmet,omitempty"`
}
// CheckAnswer is a type of the contract.
type CheckAnswer struct {
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch"`
Levels []CheckAnswerLevelsItem `json:"levels,omitempty"`
}
// ComposeAnswer is a type of the contract.
type ComposeAnswer struct {
Built bool `json:"built"`
Key string `json:"key,omitempty"`
// the compose-candidate verdict
Verdict any `json:"verdict,omitempty"`
}
// Pause is whether the node takes no new ask.
type Pause struct {
// when (RFC 3339 time)
At string `json:"at,omitempty"`
By string `json:"by,omitempty"`
Paused bool `json:"paused"`
// the layout version
V int64 `json:"v,omitempty"`
}
// Step is one step a build module runs on a node.
type Step struct {
// when (RFC 3339 time)
Ended string `json:"ended,omitempty"`
ID string `json:"id"`
Node string `json:"node"`
Owner string `json:"owner,omitempty"`
Phase string `json:"phase,omitempty"`
// when (RFC 3339 time)
PhaseAt string `json:"phase-at,omitempty"`
Reason string `json:"reason,omitempty"`
// what the step answered
Result any `json:"result,omitempty"`
// when (RFC 3339 time)
Started string `json:"started"`
// running, passed, failed or refused
State string `json:"state"`
Tool string `json:"tool"`
// the layout version
V int64 `json:"v,omitempty"`
What string `json:"what,omitempty"`
}
// StepAskBuildArtifactsItem is a type of the contract.
type StepAskBuildArtifactsItem struct {
Artifact string `json:"artifact"`
From string `json:"from,omitempty"`
Seat string `json:"seat,omitempty"`
Version string `json:"version,omitempty"`
}
// StepAskBuildToolchain is a type of the contract.
type StepAskBuildToolchain struct {
Language string `json:"language"`
Recipe string `json:"recipe"`
Version string `json:"version"`
}
// StepAskBuild is a type of the contract.
type StepAskBuild struct {
Artifacts []StepAskBuildArtifactsItem `json:"artifacts"`
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch,omitempty"`
Fp string `json:"fp,omitempty"`
Module string `json:"module"`
Path string `json:"path,omitempty"`
Publish bool `json:"publish,omitempty"`
Toolchain *StepAskBuildToolchain `json:"toolchain,omitempty"`
}
// StepAskCheck is a type of the contract.
type StepAskCheck struct {
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch"`
Kept bool `json:"kept,omitempty"`
Levels []string `json:"levels"`
Packages []string `json:"packages,omitempty"`
Run string `json:"run,omitempty"`
Runner string `json:"runner,omitempty"`
RunnerWhen string `json:"runner_when,omitempty"`
}
// StepAskCompose is a type of the contract.
type StepAskCompose struct {
Dir string `json:"dir"`
// what the build module fetches: the repository, commit and directory, as the indexer states it
Fetch any `json:"fetch"`
Package string `json:"package"`
Reader string `json:"reader,omitempty"`
// the compose-candidate request
Request any `json:"request"`
}
// StepAsk is one ask of a build module.
type StepAsk struct {
Asker string `json:"asker"`
// when (RFC 3339 time)
At string `json:"at,omitempty"`
Build *StepAskBuild `json:"build,omitempty"`
Check *StepAskCheck `json:"check,omitempty"`
Compose *StepAskCompose `json:"compose,omitempty"`
ID string `json:"id"`
// build, check or compose
Kind string `json:"kind"`
// go, typescript or image
Language string `json:"language"`
Needs []string `json:"needs,omitempty"`
// package to the tagged version a build pins
Packages map[string]string `json:"packages,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
}
// Toolchain is the toolchain a node reports.
type Toolchain struct {
// when (RFC 3339 time)
At string `json:"at,omitempty"`
// go or typescript
Language string `json:"language"`
Recipe string `json:"recipe"`
// the layout version
V int64 `json:"v,omitempty"`
Version string `json:"version"`
}
// CurrentInput is what current takes.
type CurrentInput struct {
}
// CurrentAnswer is what current answers.
type CurrentAnswer = map[string]any
// PauseInput is what pause takes.
type PauseInput struct {
}
// PauseAnswer is what pause answers.
type PauseAnswer = map[string]any
// ResumeInput is what resume takes.
type ResumeInput struct {
}
// ResumeAnswer is what resume answers.
type ResumeAnswer = map[string]any
// DeliveryAccept is the body of delivery.
type DeliveryAccept = StepAsk
// CheckAccept is the body of check.
type CheckAccept = StepAsk
// RecheckAccept is the body of recheck.
type RecheckAccept = StepAsk
// StepsByNodeIDValue is one value of the state steps under the key <node>.<id>.
type StepsByNodeIDValue = Step
// PausesByPausedNodeValue is one value of the state pauses under the key paused.<node>.
type PausesByPausedNodeValue = Pause
// PausesByCapacityNodeValue is one value of the state pauses under the key capacity.<node>.
type PausesByCapacityNodeValue = Capacity
// ToolchainsByNodeLanguageValue is one value of the state toolchains under the key <node>.<language>.
type ToolchainsByNodeLanguageValue = Toolchain
@@ -0,0 +1,68 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
package nodebuildnode
import (
"encoding/json"
"reflect"
"regexp"
"testing"
)
// TestFixtures reads every fixture of seats/node-build-node/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: "a running step", subject: "", given: "{\"id\":\"a1b2\",\"node\":\"ace\",\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"running\",\"tool\":\"build\",\"v\":1}", wire: "{\"id\":\"a1b2\",\"node\":\"ace\",\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"running\",\"tool\":\"build\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepsByNodeIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "a paused node", subject: "", given: "{\"at\":\"2026-11-05T10:00:00Z\",\"by\":\"operator@shanks\",\"paused\":true,\"v\":1}", wire: "{\"at\":\"2026-11-05T10:00:00Z\",\"by\":\"operator@shanks\",\"paused\":true,\"v\":1}",
decode: func(b []byte) (any, error) {
var v PausesByPausedNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a node's capacity", subject: "", given: "{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}", wire: "{\"configured\":2,\"effective\":2,\"v\":1,\"why\":\"the configured steps fit the cores\"}",
decode: func(b []byte) (any, error) {
var v PausesByCapacityNodeValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a node's toolchain", subject: "", given: "{\"language\":\"go\",\"recipe\":\"1\",\"v\":1,\"version\":\"1.26.0\"}", wire: "{\"language\":\"go\",\"recipe\":\"1\",\"v\":1,\"version\":\"1.26.0\"}",
decode: func(b []byte) (any, error) {
var v ToolchainsByNodeLanguageValue
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a build ask", subject: "mesh.seat.node-build-node.accept.delivery", given: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b2\",\"kind\":\"build\",\"language\":\"go\"}", wire: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b2\",\"kind\":\"build\",\"language\":\"go\"}",
decode: func(b []byte) (any, error) { var v DeliveryAccept; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-node\\.accept\\.delivery$")},
}
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
@@ -0,0 +1,3 @@
module git.novox.be/novox/mesh-delivery/contracts/go/seats/nodebuildnode
go 1.26.0
+60
View File
@@ -53,6 +53,36 @@
"series": "0.1",
"generated-from": "."
},
{
"name": "go-nodebuildgo",
"kind": "package",
"language": "go",
"paths": [
"go/seats/nodebuildgo"
],
"series": "0.1",
"generated-from": "."
},
{
"name": "go-nodebuildimage",
"kind": "package",
"language": "go",
"paths": [
"go/seats/nodebuildimage"
],
"series": "0.1",
"generated-from": "."
},
{
"name": "go-nodebuildnode",
"kind": "package",
"language": "go",
"paths": [
"go/seats/nodebuildnode"
],
"series": "0.1",
"generated-from": "."
},
{
"name": "go-npmpackageregistry",
"kind": "package",
@@ -159,6 +189,36 @@
"series": "0.1",
"generated-from": "."
},
{
"name": "ts-nodebuildgo",
"kind": "package",
"language": "typescript",
"paths": [
"ts/seats/nodebuildgo"
],
"series": "0.1",
"generated-from": "."
},
{
"name": "ts-nodebuildimage",
"kind": "package",
"language": "typescript",
"paths": [
"ts/seats/nodebuildimage"
],
"series": "0.1",
"generated-from": "."
},
{
"name": "ts-nodebuildnode",
"kind": "package",
"language": "typescript",
"paths": [
"ts/seats/nodebuildnode"
],
"series": "0.1",
"generated-from": "."
},
{
"name": "ts-npmpackageregistry",
"kind": "package",
+588
View File
@@ -0,0 +1,588 @@
{
"format": 1,
"part": "build-step",
"description": "What the three build seats share: the verbs that read and steer a node's builds, and the layouts of the asks they accept and the steps they keep. A seat lists its states against these (a part carries no states).",
"verbs": [
{
"name": "current",
"description": "The 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": {
"type": "object",
"properties": {}
},
"answer": {
"type": "object",
"description": "the steps running, the capacity and whether paused"
}
},
{
"name": "pause",
"description": "Take no new ask on this node until resumed; an ask running here ends in its place. Kept across a restart of the build module. A capacity of 0 is the lasting way to keep a node from building.",
"input": {
"type": "object",
"properties": {}
},
"answer": {
"type": "object",
"description": "whether the node is paused"
}
},
{
"name": "resume",
"description": "Take asks again on this node.",
"input": {
"type": "object",
"properties": {}
},
"answer": {
"type": "object",
"description": "whether the node is paused"
}
}
],
"defs": {
"StepAsk": {
"type": "object",
"properties": {
"v": {
"type": "integer",
"description": "the layout version"
},
"id": {
"type": "string"
},
"kind": {
"type": "string",
"description": "build, check or compose"
},
"language": {
"type": "string",
"description": "go, typescript or image"
},
"asker": {
"type": "string"
},
"at": {
"type": "string",
"description": "when (RFC 3339 time)"
},
"build": {
"type": "object",
"properties": {
"module": {
"type": "string"
},
"path": {
"type": "string"
},
"fp": {
"type": "string"
},
"fetch": {
"description": "what the build module fetches: the repository, commit and directory, as the indexer states it"
},
"artifacts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"artifact": {
"type": "string"
},
"from": {
"type": "string"
},
"seat": {
"type": "string"
},
"version": {
"type": "string"
}
},
"required": [
"artifact"
]
}
},
"publish": {
"type": "boolean"
},
"toolchain": {
"type": "object",
"properties": {
"language": {
"type": "string"
},
"version": {
"type": "string"
},
"recipe": {
"type": "string"
}
},
"required": [
"language",
"version",
"recipe"
]
}
},
"required": [
"module",
"artifacts"
]
},
"check": {
"type": "object",
"properties": {
"fetch": {
"description": "what the build module fetches: the repository, commit and directory, as the indexer states it"
},
"levels": {
"type": "array",
"items": {
"type": "string",
"description": "unit or integration"
}
},
"kept": {
"type": "boolean"
},
"runner": {
"type": "string"
},
"runner_when": {
"type": "string"
},
"run": {
"type": "string"
},
"packages": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"fetch",
"levels"
]
},
"compose": {
"type": "object",
"properties": {
"fetch": {
"description": "what the build module fetches: the repository, commit and directory, as the indexer states it"
},
"dir": {
"type": "string"
},
"package": {
"type": "string"
},
"request": {
"description": "the compose-candidate request"
},
"reader": {
"type": "string"
}
},
"required": [
"fetch",
"dir",
"package",
"request"
]
},
"needs": {
"type": "array",
"items": {
"type": "string"
}
},
"packages": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "package to the tagged version a build pins"
}
},
"required": [
"id",
"kind",
"language",
"asker"
],
"description": "one ask of a build module"
},
"BuildAnswer": {
"type": "object",
"properties": {
"artifacts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"artifact": {
"type": "string"
},
"digest": {
"type": "string"
},
"reference": {
"type": "string"
}
},
"required": [
"artifact",
"digest"
]
}
},
"toolchain": {
"type": "object",
"properties": {
"language": {
"type": "string"
},
"version": {
"type": "string"
},
"recipe": {
"type": "string"
}
},
"required": [
"language",
"version",
"recipe"
]
},
"imports": {
"type": "array",
"items": {
"type": "string"
}
},
"out-of-step": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"artifacts"
]
},
"CheckAnswer": {
"type": "object",
"properties": {
"fetch": {
"description": "what the build module fetches: the repository, commit and directory, as the indexer states it"
},
"levels": {
"type": "array",
"items": {
"type": "object",
"properties": {
"level": {
"type": "string"
},
"judged": {
"type": "string"
},
"digest": {
"type": "object",
"properties": {
"level": {
"type": "string"
},
"packages": {
"type": "array",
"items": {
"type": "object",
"properties": {
"package": {
"type": "string"
},
"digest": {
"type": "string"
}
},
"required": [
"package",
"digest"
]
}
},
"beside": {
"type": "array",
"items": {
"type": "string"
}
},
"without_tests": {
"type": "array",
"items": {
"type": "string"
}
},
"judged_by": {
"type": "string"
},
"needs": {
"type": "array",
"items": {
"type": "object",
"properties": {
"package": {
"type": "string"
},
"needs": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
}
},
"kept": {
"type": "array",
"items": {
"type": "object",
"properties": {
"package": {
"type": "string"
},
"digest": {
"type": "string"
},
"tests": {
"type": "integer"
}
}
}
},
"tests": {
"type": "array",
"items": {
"description": "one test's result"
}
},
"unmet": {
"type": "array",
"items": {
"type": "object",
"properties": {
"package": {
"type": "string"
},
"needs": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
},
"required": [
"level"
]
}
}
},
"required": [
"fetch"
]
},
"ComposeAnswer": {
"type": "object",
"properties": {
"built": {
"type": "boolean"
},
"key": {
"type": "string"
},
"verdict": {
"description": "the compose-candidate verdict"
}
},
"required": [
"built"
]
},
"Step": {
"type": "object",
"properties": {
"v": {
"type": "integer",
"description": "the layout version"
},
"id": {
"type": "string"
},
"tool": {
"type": "string"
},
"node": {
"type": "string"
},
"state": {
"type": "string",
"description": "running, passed, failed or refused"
},
"started": {
"type": "string",
"description": "when (RFC 3339 time)"
},
"ended": {
"type": "string",
"description": "when (RFC 3339 time)"
},
"reason": {
"type": "string"
},
"result": {
"description": "what the step answered"
},
"what": {
"type": "string"
},
"phase": {
"type": "string"
},
"phase-at": {
"type": "string",
"description": "when (RFC 3339 time)"
},
"owner": {
"type": "string"
}
},
"required": [
"id",
"tool",
"node",
"state",
"started"
],
"description": "one step a build module runs on a node"
},
"Toolchain": {
"type": "object",
"properties": {
"v": {
"type": "integer",
"description": "the layout version"
},
"language": {
"type": "string",
"description": "go or typescript"
},
"version": {
"type": "string"
},
"recipe": {
"type": "string"
},
"at": {
"type": "string",
"description": "when (RFC 3339 time)"
}
},
"required": [
"language",
"version",
"recipe"
],
"description": "the toolchain a node reports"
},
"Pause": {
"type": "object",
"properties": {
"v": {
"type": "integer",
"description": "the layout version"
},
"paused": {
"type": "boolean"
},
"by": {
"type": "string"
},
"at": {
"type": "string",
"description": "when (RFC 3339 time)"
}
},
"required": [
"paused"
],
"description": "whether the node takes no new ask"
},
"Capacity": {
"type": "object",
"properties": {
"v": {
"type": "integer",
"description": "the layout version"
},
"effective": {
"type": "integer"
},
"configured": {
"type": "integer"
},
"configured-from": {
"type": "string"
},
"quota-cores": {
"type": "number"
},
"quota-from": {
"type": "string"
},
"cores-per-step": {
"type": "number"
},
"by-cpu": {
"type": "integer"
},
"build-hours": {
"type": "string"
},
"outside-hours": {
"type": "boolean"
},
"build-hours-fault": {
"type": "string"
},
"ineligible": {
"type": "string"
},
"why": {
"type": "string"
},
"at": {
"type": "string",
"description": "when (RFC 3339 time)"
}
},
"required": [
"effective",
"configured",
"why"
],
"description": "how many steps the node runs at once"
}
}
}
@@ -0,0 +1,63 @@
[
{
"name": "a running step",
"of": "state:steps/<node>.<id>",
"given": {
"v": 1,
"id": "a1b2",
"tool": "build",
"node": "ace",
"state": "running",
"started": "2026-11-05T10:00:00Z"
}
},
{
"name": "a paused node",
"of": "state:pauses/paused.<node>",
"given": {
"v": 1,
"paused": true,
"by": "operator@shanks",
"at": "2026-11-05T10:00:00Z"
}
},
{
"name": "a node's capacity",
"of": "state:pauses/capacity.<node>",
"given": {
"v": 1,
"effective": 2,
"configured": 2,
"why": "the configured steps fit the cores"
}
},
{
"name": "a node's toolchain",
"of": "state:toolchains/<node>.<language>",
"given": {
"v": 1,
"language": "go",
"version": "1.26.0",
"recipe": "1"
}
},
{
"name": "a build ask",
"of": "accept:delivery",
"subject": "mesh.seat.node-build-go.accept.delivery",
"given": {
"id": "a1b2",
"kind": "build",
"language": "go",
"asker": "mesh-delivery-builder",
"build": {
"module": "nats",
"artifacts": [
{
"artifact": "go"
}
]
}
}
}
]
+87
View File
@@ -0,0 +1,87 @@
{
"format": 1,
"seat": "node-build-go",
"scope": "node",
"grain": "whole",
"decision": "novox/hq ADR 0525, ADR 0536, ADR 0553",
"pulled-by-kind": true,
"yields": true,
"accepts": [
{
"name": "delivery",
"body": {
"$ref": "#/defs/StepAsk"
}
},
{
"name": "check",
"body": {
"$ref": "#/defs/StepAsk"
}
},
{
"name": "recheck",
"body": {
"$ref": "#/defs/StepAsk"
}
}
],
"description": "The Go build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.",
"includes": [
"build-step"
],
"states": [
{
"name": "steps",
"template": "state",
"key-forms": [
{
"key": "<node>.<id>",
"value": {
"$ref": "#/defs/Step"
},
"description": "a step on a node"
}
],
"description": "the steps this module runs",
"history": 5
},
{
"name": "pauses",
"template": "state",
"key-forms": [
{
"key": "paused.<node>",
"value": {
"$ref": "#/defs/Pause"
},
"description": "whether a node is paused"
},
{
"key": "capacity.<node>",
"value": {
"$ref": "#/defs/Capacity"
},
"description": "a node's capacity"
}
],
"description": "the pause and the capacity of each node",
"history": 1
},
{
"name": "toolchains",
"template": "state",
"key-forms": [
{
"key": "<node>.<language>",
"value": {
"$ref": "#/defs/Toolchain"
},
"description": "the toolchain a node reports"
}
],
"description": "the toolchains the nodes report",
"history": 1
}
]
}
@@ -0,0 +1,63 @@
[
{
"name": "a running step",
"of": "state:steps/<node>.<id>",
"given": {
"v": 1,
"id": "a1b2",
"tool": "build",
"node": "ace",
"state": "running",
"started": "2026-11-05T10:00:00Z"
}
},
{
"name": "a paused node",
"of": "state:pauses/paused.<node>",
"given": {
"v": 1,
"paused": true,
"by": "operator@shanks",
"at": "2026-11-05T10:00:00Z"
}
},
{
"name": "a node's capacity",
"of": "state:pauses/capacity.<node>",
"given": {
"v": 1,
"effective": 2,
"configured": 2,
"why": "the configured steps fit the cores"
}
},
{
"name": "a node's toolchain",
"of": "state:toolchains/<node>.<language>",
"given": {
"v": 1,
"language": "go",
"version": "1.26.0",
"recipe": "1"
}
},
{
"name": "a build ask",
"of": "accept:delivery",
"subject": "mesh.seat.node-build-image.accept.delivery",
"given": {
"id": "a1b2",
"kind": "build",
"language": "go",
"asker": "mesh-delivery-builder",
"build": {
"module": "nats",
"artifacts": [
{
"artifact": "go"
}
]
}
}
}
]
@@ -0,0 +1,87 @@
{
"format": 1,
"seat": "node-build-image",
"scope": "node",
"grain": "whole",
"decision": "novox/hq ADR 0525, ADR 0536, ADR 0553",
"pulled-by-kind": true,
"yields": true,
"accepts": [
{
"name": "delivery",
"body": {
"$ref": "#/defs/StepAsk"
}
},
{
"name": "check",
"body": {
"$ref": "#/defs/StepAsk"
}
},
{
"name": "recheck",
"body": {
"$ref": "#/defs/StepAsk"
}
}
],
"description": "The image build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.",
"includes": [
"build-step"
],
"states": [
{
"name": "steps",
"template": "state",
"key-forms": [
{
"key": "<node>.<id>",
"value": {
"$ref": "#/defs/Step"
},
"description": "a step on a node"
}
],
"description": "the steps this module runs",
"history": 5
},
{
"name": "pauses",
"template": "state",
"key-forms": [
{
"key": "paused.<node>",
"value": {
"$ref": "#/defs/Pause"
},
"description": "whether a node is paused"
},
{
"key": "capacity.<node>",
"value": {
"$ref": "#/defs/Capacity"
},
"description": "a node's capacity"
}
],
"description": "the pause and the capacity of each node",
"history": 1
},
{
"name": "toolchains",
"template": "state",
"key-forms": [
{
"key": "<node>.<language>",
"value": {
"$ref": "#/defs/Toolchain"
},
"description": "the toolchain a node reports"
}
],
"description": "the toolchains the nodes report",
"history": 1
}
]
}
@@ -0,0 +1,63 @@
[
{
"name": "a running step",
"of": "state:steps/<node>.<id>",
"given": {
"v": 1,
"id": "a1b2",
"tool": "build",
"node": "ace",
"state": "running",
"started": "2026-11-05T10:00:00Z"
}
},
{
"name": "a paused node",
"of": "state:pauses/paused.<node>",
"given": {
"v": 1,
"paused": true,
"by": "operator@shanks",
"at": "2026-11-05T10:00:00Z"
}
},
{
"name": "a node's capacity",
"of": "state:pauses/capacity.<node>",
"given": {
"v": 1,
"effective": 2,
"configured": 2,
"why": "the configured steps fit the cores"
}
},
{
"name": "a node's toolchain",
"of": "state:toolchains/<node>.<language>",
"given": {
"v": 1,
"language": "go",
"version": "1.26.0",
"recipe": "1"
}
},
{
"name": "a build ask",
"of": "accept:delivery",
"subject": "mesh.seat.node-build-node.accept.delivery",
"given": {
"id": "a1b2",
"kind": "build",
"language": "go",
"asker": "mesh-delivery-builder",
"build": {
"module": "nats",
"artifacts": [
{
"artifact": "go"
}
]
}
}
}
]
+87
View File
@@ -0,0 +1,87 @@
{
"format": 1,
"seat": "node-build-node",
"scope": "node",
"grain": "whole",
"decision": "novox/hq ADR 0525, ADR 0536, ADR 0553",
"pulled-by-kind": true,
"yields": true,
"accepts": [
{
"name": "delivery",
"body": {
"$ref": "#/defs/StepAsk"
}
},
{
"name": "check",
"body": {
"$ref": "#/defs/StepAsk"
}
},
{
"name": "recheck",
"body": {
"$ref": "#/defs/StepAsk"
}
}
],
"description": "The Node build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.",
"includes": [
"build-step"
],
"states": [
{
"name": "steps",
"template": "state",
"key-forms": [
{
"key": "<node>.<id>",
"value": {
"$ref": "#/defs/Step"
},
"description": "a step on a node"
}
],
"description": "the steps this module runs",
"history": 5
},
{
"name": "pauses",
"template": "state",
"key-forms": [
{
"key": "paused.<node>",
"value": {
"$ref": "#/defs/Pause"
},
"description": "whether a node is paused"
},
{
"key": "capacity.<node>",
"value": {
"$ref": "#/defs/Capacity"
},
"description": "a node's capacity"
}
],
"description": "the pause and the capacity of each node",
"history": 1
},
{
"name": "toolchains",
"template": "state",
"key-forms": [
{
"key": "<node>.<language>",
"value": {
"$ref": "#/defs/Toolchain"
},
"description": "the toolchain a node reports"
}
],
"description": "the toolchains the nodes report",
"history": 1
}
]
}
+12
View File
@@ -0,0 +1,12 @@
{
"lockfileVersion": 3,
"name": "@novox/mesh-delivery-contracts-node-build-go",
"packages": {
"": {
"name": "@novox/mesh-delivery-contracts-node-build-go",
"version": "0.1.0"
}
},
"requires": true,
"version": "0.1.0"
}
@@ -0,0 +1,13 @@
{
"description": "The contract of the seat node-build-go, generated from its definition.",
"exports": {
".": "./src/index.ts"
},
"files": [
"src"
],
"name": "@novox/mesh-delivery-contracts-node-build-go",
"type": "module",
"types": "./src/index.ts",
"version": "0.1.0"
}
+153
View File
@@ -0,0 +1,153 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "node-build-go", defined whole (seats/node-build-go/seat.json): The Go build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.
import type * as buildStep from "./parts/build-step.js";
export const seat = "node-build-go";
export const verbs = {
current: "current",
pause: "pause",
resume: "resume",
} as const;
export const accepts = {
delivery: "delivery",
check: "check",
recheck: "recheck",
} as const;
export const deliverySubject = "mesh.seat.node-build-go.accept.delivery";
export const checkSubject = "mesh.seat.node-build-go.accept.check";
export const recheckSubject = "mesh.seat.node-build-go.accept.recheck";
export const states = {
steps: "steps",
pauses: "pauses",
toolchains: "toolchains",
} as const;
/** The key of one value of the state steps under the form "<node>.<id>". */
export function stepsByNodeIDKey(node: string, id: string): string {
return node + "." + id;
}
/** The parts of a key of the form "<node>.<id>", or undefined for a key of another form. */
export function parseStepsByNodeIDKey(key: string): { node: string; id: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const id = rest;
rest = "";
if (rest !== "") return undefined;
return { node, id };
}
/** The key of one value of the state pauses under the form "paused.<node>". */
export function pausesByPausedNodeKey(node: string): string {
return "paused." + node;
}
/** The parts of a key of the form "paused.<node>", or undefined for a key of another form. */
export function parsePausesByPausedNodeKey(key: string): { node: string } | undefined {
let rest = key;
if (!rest.startsWith("paused.")) return undefined;
rest = rest.slice(7);
if (rest === "") return undefined;
const node = rest;
rest = "";
if (rest !== "") return undefined;
return { node };
}
/** The key of one value of the state pauses under the form "capacity.<node>". */
export function pausesByCapacityNodeKey(node: string): string {
return "capacity." + node;
}
/** The parts of a key of the form "capacity.<node>", or undefined for a key of another form. */
export function parsePausesByCapacityNodeKey(key: string): { node: string } | undefined {
let rest = key;
if (!rest.startsWith("capacity.")) return undefined;
rest = rest.slice(9);
if (rest === "") return undefined;
const node = rest;
rest = "";
if (rest !== "") return undefined;
return { node };
}
/** The key of one value of the state toolchains under the form "<node>.<language>". */
export function toolchainsByNodeLanguageKey(node: string, language: string): string {
return node + "." + language;
}
/** The parts of a key of the form "<node>.<language>", or undefined for a key of another form. */
export function parseToolchainsByNodeLanguageKey(key: string): { node: string; language: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const language = rest;
rest = "";
if (rest !== "") return undefined;
return { node, language };
}
export type BuildAnswer = buildStep.BuildAnswer;
export type BuildAnswerArtifactsItem = buildStep.BuildAnswerArtifactsItem;
export type BuildAnswerToolchain = buildStep.BuildAnswerToolchain;
export type Capacity = buildStep.Capacity;
export type CheckAnswer = buildStep.CheckAnswer;
export type CheckAnswerLevelsItem = buildStep.CheckAnswerLevelsItem;
export type CheckAnswerLevelsItemDigest = buildStep.CheckAnswerLevelsItemDigest;
export type CheckAnswerLevelsItemDigestNeedsItem = buildStep.CheckAnswerLevelsItemDigestNeedsItem;
export type CheckAnswerLevelsItemDigestPackagesItem = buildStep.CheckAnswerLevelsItemDigestPackagesItem;
export type CheckAnswerLevelsItemKeptItem = buildStep.CheckAnswerLevelsItemKeptItem;
export type CheckAnswerLevelsItemUnmetItem = buildStep.CheckAnswerLevelsItemUnmetItem;
export type ComposeAnswer = buildStep.ComposeAnswer;
export type CurrentAnswer = buildStep.CurrentAnswer;
export type CurrentInput = buildStep.CurrentInput;
export type Pause = buildStep.Pause;
export type PauseAnswer = buildStep.PauseAnswer;
export type PauseInput = buildStep.PauseInput;
export type ResumeAnswer = buildStep.ResumeAnswer;
export type ResumeInput = buildStep.ResumeInput;
export type Step = buildStep.Step;
export type StepAsk = buildStep.StepAsk;
export type StepAskBuild = buildStep.StepAskBuild;
export type StepAskBuildArtifactsItem = buildStep.StepAskBuildArtifactsItem;
export type StepAskBuildToolchain = buildStep.StepAskBuildToolchain;
export type StepAskCheck = buildStep.StepAskCheck;
export type StepAskCompose = buildStep.StepAskCompose;
export type Toolchain = buildStep.Toolchain;
/** is the body of delivery. */
export type DeliveryAccept = StepAsk;
/** is the body of check. */
export type CheckAccept = StepAsk;
/** is the body of recheck. */
export type RecheckAccept = StepAsk;
/** is one value of the state steps under the key <node>.<id>. */
export type StepsByNodeIDValue = Step;
/** is one value of the state pauses under the key paused.<node>. */
export type PausesByPausedNodeValue = Pause;
/** is one value of the state pauses under the key capacity.<node>. */
export type PausesByCapacityNodeValue = Capacity;
/** is one value of the state toolchains under the key <node>.<language>. */
export type ToolchainsByNodeLanguageValue = Toolchain;
@@ -0,0 +1,232 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The part "build-step" several seats include whole: What the three build seats share: the verbs that read and steer a node's builds, and the layouts of the asks they accept and the steps they keep. A seat lists its states against these (a part carries no states).
export const verbs = {
current: "current",
pause: "pause",
resume: "resume",
} as const;
export interface BuildAnswerArtifactsItem {
"artifact": string;
"digest": string;
"reference"?: string;
}
export interface BuildAnswerToolchain {
"language": string;
"recipe": string;
"version": string;
}
export interface BuildAnswer {
"artifacts": BuildAnswerArtifactsItem[];
"imports"?: string[];
"out-of-step"?: string[];
"toolchain"?: BuildAnswerToolchain;
}
/** how many steps the node runs at once */
export interface Capacity {
/** when (RFC 3339 time) */
"at"?: string;
"build-hours"?: string;
"build-hours-fault"?: string;
"by-cpu"?: number;
"configured": number;
"configured-from"?: string;
"cores-per-step"?: number;
"effective": number;
"ineligible"?: string;
"outside-hours"?: boolean;
"quota-cores"?: number;
"quota-from"?: string;
/** the layout version */
"v"?: number;
"why": string;
}
export interface CheckAnswerLevelsItemDigestNeedsItem {
"needs"?: string[];
"package"?: string;
}
export interface CheckAnswerLevelsItemDigestPackagesItem {
"digest": string;
"package": string;
}
export interface CheckAnswerLevelsItemDigest {
"beside"?: string[];
"judged_by"?: string;
"level"?: string;
"needs"?: CheckAnswerLevelsItemDigestNeedsItem[];
"packages"?: CheckAnswerLevelsItemDigestPackagesItem[];
"without_tests"?: string[];
}
export interface CheckAnswerLevelsItemKeptItem {
"digest"?: string;
"package"?: string;
"tests"?: number;
}
export interface CheckAnswerLevelsItemUnmetItem {
"needs"?: string[];
"package"?: string;
}
export interface CheckAnswerLevelsItem {
"digest"?: CheckAnswerLevelsItemDigest;
"judged"?: string;
"kept"?: CheckAnswerLevelsItemKeptItem[];
"level": string;
"tests"?: unknown[];
"unmet"?: CheckAnswerLevelsItemUnmetItem[];
}
export interface CheckAnswer {
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch": unknown;
"levels"?: CheckAnswerLevelsItem[];
}
export interface ComposeAnswer {
"built": boolean;
"key"?: string;
/** the compose-candidate verdict */
"verdict"?: unknown;
}
/** whether the node takes no new ask */
export interface Pause {
/** when (RFC 3339 time) */
"at"?: string;
"by"?: string;
"paused": boolean;
/** the layout version */
"v"?: number;
}
/** one step a build module runs on a node */
export interface Step {
/** when (RFC 3339 time) */
"ended"?: string;
"id": string;
"node": string;
"owner"?: string;
"phase"?: string;
/** when (RFC 3339 time) */
"phase-at"?: string;
"reason"?: string;
/** what the step answered */
"result"?: unknown;
/** when (RFC 3339 time) */
"started": string;
/** running, passed, failed or refused */
"state": string;
"tool": string;
/** the layout version */
"v"?: number;
"what"?: string;
}
export interface StepAskBuildArtifactsItem {
"artifact": string;
"from"?: string;
"seat"?: string;
"version"?: string;
}
export interface StepAskBuildToolchain {
"language": string;
"recipe": string;
"version": string;
}
export interface StepAskBuild {
"artifacts": StepAskBuildArtifactsItem[];
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch"?: unknown;
"fp"?: string;
"module": string;
"path"?: string;
"publish"?: boolean;
"toolchain"?: StepAskBuildToolchain;
}
export interface StepAskCheck {
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch": unknown;
"kept"?: boolean;
"levels": string[];
"packages"?: string[];
"run"?: string;
"runner"?: string;
"runner_when"?: string;
}
export interface StepAskCompose {
"dir": string;
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch": unknown;
"package": string;
"reader"?: string;
/** the compose-candidate request */
"request": unknown;
}
/** one ask of a build module */
export interface StepAsk {
"asker": string;
/** when (RFC 3339 time) */
"at"?: string;
"build"?: StepAskBuild;
"check"?: StepAskCheck;
"compose"?: StepAskCompose;
"id": string;
/** build, check or compose */
"kind": string;
/** go, typescript or image */
"language": string;
"needs"?: string[];
/** package to the tagged version a build pins */
"packages"?: Record<string, string>;
/** the layout version */
"v"?: number;
}
/** the toolchain a node reports */
export interface Toolchain {
/** when (RFC 3339 time) */
"at"?: string;
/** go or typescript */
"language": string;
"recipe": string;
/** the layout version */
"v"?: number;
"version": string;
}
/** is what current takes. */
export interface CurrentInput {
}
/** is what current answers. */
export type CurrentAnswer = Record<string, unknown>;
/** is what pause takes. */
export interface PauseInput {
}
/** is what pause answers. */
export type PauseAnswer = Record<string, unknown>;
/** is what resume takes. */
export interface ResumeInput {
}
/** is what resume answers. */
export type ResumeAnswer = Record<string, unknown>;
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
+12
View File
@@ -0,0 +1,12 @@
{
"lockfileVersion": 3,
"name": "@novox/mesh-delivery-contracts-node-build-image",
"packages": {
"": {
"name": "@novox/mesh-delivery-contracts-node-build-image",
"version": "0.1.0"
}
},
"requires": true,
"version": "0.1.0"
}
@@ -0,0 +1,13 @@
{
"description": "The contract of the seat node-build-image, generated from its definition.",
"exports": {
".": "./src/index.ts"
},
"files": [
"src"
],
"name": "@novox/mesh-delivery-contracts-node-build-image",
"type": "module",
"types": "./src/index.ts",
"version": "0.1.0"
}
@@ -0,0 +1,153 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "node-build-image", defined whole (seats/node-build-image/seat.json): The image build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.
import type * as buildStep from "./parts/build-step.js";
export const seat = "node-build-image";
export const verbs = {
current: "current",
pause: "pause",
resume: "resume",
} as const;
export const accepts = {
delivery: "delivery",
check: "check",
recheck: "recheck",
} as const;
export const deliverySubject = "mesh.seat.node-build-image.accept.delivery";
export const checkSubject = "mesh.seat.node-build-image.accept.check";
export const recheckSubject = "mesh.seat.node-build-image.accept.recheck";
export const states = {
steps: "steps",
pauses: "pauses",
toolchains: "toolchains",
} as const;
/** The key of one value of the state steps under the form "<node>.<id>". */
export function stepsByNodeIDKey(node: string, id: string): string {
return node + "." + id;
}
/** The parts of a key of the form "<node>.<id>", or undefined for a key of another form. */
export function parseStepsByNodeIDKey(key: string): { node: string; id: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const id = rest;
rest = "";
if (rest !== "") return undefined;
return { node, id };
}
/** The key of one value of the state pauses under the form "paused.<node>". */
export function pausesByPausedNodeKey(node: string): string {
return "paused." + node;
}
/** The parts of a key of the form "paused.<node>", or undefined for a key of another form. */
export function parsePausesByPausedNodeKey(key: string): { node: string } | undefined {
let rest = key;
if (!rest.startsWith("paused.")) return undefined;
rest = rest.slice(7);
if (rest === "") return undefined;
const node = rest;
rest = "";
if (rest !== "") return undefined;
return { node };
}
/** The key of one value of the state pauses under the form "capacity.<node>". */
export function pausesByCapacityNodeKey(node: string): string {
return "capacity." + node;
}
/** The parts of a key of the form "capacity.<node>", or undefined for a key of another form. */
export function parsePausesByCapacityNodeKey(key: string): { node: string } | undefined {
let rest = key;
if (!rest.startsWith("capacity.")) return undefined;
rest = rest.slice(9);
if (rest === "") return undefined;
const node = rest;
rest = "";
if (rest !== "") return undefined;
return { node };
}
/** The key of one value of the state toolchains under the form "<node>.<language>". */
export function toolchainsByNodeLanguageKey(node: string, language: string): string {
return node + "." + language;
}
/** The parts of a key of the form "<node>.<language>", or undefined for a key of another form. */
export function parseToolchainsByNodeLanguageKey(key: string): { node: string; language: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const language = rest;
rest = "";
if (rest !== "") return undefined;
return { node, language };
}
export type BuildAnswer = buildStep.BuildAnswer;
export type BuildAnswerArtifactsItem = buildStep.BuildAnswerArtifactsItem;
export type BuildAnswerToolchain = buildStep.BuildAnswerToolchain;
export type Capacity = buildStep.Capacity;
export type CheckAnswer = buildStep.CheckAnswer;
export type CheckAnswerLevelsItem = buildStep.CheckAnswerLevelsItem;
export type CheckAnswerLevelsItemDigest = buildStep.CheckAnswerLevelsItemDigest;
export type CheckAnswerLevelsItemDigestNeedsItem = buildStep.CheckAnswerLevelsItemDigestNeedsItem;
export type CheckAnswerLevelsItemDigestPackagesItem = buildStep.CheckAnswerLevelsItemDigestPackagesItem;
export type CheckAnswerLevelsItemKeptItem = buildStep.CheckAnswerLevelsItemKeptItem;
export type CheckAnswerLevelsItemUnmetItem = buildStep.CheckAnswerLevelsItemUnmetItem;
export type ComposeAnswer = buildStep.ComposeAnswer;
export type CurrentAnswer = buildStep.CurrentAnswer;
export type CurrentInput = buildStep.CurrentInput;
export type Pause = buildStep.Pause;
export type PauseAnswer = buildStep.PauseAnswer;
export type PauseInput = buildStep.PauseInput;
export type ResumeAnswer = buildStep.ResumeAnswer;
export type ResumeInput = buildStep.ResumeInput;
export type Step = buildStep.Step;
export type StepAsk = buildStep.StepAsk;
export type StepAskBuild = buildStep.StepAskBuild;
export type StepAskBuildArtifactsItem = buildStep.StepAskBuildArtifactsItem;
export type StepAskBuildToolchain = buildStep.StepAskBuildToolchain;
export type StepAskCheck = buildStep.StepAskCheck;
export type StepAskCompose = buildStep.StepAskCompose;
export type Toolchain = buildStep.Toolchain;
/** is the body of delivery. */
export type DeliveryAccept = StepAsk;
/** is the body of check. */
export type CheckAccept = StepAsk;
/** is the body of recheck. */
export type RecheckAccept = StepAsk;
/** is one value of the state steps under the key <node>.<id>. */
export type StepsByNodeIDValue = Step;
/** is one value of the state pauses under the key paused.<node>. */
export type PausesByPausedNodeValue = Pause;
/** is one value of the state pauses under the key capacity.<node>. */
export type PausesByCapacityNodeValue = Capacity;
/** is one value of the state toolchains under the key <node>.<language>. */
export type ToolchainsByNodeLanguageValue = Toolchain;
@@ -0,0 +1,232 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The part "build-step" several seats include whole: What the three build seats share: the verbs that read and steer a node's builds, and the layouts of the asks they accept and the steps they keep. A seat lists its states against these (a part carries no states).
export const verbs = {
current: "current",
pause: "pause",
resume: "resume",
} as const;
export interface BuildAnswerArtifactsItem {
"artifact": string;
"digest": string;
"reference"?: string;
}
export interface BuildAnswerToolchain {
"language": string;
"recipe": string;
"version": string;
}
export interface BuildAnswer {
"artifacts": BuildAnswerArtifactsItem[];
"imports"?: string[];
"out-of-step"?: string[];
"toolchain"?: BuildAnswerToolchain;
}
/** how many steps the node runs at once */
export interface Capacity {
/** when (RFC 3339 time) */
"at"?: string;
"build-hours"?: string;
"build-hours-fault"?: string;
"by-cpu"?: number;
"configured": number;
"configured-from"?: string;
"cores-per-step"?: number;
"effective": number;
"ineligible"?: string;
"outside-hours"?: boolean;
"quota-cores"?: number;
"quota-from"?: string;
/** the layout version */
"v"?: number;
"why": string;
}
export interface CheckAnswerLevelsItemDigestNeedsItem {
"needs"?: string[];
"package"?: string;
}
export interface CheckAnswerLevelsItemDigestPackagesItem {
"digest": string;
"package": string;
}
export interface CheckAnswerLevelsItemDigest {
"beside"?: string[];
"judged_by"?: string;
"level"?: string;
"needs"?: CheckAnswerLevelsItemDigestNeedsItem[];
"packages"?: CheckAnswerLevelsItemDigestPackagesItem[];
"without_tests"?: string[];
}
export interface CheckAnswerLevelsItemKeptItem {
"digest"?: string;
"package"?: string;
"tests"?: number;
}
export interface CheckAnswerLevelsItemUnmetItem {
"needs"?: string[];
"package"?: string;
}
export interface CheckAnswerLevelsItem {
"digest"?: CheckAnswerLevelsItemDigest;
"judged"?: string;
"kept"?: CheckAnswerLevelsItemKeptItem[];
"level": string;
"tests"?: unknown[];
"unmet"?: CheckAnswerLevelsItemUnmetItem[];
}
export interface CheckAnswer {
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch": unknown;
"levels"?: CheckAnswerLevelsItem[];
}
export interface ComposeAnswer {
"built": boolean;
"key"?: string;
/** the compose-candidate verdict */
"verdict"?: unknown;
}
/** whether the node takes no new ask */
export interface Pause {
/** when (RFC 3339 time) */
"at"?: string;
"by"?: string;
"paused": boolean;
/** the layout version */
"v"?: number;
}
/** one step a build module runs on a node */
export interface Step {
/** when (RFC 3339 time) */
"ended"?: string;
"id": string;
"node": string;
"owner"?: string;
"phase"?: string;
/** when (RFC 3339 time) */
"phase-at"?: string;
"reason"?: string;
/** what the step answered */
"result"?: unknown;
/** when (RFC 3339 time) */
"started": string;
/** running, passed, failed or refused */
"state": string;
"tool": string;
/** the layout version */
"v"?: number;
"what"?: string;
}
export interface StepAskBuildArtifactsItem {
"artifact": string;
"from"?: string;
"seat"?: string;
"version"?: string;
}
export interface StepAskBuildToolchain {
"language": string;
"recipe": string;
"version": string;
}
export interface StepAskBuild {
"artifacts": StepAskBuildArtifactsItem[];
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch"?: unknown;
"fp"?: string;
"module": string;
"path"?: string;
"publish"?: boolean;
"toolchain"?: StepAskBuildToolchain;
}
export interface StepAskCheck {
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch": unknown;
"kept"?: boolean;
"levels": string[];
"packages"?: string[];
"run"?: string;
"runner"?: string;
"runner_when"?: string;
}
export interface StepAskCompose {
"dir": string;
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch": unknown;
"package": string;
"reader"?: string;
/** the compose-candidate request */
"request": unknown;
}
/** one ask of a build module */
export interface StepAsk {
"asker": string;
/** when (RFC 3339 time) */
"at"?: string;
"build"?: StepAskBuild;
"check"?: StepAskCheck;
"compose"?: StepAskCompose;
"id": string;
/** build, check or compose */
"kind": string;
/** go, typescript or image */
"language": string;
"needs"?: string[];
/** package to the tagged version a build pins */
"packages"?: Record<string, string>;
/** the layout version */
"v"?: number;
}
/** the toolchain a node reports */
export interface Toolchain {
/** when (RFC 3339 time) */
"at"?: string;
/** go or typescript */
"language": string;
"recipe": string;
/** the layout version */
"v"?: number;
"version": string;
}
/** is what current takes. */
export interface CurrentInput {
}
/** is what current answers. */
export type CurrentAnswer = Record<string, unknown>;
/** is what pause takes. */
export interface PauseInput {
}
/** is what pause answers. */
export type PauseAnswer = Record<string, unknown>;
/** is what resume takes. */
export interface ResumeInput {
}
/** is what resume answers. */
export type ResumeAnswer = Record<string, unknown>;
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}
+12
View File
@@ -0,0 +1,12 @@
{
"lockfileVersion": 3,
"name": "@novox/mesh-delivery-contracts-node-build-node",
"packages": {
"": {
"name": "@novox/mesh-delivery-contracts-node-build-node",
"version": "0.1.0"
}
},
"requires": true,
"version": "0.1.0"
}
@@ -0,0 +1,13 @@
{
"description": "The contract of the seat node-build-node, generated from its definition.",
"exports": {
".": "./src/index.ts"
},
"files": [
"src"
],
"name": "@novox/mesh-delivery-contracts-node-build-node",
"type": "module",
"types": "./src/index.ts",
"version": "0.1.0"
}
@@ -0,0 +1,153 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The contract of the seat "node-build-node", defined whole (seats/node-build-node/seat.json): The Node build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.
import type * as buildStep from "./parts/build-step.js";
export const seat = "node-build-node";
export const verbs = {
current: "current",
pause: "pause",
resume: "resume",
} as const;
export const accepts = {
delivery: "delivery",
check: "check",
recheck: "recheck",
} as const;
export const deliverySubject = "mesh.seat.node-build-node.accept.delivery";
export const checkSubject = "mesh.seat.node-build-node.accept.check";
export const recheckSubject = "mesh.seat.node-build-node.accept.recheck";
export const states = {
steps: "steps",
pauses: "pauses",
toolchains: "toolchains",
} as const;
/** The key of one value of the state steps under the form "<node>.<id>". */
export function stepsByNodeIDKey(node: string, id: string): string {
return node + "." + id;
}
/** The parts of a key of the form "<node>.<id>", or undefined for a key of another form. */
export function parseStepsByNodeIDKey(key: string): { node: string; id: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const id = rest;
rest = "";
if (rest !== "") return undefined;
return { node, id };
}
/** The key of one value of the state pauses under the form "paused.<node>". */
export function pausesByPausedNodeKey(node: string): string {
return "paused." + node;
}
/** The parts of a key of the form "paused.<node>", or undefined for a key of another form. */
export function parsePausesByPausedNodeKey(key: string): { node: string } | undefined {
let rest = key;
if (!rest.startsWith("paused.")) return undefined;
rest = rest.slice(7);
if (rest === "") return undefined;
const node = rest;
rest = "";
if (rest !== "") return undefined;
return { node };
}
/** The key of one value of the state pauses under the form "capacity.<node>". */
export function pausesByCapacityNodeKey(node: string): string {
return "capacity." + node;
}
/** The parts of a key of the form "capacity.<node>", or undefined for a key of another form. */
export function parsePausesByCapacityNodeKey(key: string): { node: string } | undefined {
let rest = key;
if (!rest.startsWith("capacity.")) return undefined;
rest = rest.slice(9);
if (rest === "") return undefined;
const node = rest;
rest = "";
if (rest !== "") return undefined;
return { node };
}
/** The key of one value of the state toolchains under the form "<node>.<language>". */
export function toolchainsByNodeLanguageKey(node: string, language: string): string {
return node + "." + language;
}
/** The parts of a key of the form "<node>.<language>", or undefined for a key of another form. */
export function parseToolchainsByNodeLanguageKey(key: string): { node: string; language: string } | undefined {
let rest = key;
const at0 = rest.indexOf(".");
if (at0 <= 0) return undefined;
const node = rest.slice(0, at0);
rest = rest.slice(at0 + 1);
if (rest === "") return undefined;
const language = rest;
rest = "";
if (rest !== "") return undefined;
return { node, language };
}
export type BuildAnswer = buildStep.BuildAnswer;
export type BuildAnswerArtifactsItem = buildStep.BuildAnswerArtifactsItem;
export type BuildAnswerToolchain = buildStep.BuildAnswerToolchain;
export type Capacity = buildStep.Capacity;
export type CheckAnswer = buildStep.CheckAnswer;
export type CheckAnswerLevelsItem = buildStep.CheckAnswerLevelsItem;
export type CheckAnswerLevelsItemDigest = buildStep.CheckAnswerLevelsItemDigest;
export type CheckAnswerLevelsItemDigestNeedsItem = buildStep.CheckAnswerLevelsItemDigestNeedsItem;
export type CheckAnswerLevelsItemDigestPackagesItem = buildStep.CheckAnswerLevelsItemDigestPackagesItem;
export type CheckAnswerLevelsItemKeptItem = buildStep.CheckAnswerLevelsItemKeptItem;
export type CheckAnswerLevelsItemUnmetItem = buildStep.CheckAnswerLevelsItemUnmetItem;
export type ComposeAnswer = buildStep.ComposeAnswer;
export type CurrentAnswer = buildStep.CurrentAnswer;
export type CurrentInput = buildStep.CurrentInput;
export type Pause = buildStep.Pause;
export type PauseAnswer = buildStep.PauseAnswer;
export type PauseInput = buildStep.PauseInput;
export type ResumeAnswer = buildStep.ResumeAnswer;
export type ResumeInput = buildStep.ResumeInput;
export type Step = buildStep.Step;
export type StepAsk = buildStep.StepAsk;
export type StepAskBuild = buildStep.StepAskBuild;
export type StepAskBuildArtifactsItem = buildStep.StepAskBuildArtifactsItem;
export type StepAskBuildToolchain = buildStep.StepAskBuildToolchain;
export type StepAskCheck = buildStep.StepAskCheck;
export type StepAskCompose = buildStep.StepAskCompose;
export type Toolchain = buildStep.Toolchain;
/** is the body of delivery. */
export type DeliveryAccept = StepAsk;
/** is the body of check. */
export type CheckAccept = StepAsk;
/** is the body of recheck. */
export type RecheckAccept = StepAsk;
/** is one value of the state steps under the key <node>.<id>. */
export type StepsByNodeIDValue = Step;
/** is one value of the state pauses under the key paused.<node>. */
export type PausesByPausedNodeValue = Pause;
/** is one value of the state pauses under the key capacity.<node>. */
export type PausesByCapacityNodeValue = Capacity;
/** is one value of the state toolchains under the key <node>.<language>. */
export type ToolchainsByNodeLanguageValue = Toolchain;
@@ -0,0 +1,232 @@
// Code generated by seatgen from the seat definitions; DO NOT EDIT.
// The part "build-step" several seats include whole: What the three build seats share: the verbs that read and steer a node's builds, and the layouts of the asks they accept and the steps they keep. A seat lists its states against these (a part carries no states).
export const verbs = {
current: "current",
pause: "pause",
resume: "resume",
} as const;
export interface BuildAnswerArtifactsItem {
"artifact": string;
"digest": string;
"reference"?: string;
}
export interface BuildAnswerToolchain {
"language": string;
"recipe": string;
"version": string;
}
export interface BuildAnswer {
"artifacts": BuildAnswerArtifactsItem[];
"imports"?: string[];
"out-of-step"?: string[];
"toolchain"?: BuildAnswerToolchain;
}
/** how many steps the node runs at once */
export interface Capacity {
/** when (RFC 3339 time) */
"at"?: string;
"build-hours"?: string;
"build-hours-fault"?: string;
"by-cpu"?: number;
"configured": number;
"configured-from"?: string;
"cores-per-step"?: number;
"effective": number;
"ineligible"?: string;
"outside-hours"?: boolean;
"quota-cores"?: number;
"quota-from"?: string;
/** the layout version */
"v"?: number;
"why": string;
}
export interface CheckAnswerLevelsItemDigestNeedsItem {
"needs"?: string[];
"package"?: string;
}
export interface CheckAnswerLevelsItemDigestPackagesItem {
"digest": string;
"package": string;
}
export interface CheckAnswerLevelsItemDigest {
"beside"?: string[];
"judged_by"?: string;
"level"?: string;
"needs"?: CheckAnswerLevelsItemDigestNeedsItem[];
"packages"?: CheckAnswerLevelsItemDigestPackagesItem[];
"without_tests"?: string[];
}
export interface CheckAnswerLevelsItemKeptItem {
"digest"?: string;
"package"?: string;
"tests"?: number;
}
export interface CheckAnswerLevelsItemUnmetItem {
"needs"?: string[];
"package"?: string;
}
export interface CheckAnswerLevelsItem {
"digest"?: CheckAnswerLevelsItemDigest;
"judged"?: string;
"kept"?: CheckAnswerLevelsItemKeptItem[];
"level": string;
"tests"?: unknown[];
"unmet"?: CheckAnswerLevelsItemUnmetItem[];
}
export interface CheckAnswer {
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch": unknown;
"levels"?: CheckAnswerLevelsItem[];
}
export interface ComposeAnswer {
"built": boolean;
"key"?: string;
/** the compose-candidate verdict */
"verdict"?: unknown;
}
/** whether the node takes no new ask */
export interface Pause {
/** when (RFC 3339 time) */
"at"?: string;
"by"?: string;
"paused": boolean;
/** the layout version */
"v"?: number;
}
/** one step a build module runs on a node */
export interface Step {
/** when (RFC 3339 time) */
"ended"?: string;
"id": string;
"node": string;
"owner"?: string;
"phase"?: string;
/** when (RFC 3339 time) */
"phase-at"?: string;
"reason"?: string;
/** what the step answered */
"result"?: unknown;
/** when (RFC 3339 time) */
"started": string;
/** running, passed, failed or refused */
"state": string;
"tool": string;
/** the layout version */
"v"?: number;
"what"?: string;
}
export interface StepAskBuildArtifactsItem {
"artifact": string;
"from"?: string;
"seat"?: string;
"version"?: string;
}
export interface StepAskBuildToolchain {
"language": string;
"recipe": string;
"version": string;
}
export interface StepAskBuild {
"artifacts": StepAskBuildArtifactsItem[];
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch"?: unknown;
"fp"?: string;
"module": string;
"path"?: string;
"publish"?: boolean;
"toolchain"?: StepAskBuildToolchain;
}
export interface StepAskCheck {
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch": unknown;
"kept"?: boolean;
"levels": string[];
"packages"?: string[];
"run"?: string;
"runner"?: string;
"runner_when"?: string;
}
export interface StepAskCompose {
"dir": string;
/** what the build module fetches: the repository, commit and directory, as the indexer states it */
"fetch": unknown;
"package": string;
"reader"?: string;
/** the compose-candidate request */
"request": unknown;
}
/** one ask of a build module */
export interface StepAsk {
"asker": string;
/** when (RFC 3339 time) */
"at"?: string;
"build"?: StepAskBuild;
"check"?: StepAskCheck;
"compose"?: StepAskCompose;
"id": string;
/** build, check or compose */
"kind": string;
/** go, typescript or image */
"language": string;
"needs"?: string[];
/** package to the tagged version a build pins */
"packages"?: Record<string, string>;
/** the layout version */
"v"?: number;
}
/** the toolchain a node reports */
export interface Toolchain {
/** when (RFC 3339 time) */
"at"?: string;
/** go or typescript */
"language": string;
"recipe": string;
/** the layout version */
"v"?: number;
"version": string;
}
/** is what current takes. */
export interface CurrentInput {
}
/** is what current answers. */
export type CurrentAnswer = Record<string, unknown>;
/** is what pause takes. */
export interface PauseInput {
}
/** is what pause answers. */
export type PauseAnswer = Record<string, unknown>;
/** is what resume takes. */
export interface ResumeInput {
}
/** is what resume answers. */
export type ResumeAnswer = Record<string, unknown>;
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": true,
"strict": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*.ts"]
}