CT12: the build seats' ask carries its version, every ask says ask-taken and step-ended (issue 1966)

The builder's reserved version reaches the build in the ask; a holder says when it takes and ends
any ask, a builder's build included, so the watchman times every ask; the toolchains key names its
program's digest; the checker may drop its own asks until its removal. step-progress and ask-taken
name no keep and go on the shared events stream. The delivery SDK's neutral forms follow the part.

Builds: design 47 G §472, §548, §549, §552, §573, §602, §603

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
2026-11-11 20:27:39 +01:00
parent c7ad2477f0
commit 7ecae5a6dd
34 changed files with 622 additions and 127 deletions
-3
View File
@@ -100,9 +100,6 @@ const StreamVersionDelivered = "SEAT_mesh-wants_version-delivered"
// SubjectVersionDelivered is where version-delivered is published.
const SubjectVersionDelivered = "mesh.seat.mesh-wants.event.version-delivered"
// StreamStepProgress is the stream step-progress is kept in.
const StreamStepProgress = "SEAT_mesh-wants_step-progress"
// SubjectStepProgress is where step-progress is published, on mesh.seat.mesh-wants.event.step-progress.<node>.
func SubjectStepProgress(node string) string {
return "mesh.seat.mesh-wants.event.step-progress." + node
+38 -11
View File
@@ -36,6 +36,7 @@ const (
EventStepEnded = "step-ended"
EventToolchainReported = "toolchain-reported"
EventStepProgress = "step-progress"
EventAskTaken = "ask-taken"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
@@ -45,7 +46,7 @@ func Verbs() []string {
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventStepEnded, EventToolchainReported, EventStepProgress}
return []string{EventStepEnded, EventToolchainReported, EventStepProgress, EventAskTaken}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
@@ -74,9 +75,6 @@ func SubjectToolchainReported(node string) string {
// SubjectToolchainReportedAll hears every toolchain-reported.
const SubjectToolchainReportedAll = "mesh.seat.node-build-go.event.toolchain-reported.*"
// StreamStepProgress is the stream step-progress is kept in.
const StreamStepProgress = "SEAT_node-build-go_step-progress"
// SubjectStepProgress is where step-progress is published, on mesh.seat.node-build-go.event.step-progress.<node>.
func SubjectStepProgress(node string) string {
return "mesh.seat.node-build-go.event.step-progress." + node
@@ -85,6 +83,12 @@ func SubjectStepProgress(node string) string {
// SubjectStepProgressAll hears every step-progress.
const SubjectStepProgressAll = "mesh.seat.node-build-go.event.step-progress.*"
// SubjectAskTaken is where ask-taken is published, on mesh.seat.node-build-go.event.ask-taken.<node>.
func SubjectAskTaken(node string) string { return "mesh.seat.node-build-go.event.ask-taken." + node }
// SubjectAskTakenAll hears every ask-taken.
const SubjectAskTakenAll = "mesh.seat.node-build-go.event.ask-taken.*"
// AcceptSubjectDelivery is where delivery is sent.
const AcceptSubjectDelivery = "mesh.seat.node-build-go.accept.delivery"
@@ -372,6 +376,16 @@ type AskArtifact struct {
Version string `json:"version,omitempty"`
}
// AskTaken is an ask a build seat's holder took, said when it takes any ask, whatever its asker (design 47 G section 602).
type AskTaken struct {
// the ask's id
Ask string `json:"ask"`
Asker string `json:"asker"`
At time.Time `json:"at"`
// the node that took it, as in the subject
Node string `json:"node"`
}
// BuildAnswer is a type of the contract.
type BuildAnswer struct {
Artifacts []BuiltArtifact `json:"artifacts"`
@@ -761,23 +775,31 @@ type StepAsk struct {
Step *StepRun `json:"step,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
// the version MAJOR.MINOR.PATCH the builder reserved for the build, passed to it as MESH_VERSION; empty for a build that reserves none, which stamps none (design 47 G section 573)
Version string `json:"version,omitempty"`
}
// StepEnded is a pipeline step's end, said by the build seat's holder on the node that ran it (ADR 0666 sections 7, 21): the runner takes it only from that holder's account, naming the ask, the commit and the fingerprint it was asked at.
// StepEnded is an ask's end, said by the build seat's holder on the node that ran it, whatever its asker (design 47 G section 602): a pipeline step's end names the pipeline, the commit and the fingerprint it was asked at, which the runner takes only from that holder's account (ADR 0666 sections 7, 21); the end of any other ask names its asker, the ask, the node, the outcome and when, and neither commit nor fingerprint (design 47 G section 548).
type StepEnded struct {
Artifact string `json:"artifact"`
Artifact string `json:"artifact,omitempty"`
// the ask's id, by which a reader takes only its own asks
Ask string `json:"ask"`
// who asked it
Asker string `json:"asker"`
// when it ended (RFC 3339 time)
At time.Time `json:"at"`
// for a rerun, the caller the runtime proved
By string `json:"by,omitempty"`
// the packages not run because the ask's kept results held them
Carried []KeptResult `json:"carried,omitempty"`
Commit string `json:"commit"`
Commit string `json:"commit,omitempty"`
Ended *time.Time `json:"ended,omitempty"`
Fingerprint string `json:"fingerprint"`
Fingerprint string `json:"fingerprint,omitempty"`
// the ask's id
ID string `json:"id"`
// the packages that passed at their digest, for the runner to keep
Kept []KeptResult `json:"kept,omitempty"`
Module string `json:"module"`
Module string `json:"module,omitempty"`
// the node that ran it, as in the subject
Node string `json:"node"`
// never passed for a step that ran nothing
@@ -786,12 +808,12 @@ type StepEnded struct {
Output string `json:"output,omitempty"`
// the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16)
OutputObject string `json:"output-object,omitempty"`
Pipeline string `json:"pipeline"`
Pipeline string `json:"pipeline,omitempty"`
Rerun bool `json:"rerun,omitempty"`
// why it failed or could not run, naming the part not heard
Said string `json:"said,omitempty"`
Started *time.Time `json:"started,omitempty"`
Step string `json:"step"`
Step string `json:"step,omitempty"`
Tests *TestCounts `json:"tests,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
@@ -912,6 +934,8 @@ type TestCounts struct {
type Toolchain struct {
// when (RFC 3339 time)
At *time.Time `json:"at,omitempty"`
// the sha256: digest of the language's toolchain program as the build module runs it: the program of the module that provides that language's toolchain, never the build module's own (design 47 G section 472)
Digest string `json:"digest,omitempty"`
// go or typescript
Language string `json:"language"`
Recipe string `json:"recipe"`
@@ -1067,6 +1091,9 @@ type ToolchainReportedEvent = ToolchainReported
// StepProgressEvent is the body of the event step-progress.
type StepProgressEvent = StepProgress
// AskTakenEvent is the body of the event ask-taken.
type AskTakenEvent = AskTaken
// StepsByAskerNodeIDValue is one value of the state steps under the key <asker>.<node>.<id>.
type StepsByAskerNodeIDValue = Step
@@ -17,14 +17,18 @@ func TestFixtures(t *testing.T) {
decode func([]byte) (any, error)
subjectIs *regexp.Regexp
}{
{name: "a unit step ended passed on its node, with its counts and what it carried", subject: "mesh.seat.node-build-go.event.step-ended.ace", given: "{\"artifact\":\"nats:program\",\"carried\":[{\"digest\":\"sha256:bbbb\",\"level\":\"unit\",\"package\":\"./modules/nats/a\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"kept\":[{\"digest\":\"sha256:cccc\",\"level\":\"unit\",\"package\":\"./modules/nats/b\"}],\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"unit\",\"tests\":{\"unit\":14},\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"carried\":[{\"digest\":\"sha256:bbbb\",\"level\":\"unit\",\"package\":\"./modules/nats/a\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"kept\":[{\"digest\":\"sha256:cccc\",\"level\":\"unit\",\"package\":\"./modules/nats/b\"}],\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"unit\",\"tests\":{\"unit\":14},\"v\":1}",
{name: "a unit step ended passed on its node, with its counts and what it carried", subject: "mesh.seat.node-build-go.event.step-ended.ace", given: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5e\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"carried\":[{\"digest\":\"sha256:bbbb\",\"level\":\"unit\",\"package\":\"./modules/nats/a\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"kept\":[{\"digest\":\"sha256:cccc\",\"level\":\"unit\",\"package\":\"./modules/nats/b\"}],\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"unit\",\"tests\":{\"unit\":14},\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5e\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"carried\":[{\"digest\":\"sha256:bbbb\",\"level\":\"unit\",\"package\":\"./modules/nats/a\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"kept\":[{\"digest\":\"sha256:cccc\",\"level\":\"unit\",\"package\":\"./modules/nats/b\"}],\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"unit\",\"tests\":{\"unit\":14},\"v\":1}",
decode: func(b []byte) (any, error) { var v StepEndedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-go\\.event\\.step-ended\\.[^.*> ]+$")},
{name: "an integration step that could not run, naming the part not heard", subject: "mesh.seat.node-build-go.event.step-ended.g14", given: "{\"artifact\":\"nats:program\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"integration\",\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"integration\",\"v\":1}",
{name: "an integration step that could not run, naming the part not heard", subject: "mesh.seat.node-build-go.event.step-ended.g14", given: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5f\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"integration\",\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5f\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"integration\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepEndedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-go\\.event\\.step-ended\\.[^.*> ]+$")},
{name: "a node's toolchain reported", subject: "mesh.seat.node-build-go.event.toolchain-reported.ace", given: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"language\":\"go\",\"node\":\"ace\",\"recipe\":\"1\",\"version\":\"1.26.0\"}", wire: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"language\":\"go\",\"node\":\"ace\",\"recipe\":\"1\",\"version\":\"1.26.0\"}",
decode: func(b []byte) (any, error) { var v ToolchainReportedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-go\\.event\\.toolchain-reported\\.[^.*> ]+$")},
{name: "a running ask says its progress", subject: "mesh.seat.node-build-go.event.step-progress.ace", given: "{\"ask\":\"a1b2\",\"asker\":\"runner\",\"at\":\"2026-11-11T10:01:00Z\",\"phase\":\"fetch\"}", wire: "{\"ask\":\"a1b2\",\"asker\":\"runner\",\"at\":\"2026-11-11T10:01:00Z\",\"phase\":\"fetch\"}",
decode: func(b []byte) (any, error) { var v StepProgressEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-go\\.event\\.step-progress\\.[^.*> ]+$")},
{name: "a builder's build ended, naming its asker and no commit or fingerprint (G 548)", subject: "mesh.seat.node-build-go.event.step-ended.ace", given: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:03:00Z\",\"id\":\"m2kx9a1b3c4d6a\",\"node\":\"ace\",\"outcome\":\"failed\",\"said\":\"the build failed\",\"v\":1}", wire: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:03:00Z\",\"id\":\"m2kx9a1b3c4d6a\",\"node\":\"ace\",\"outcome\":\"failed\",\"said\":\"the build failed\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepEndedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-go\\.event\\.step-ended\\.[^.*> ]+$")},
{name: "an ask taken, whatever its asker (G 602)", subject: "mesh.seat.node-build-go.event.ask-taken.ace", given: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:00:00Z\",\"node\":\"ace\"}", wire: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:00:00Z\",\"node\":\"ace\"}",
decode: func(b []byte) (any, error) { var v AskTakenEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-go\\.event\\.ask-taken\\.[^.*> ]+$")},
{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}",
@@ -45,8 +49,16 @@ func TestFixtures(t *testing.T) {
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a node's toolchain with its program's digest (G 472)", subject: "", given: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"language\":\"go\",\"recipe\":\"1\",\"v\":1,\"version\":\"1.26.0\"}", wire: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"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$")},
{name: "a build ask with the version the builder reserved (G 573)", subject: "mesh.seat.node-build-go.accept.delivery", given: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b3\",\"kind\":\"build\",\"language\":\"go\",\"version\":\"1.4.2\"}", wire: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b3\",\"kind\":\"build\",\"language\":\"go\",\"version\":\"1.4.2\"}",
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$")},
{name: "a check ask with its fetch, siblings and levels", subject: "mesh.seat.node-build-go.accept.check", given: "{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"beside\":[{\"commit\":\"fedcba9876543210fedcba9876543210fedcba98\",\"repository\":\"novox/mesh-sdk\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"packages\":{\"git.novox.be/novox/mesh-sdk/go\":\"fedcba9876543210fedcba9876543210fedcba98\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-catalog\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"],\"node-names\":[\"ace\",\"g14\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"2\",\"version\":\"1.26.0\"}},\"id\":\"c3d4\",\"kind\":\"check\",\"language\":\"go\",\"v\":1}", wire: "{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"beside\":[{\"commit\":\"fedcba9876543210fedcba9876543210fedcba98\",\"repository\":\"novox/mesh-sdk\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"packages\":{\"git.novox.be/novox/mesh-sdk/go\":\"fedcba9876543210fedcba9876543210fedcba98\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-catalog\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"],\"node-names\":[\"ace\",\"g14\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"2\",\"version\":\"1.26.0\"}},\"id\":\"c3d4\",\"kind\":\"check\",\"language\":\"go\",\"v\":1}",
decode: func(b []byte) (any, error) { var v CheckAccept; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-go\\.accept\\.check$")},
{name: "a finished build step with its artifacts", subject: "", given: "{\"ended\":\"2026-11-05T10:03:00Z\",\"id\":\"a1b2\",\"node\":\"ace\",\"result\":{\"artifacts\":[{\"artifact\":\"go\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"reference\":\"container-image-registry/nats/go@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}],\"imports\":[\"git.novox.be/novox/mesh-sdk/go\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"1\",\"version\":\"1.26.0\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"build\",\"v\":1}", wire: "{\"ended\":\"2026-11-05T10:03:00Z\",\"id\":\"a1b2\",\"node\":\"ace\",\"result\":{\"artifacts\":[{\"artifact\":\"go\",\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"reference\":\"container-image-registry/nats/go@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}],\"imports\":[\"git.novox.be/novox/mesh-sdk/go\"],\"toolchain\":{\"language\":\"go\",\"recipe\":\"1\",\"version\":\"1.26.0\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"build\",\"v\":1}",
+38 -11
View File
@@ -35,6 +35,7 @@ const (
EventStepEnded = "step-ended"
EventToolchainReported = "toolchain-reported"
EventStepProgress = "step-progress"
EventAskTaken = "ask-taken"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
@@ -44,7 +45,7 @@ func Verbs() []string {
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventStepEnded, EventToolchainReported, EventStepProgress}
return []string{EventStepEnded, EventToolchainReported, EventStepProgress, EventAskTaken}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
@@ -75,9 +76,6 @@ func SubjectToolchainReported(node string) string {
// SubjectToolchainReportedAll hears every toolchain-reported.
const SubjectToolchainReportedAll = "mesh.seat.node-build-image.event.toolchain-reported.*"
// StreamStepProgress is the stream step-progress is kept in.
const StreamStepProgress = "SEAT_node-build-image_step-progress"
// SubjectStepProgress is where step-progress is published, on mesh.seat.node-build-image.event.step-progress.<node>.
func SubjectStepProgress(node string) string {
return "mesh.seat.node-build-image.event.step-progress." + node
@@ -86,6 +84,12 @@ func SubjectStepProgress(node string) string {
// SubjectStepProgressAll hears every step-progress.
const SubjectStepProgressAll = "mesh.seat.node-build-image.event.step-progress.*"
// SubjectAskTaken is where ask-taken is published, on mesh.seat.node-build-image.event.ask-taken.<node>.
func SubjectAskTaken(node string) string { return "mesh.seat.node-build-image.event.ask-taken." + node }
// SubjectAskTakenAll hears every ask-taken.
const SubjectAskTakenAll = "mesh.seat.node-build-image.event.ask-taken.*"
// AcceptSubjectDelivery is where delivery is sent.
const AcceptSubjectDelivery = "mesh.seat.node-build-image.accept.delivery"
@@ -370,6 +374,16 @@ type AskArtifact struct {
Version string `json:"version,omitempty"`
}
// AskTaken is an ask a build seat's holder took, said when it takes any ask, whatever its asker (design 47 G section 602).
type AskTaken struct {
// the ask's id
Ask string `json:"ask"`
Asker string `json:"asker"`
At time.Time `json:"at"`
// the node that took it, as in the subject
Node string `json:"node"`
}
// BuildAnswer is a type of the contract.
type BuildAnswer struct {
Artifacts []BuiltArtifact `json:"artifacts"`
@@ -759,23 +773,31 @@ type StepAsk struct {
Step *StepRun `json:"step,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
// the version MAJOR.MINOR.PATCH the builder reserved for the build, passed to it as MESH_VERSION; empty for a build that reserves none, which stamps none (design 47 G section 573)
Version string `json:"version,omitempty"`
}
// StepEnded is a pipeline step's end, said by the build seat's holder on the node that ran it (ADR 0666 sections 7, 21): the runner takes it only from that holder's account, naming the ask, the commit and the fingerprint it was asked at.
// StepEnded is an ask's end, said by the build seat's holder on the node that ran it, whatever its asker (design 47 G section 602): a pipeline step's end names the pipeline, the commit and the fingerprint it was asked at, which the runner takes only from that holder's account (ADR 0666 sections 7, 21); the end of any other ask names its asker, the ask, the node, the outcome and when, and neither commit nor fingerprint (design 47 G section 548).
type StepEnded struct {
Artifact string `json:"artifact"`
Artifact string `json:"artifact,omitempty"`
// the ask's id, by which a reader takes only its own asks
Ask string `json:"ask"`
// who asked it
Asker string `json:"asker"`
// when it ended (RFC 3339 time)
At time.Time `json:"at"`
// for a rerun, the caller the runtime proved
By string `json:"by,omitempty"`
// the packages not run because the ask's kept results held them
Carried []KeptResult `json:"carried,omitempty"`
Commit string `json:"commit"`
Commit string `json:"commit,omitempty"`
Ended *time.Time `json:"ended,omitempty"`
Fingerprint string `json:"fingerprint"`
Fingerprint string `json:"fingerprint,omitempty"`
// the ask's id
ID string `json:"id"`
// the packages that passed at their digest, for the runner to keep
Kept []KeptResult `json:"kept,omitempty"`
Module string `json:"module"`
Module string `json:"module,omitempty"`
// the node that ran it, as in the subject
Node string `json:"node"`
// never passed for a step that ran nothing
@@ -784,12 +806,12 @@ type StepEnded struct {
Output string `json:"output,omitempty"`
// the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16)
OutputObject string `json:"output-object,omitempty"`
Pipeline string `json:"pipeline"`
Pipeline string `json:"pipeline,omitempty"`
Rerun bool `json:"rerun,omitempty"`
// why it failed or could not run, naming the part not heard
Said string `json:"said,omitempty"`
Started *time.Time `json:"started,omitempty"`
Step string `json:"step"`
Step string `json:"step,omitempty"`
Tests *TestCounts `json:"tests,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
@@ -910,6 +932,8 @@ type TestCounts struct {
type Toolchain struct {
// when (RFC 3339 time)
At *time.Time `json:"at,omitempty"`
// the sha256: digest of the language's toolchain program as the build module runs it: the program of the module that provides that language's toolchain, never the build module's own (design 47 G section 472)
Digest string `json:"digest,omitempty"`
// go or typescript
Language string `json:"language"`
Recipe string `json:"recipe"`
@@ -1062,6 +1086,9 @@ type ToolchainReportedEvent = ToolchainReported
// StepProgressEvent is the body of the event step-progress.
type StepProgressEvent = StepProgress
// AskTakenEvent is the body of the event ask-taken.
type AskTakenEvent = AskTaken
// StepsByAskerNodeIDValue is one value of the state steps under the key <asker>.<node>.<id>.
type StepsByAskerNodeIDValue = Step
@@ -17,14 +17,18 @@ func TestFixtures(t *testing.T) {
decode func([]byte) (any, error)
subjectIs *regexp.Regexp
}{
{name: "a lint step ended passed on its node", subject: "mesh.seat.node-build-image.event.step-ended.ace", given: "{\"artifact\":\"nats:program\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"lint\",\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"lint\",\"v\":1}",
{name: "a lint step ended passed on its node", subject: "mesh.seat.node-build-image.event.step-ended.ace", given: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5e\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"lint\",\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5e\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"lint\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepEndedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-image\\.event\\.step-ended\\.[^.*> ]+$")},
{name: "a lint step that could not run, naming the part not heard", subject: "mesh.seat.node-build-image.event.step-ended.g14", given: "{\"artifact\":\"nats:program\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"lint\",\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"lint\",\"v\":1}",
{name: "a lint step that could not run, naming the part not heard", subject: "mesh.seat.node-build-image.event.step-ended.g14", given: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5f\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"lint\",\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5f\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"lint\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepEndedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-image\\.event\\.step-ended\\.[^.*> ]+$")},
{name: "a node's toolchain reported", subject: "mesh.seat.node-build-image.event.toolchain-reported.ace", given: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"language\":\"go\",\"node\":\"ace\",\"recipe\":\"1\",\"version\":\"1.26.0\"}", wire: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"language\":\"go\",\"node\":\"ace\",\"recipe\":\"1\",\"version\":\"1.26.0\"}",
decode: func(b []byte) (any, error) { var v ToolchainReportedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-image\\.event\\.toolchain-reported\\.[^.*> ]+$")},
{name: "a running ask says its progress", subject: "mesh.seat.node-build-image.event.step-progress.ace", given: "{\"ask\":\"a1b2\",\"asker\":\"runner\",\"at\":\"2026-11-11T10:01:00Z\",\"phase\":\"fetch\"}", wire: "{\"ask\":\"a1b2\",\"asker\":\"runner\",\"at\":\"2026-11-11T10:01:00Z\",\"phase\":\"fetch\"}",
decode: func(b []byte) (any, error) { var v StepProgressEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-image\\.event\\.step-progress\\.[^.*> ]+$")},
{name: "a builder's build ended, naming its asker and no commit or fingerprint (G 548)", subject: "mesh.seat.node-build-image.event.step-ended.ace", given: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:03:00Z\",\"id\":\"m2kx9a1b3c4d6a\",\"node\":\"ace\",\"outcome\":\"failed\",\"said\":\"the build failed\",\"v\":1}", wire: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:03:00Z\",\"id\":\"m2kx9a1b3c4d6a\",\"node\":\"ace\",\"outcome\":\"failed\",\"said\":\"the build failed\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepEndedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-image\\.event\\.step-ended\\.[^.*> ]+$")},
{name: "an ask taken, whatever its asker (G 602)", subject: "mesh.seat.node-build-image.event.ask-taken.ace", given: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:00:00Z\",\"node\":\"ace\"}", wire: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:00:00Z\",\"node\":\"ace\"}",
decode: func(b []byte) (any, error) { var v AskTakenEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-image\\.event\\.ask-taken\\.[^.*> ]+$")},
{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}",
@@ -45,8 +49,16 @@ func TestFixtures(t *testing.T) {
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a node's toolchain with its program's digest (G 472)", subject: "", given: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"language\":\"go\",\"recipe\":\"1\",\"v\":1,\"version\":\"1.26.0\"}", wire: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"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$")},
{name: "a build ask with the version the builder reserved (G 573)", subject: "mesh.seat.node-build-image.accept.delivery", given: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b3\",\"kind\":\"build\",\"language\":\"go\",\"version\":\"1.4.2\"}", wire: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b3\",\"kind\":\"build\",\"language\":\"go\",\"version\":\"1.4.2\"}",
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$")},
{name: "a step ended on a transport fault, given again by the bus", subject: "", given: "{\"again-at\":\"2026-11-05T10:01:30Z\",\"ended\":\"2026-11-05T10:00:30Z\",\"id\":\"a1b2\",\"node\":\"ace\",\"passing\":true,\"reason\":\"fetching the commit: kex_exchange_identification: read: Connection reset by peer\",\"run\":1,\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"again\",\"tool\":\"build\",\"v\":1}", wire: "{\"again-at\":\"2026-11-05T10:01:30Z\",\"ended\":\"2026-11-05T10:00:30Z\",\"id\":\"a1b2\",\"node\":\"ace\",\"passing\":true,\"reason\":\"fetching the commit: kex_exchange_identification: read: Connection reset by peer\",\"run\":1,\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"again\",\"tool\":\"build\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepsByNodeIDValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil},
{name: "an ask dropped by the caller that no longer waits", subject: "", given: "{\"at\":\"2026-11-05T10:00:00Z\",\"by\":\"mesh-delivery-builder\",\"v\":1,\"why\":\"a newer fingerprint supersedes it\"}", wire: "{\"at\":\"2026-11-05T10:00:00Z\",\"by\":\"mesh-delivery-builder\",\"v\":1,\"why\":\"a newer fingerprint supersedes it\"}",
+38 -11
View File
@@ -35,6 +35,7 @@ const (
EventStepEnded = "step-ended"
EventToolchainReported = "toolchain-reported"
EventStepProgress = "step-progress"
EventAskTaken = "ask-taken"
)
// Verbs is every verb the seat serves, in its definition's order: a new copy each call.
@@ -44,7 +45,7 @@ func Verbs() []string {
// Events is every event published on the seat's subject: a new copy each call.
func Events() []string {
return []string{EventStepEnded, EventToolchainReported, EventStepProgress}
return []string{EventStepEnded, EventToolchainReported, EventStepProgress, EventAskTaken}
}
// Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects.
@@ -75,9 +76,6 @@ func SubjectToolchainReported(node string) string {
// SubjectToolchainReportedAll hears every toolchain-reported.
const SubjectToolchainReportedAll = "mesh.seat.node-build-node.event.toolchain-reported.*"
// StreamStepProgress is the stream step-progress is kept in.
const StreamStepProgress = "SEAT_node-build-node_step-progress"
// SubjectStepProgress is where step-progress is published, on mesh.seat.node-build-node.event.step-progress.<node>.
func SubjectStepProgress(node string) string {
return "mesh.seat.node-build-node.event.step-progress." + node
@@ -86,6 +84,12 @@ func SubjectStepProgress(node string) string {
// SubjectStepProgressAll hears every step-progress.
const SubjectStepProgressAll = "mesh.seat.node-build-node.event.step-progress.*"
// SubjectAskTaken is where ask-taken is published, on mesh.seat.node-build-node.event.ask-taken.<node>.
func SubjectAskTaken(node string) string { return "mesh.seat.node-build-node.event.ask-taken." + node }
// SubjectAskTakenAll hears every ask-taken.
const SubjectAskTakenAll = "mesh.seat.node-build-node.event.ask-taken.*"
// AcceptSubjectDelivery is where delivery is sent.
const AcceptSubjectDelivery = "mesh.seat.node-build-node.accept.delivery"
@@ -370,6 +374,16 @@ type AskArtifact struct {
Version string `json:"version,omitempty"`
}
// AskTaken is an ask a build seat's holder took, said when it takes any ask, whatever its asker (design 47 G section 602).
type AskTaken struct {
// the ask's id
Ask string `json:"ask"`
Asker string `json:"asker"`
At time.Time `json:"at"`
// the node that took it, as in the subject
Node string `json:"node"`
}
// BuildAnswer is a type of the contract.
type BuildAnswer struct {
Artifacts []BuiltArtifact `json:"artifacts"`
@@ -759,23 +773,31 @@ type StepAsk struct {
Step *StepRun `json:"step,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
// the version MAJOR.MINOR.PATCH the builder reserved for the build, passed to it as MESH_VERSION; empty for a build that reserves none, which stamps none (design 47 G section 573)
Version string `json:"version,omitempty"`
}
// StepEnded is a pipeline step's end, said by the build seat's holder on the node that ran it (ADR 0666 sections 7, 21): the runner takes it only from that holder's account, naming the ask, the commit and the fingerprint it was asked at.
// StepEnded is an ask's end, said by the build seat's holder on the node that ran it, whatever its asker (design 47 G section 602): a pipeline step's end names the pipeline, the commit and the fingerprint it was asked at, which the runner takes only from that holder's account (ADR 0666 sections 7, 21); the end of any other ask names its asker, the ask, the node, the outcome and when, and neither commit nor fingerprint (design 47 G section 548).
type StepEnded struct {
Artifact string `json:"artifact"`
Artifact string `json:"artifact,omitempty"`
// the ask's id, by which a reader takes only its own asks
Ask string `json:"ask"`
// who asked it
Asker string `json:"asker"`
// when it ended (RFC 3339 time)
At time.Time `json:"at"`
// for a rerun, the caller the runtime proved
By string `json:"by,omitempty"`
// the packages not run because the ask's kept results held them
Carried []KeptResult `json:"carried,omitempty"`
Commit string `json:"commit"`
Commit string `json:"commit,omitempty"`
Ended *time.Time `json:"ended,omitempty"`
Fingerprint string `json:"fingerprint"`
Fingerprint string `json:"fingerprint,omitempty"`
// the ask's id
ID string `json:"id"`
// the packages that passed at their digest, for the runner to keep
Kept []KeptResult `json:"kept,omitempty"`
Module string `json:"module"`
Module string `json:"module,omitempty"`
// the node that ran it, as in the subject
Node string `json:"node"`
// never passed for a step that ran nothing
@@ -784,12 +806,12 @@ type StepEnded struct {
Output string `json:"output,omitempty"`
// the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16)
OutputObject string `json:"output-object,omitempty"`
Pipeline string `json:"pipeline"`
Pipeline string `json:"pipeline,omitempty"`
Rerun bool `json:"rerun,omitempty"`
// why it failed or could not run, naming the part not heard
Said string `json:"said,omitempty"`
Started *time.Time `json:"started,omitempty"`
Step string `json:"step"`
Step string `json:"step,omitempty"`
Tests *TestCounts `json:"tests,omitempty"`
// the layout version
V int64 `json:"v,omitempty"`
@@ -910,6 +932,8 @@ type TestCounts struct {
type Toolchain struct {
// when (RFC 3339 time)
At *time.Time `json:"at,omitempty"`
// the sha256: digest of the language's toolchain program as the build module runs it: the program of the module that provides that language's toolchain, never the build module's own (design 47 G section 472)
Digest string `json:"digest,omitempty"`
// go or typescript
Language string `json:"language"`
Recipe string `json:"recipe"`
@@ -1062,6 +1086,9 @@ type ToolchainReportedEvent = ToolchainReported
// StepProgressEvent is the body of the event step-progress.
type StepProgressEvent = StepProgress
// AskTakenEvent is the body of the event ask-taken.
type AskTakenEvent = AskTaken
// StepsByAskerNodeIDValue is one value of the state steps under the key <asker>.<node>.<id>.
type StepsByAskerNodeIDValue = Step
@@ -17,14 +17,18 @@ func TestFixtures(t *testing.T) {
decode func([]byte) (any, error)
subjectIs *regexp.Regexp
}{
{name: "a unit step ended passed on its node, with its counts and what it carried", subject: "mesh.seat.node-build-node.event.step-ended.ace", given: "{\"artifact\":\"nats:program\",\"carried\":[{\"digest\":\"sha256:bbbb\",\"level\":\"unit\",\"package\":\"./modules/nats/a\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"kept\":[{\"digest\":\"sha256:cccc\",\"level\":\"unit\",\"package\":\"./modules/nats/b\"}],\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"unit\",\"tests\":{\"unit\":14},\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"carried\":[{\"digest\":\"sha256:bbbb\",\"level\":\"unit\",\"package\":\"./modules/nats/a\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"kept\":[{\"digest\":\"sha256:cccc\",\"level\":\"unit\",\"package\":\"./modules/nats/b\"}],\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"unit\",\"tests\":{\"unit\":14},\"v\":1}",
{name: "a unit step ended passed on its node, with its counts and what it carried", subject: "mesh.seat.node-build-node.event.step-ended.ace", given: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5e\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"carried\":[{\"digest\":\"sha256:bbbb\",\"level\":\"unit\",\"package\":\"./modules/nats/a\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"kept\":[{\"digest\":\"sha256:cccc\",\"level\":\"unit\",\"package\":\"./modules/nats/b\"}],\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"unit\",\"tests\":{\"unit\":14},\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5e\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"carried\":[{\"digest\":\"sha256:bbbb\",\"level\":\"unit\",\"package\":\"./modules/nats/a\"}],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"ended\":\"2026-11-10T10:02:00Z\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5e\",\"kept\":[{\"digest\":\"sha256:cccc\",\"level\":\"unit\",\"package\":\"./modules/nats/b\"}],\"module\":\"nats\",\"node\":\"ace\",\"outcome\":\"passed\",\"pipeline\":\"main.12.nats\",\"started\":\"2026-11-10T10:00:00Z\",\"step\":\"unit\",\"tests\":{\"unit\":14},\"v\":1}",
decode: func(b []byte) (any, error) { var v StepEndedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-node\\.event\\.step-ended\\.[^.*> ]+$")},
{name: "an integration step that could not run, naming the part not heard", subject: "mesh.seat.node-build-node.event.step-ended.g14", given: "{\"artifact\":\"nats:program\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"integration\",\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"integration\",\"v\":1}",
{name: "an integration step that could not run, naming the part not heard", subject: "mesh.seat.node-build-node.event.step-ended.g14", given: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5f\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"integration\",\"v\":1}", wire: "{\"artifact\":\"nats:program\",\"ask\":\"m2kx9a1b3c4d5f\",\"asker\":\"mesh-delivery-pipeline\",\"at\":\"2026-11-10T10:02:00Z\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"fingerprint\":\"fp-0123\",\"id\":\"m2kx9a1b3c4d5f\",\"module\":\"nats\",\"node\":\"g14\",\"outcome\":\"could not run\",\"output-object\":\"mesh-build-go_sent-objects/m2kx9a1b3c4d5f\",\"pipeline\":\"main.12.nats\",\"said\":\"the sandbox could not fetch novox/mesh-sdk\",\"step\":\"integration\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepEndedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-node\\.event\\.step-ended\\.[^.*> ]+$")},
{name: "a node's toolchain reported", subject: "mesh.seat.node-build-node.event.toolchain-reported.ace", given: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"language\":\"go\",\"node\":\"ace\",\"recipe\":\"1\",\"version\":\"1.26.0\"}", wire: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"language\":\"go\",\"node\":\"ace\",\"recipe\":\"1\",\"version\":\"1.26.0\"}",
decode: func(b []byte) (any, error) { var v ToolchainReportedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-node\\.event\\.toolchain-reported\\.[^.*> ]+$")},
{name: "a running ask says its progress", subject: "mesh.seat.node-build-node.event.step-progress.ace", given: "{\"ask\":\"a1b2\",\"asker\":\"runner\",\"at\":\"2026-11-11T10:01:00Z\",\"phase\":\"fetch\"}", wire: "{\"ask\":\"a1b2\",\"asker\":\"runner\",\"at\":\"2026-11-11T10:01:00Z\",\"phase\":\"fetch\"}",
decode: func(b []byte) (any, error) { var v StepProgressEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-node\\.event\\.step-progress\\.[^.*> ]+$")},
{name: "a builder's build ended, naming its asker and no commit or fingerprint (G 548)", subject: "mesh.seat.node-build-node.event.step-ended.ace", given: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:03:00Z\",\"id\":\"m2kx9a1b3c4d6a\",\"node\":\"ace\",\"outcome\":\"failed\",\"said\":\"the build failed\",\"v\":1}", wire: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:03:00Z\",\"id\":\"m2kx9a1b3c4d6a\",\"node\":\"ace\",\"outcome\":\"failed\",\"said\":\"the build failed\",\"v\":1}",
decode: func(b []byte) (any, error) { var v StepEndedEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-node\\.event\\.step-ended\\.[^.*> ]+$")},
{name: "an ask taken, whatever its asker (G 602)", subject: "mesh.seat.node-build-node.event.ask-taken.ace", given: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:00:00Z\",\"node\":\"ace\"}", wire: "{\"ask\":\"m2kx9a1b3c4d6a\",\"asker\":\"mesh-delivery-builder\",\"at\":\"2026-11-11T10:00:00Z\",\"node\":\"ace\"}",
decode: func(b []byte) (any, error) { var v AskTakenEvent; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-node\\.event\\.ask-taken\\.[^.*> ]+$")},
{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}",
@@ -45,8 +49,16 @@ func TestFixtures(t *testing.T) {
err := json.Unmarshal(b, &v)
return v, err
}, subjectIs: nil},
{name: "a node's toolchain with its program's digest (G 472)", subject: "", given: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"language\":\"go\",\"recipe\":\"1\",\"v\":1,\"version\":\"1.26.0\"}", wire: "{\"digest\":\"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"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$")},
{name: "a build ask with the version the builder reserved (G 573)", subject: "mesh.seat.node-build-node.accept.delivery", given: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b3\",\"kind\":\"build\",\"language\":\"go\",\"version\":\"1.4.2\"}", wire: "{\"asker\":\"mesh-delivery-builder\",\"build\":{\"artifacts\":[{\"artifact\":\"go\"}],\"module\":\"nats\"},\"id\":\"a1b3\",\"kind\":\"build\",\"language\":\"go\",\"version\":\"1.4.2\"}",
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$")},
{name: "a check ask with the group's tagged package", subject: "mesh.seat.node-build-node.accept.check", given: "{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"package\":{\"name\":\"@novox/mesh-sdk\",\"version\":\"0.1.15-feat-x.1\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-delivery\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"],\"node-names\":[\"ace\",\"g14\"],\"toolchain\":{\"language\":\"typescript\",\"recipe\":\"1\",\"version\":\"26.12.0\"}},\"id\":\"c3d5\",\"kind\":\"check\",\"language\":\"typescript\",\"v\":1}", wire: "{\"asker\":\"mesh-delivery-checker\",\"at\":\"2026-11-05T10:00:00Z\",\"check\":{\"fetch\":{\"base\":\"89abcdef0123456789abcdef0123456789abcdef\",\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"package\":{\"name\":\"@novox/mesh-sdk\",\"version\":\"0.1.15-feat-x.1\"},\"ref\":\"refs/pull/7/head\",\"repository\":\"novox/mesh-delivery\"},\"kept\":true,\"levels\":[\"unit\",\"integration\"],\"node-names\":[\"ace\",\"g14\"],\"toolchain\":{\"language\":\"typescript\",\"recipe\":\"1\",\"version\":\"26.12.0\"}},\"id\":\"c3d5\",\"kind\":\"check\",\"language\":\"typescript\",\"v\":1}",
decode: func(b []byte) (any, error) { var v CheckAccept; err := json.Unmarshal(b, &v); return v, err }, subjectIs: regexp.MustCompile("^mesh\\.seat\\.node-build-node\\.accept\\.check$")},
{name: "a finished check step of a TypeScript merge preview", subject: "", given: "{\"ended\":\"2026-11-05T10:01:00Z\",\"id\":\"c3d6\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"changed\":[\"modules/m/package.json\"],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"merge\":\"0123456789abcdef0123456789abcdef01234567\",\"modules\":[\"modules/m\"],\"trees\":{\"modules/m\":{\"manifest\":\"0581b699d9d05517e69b21f5cedbeb2eee8aba2b205280b561be731594d7feef\",\"tree\":\"0123456789abcdef0123456789abcdef01234567\"}},\"workspace\":\"mvii1sxt979f67\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}", wire: "{\"ended\":\"2026-11-05T10:01:00Z\",\"id\":\"c3d6\",\"node\":\"ace\",\"result\":{\"fetch\":{\"base\":\"abcdef0123456789abcdef0123456789abcdef01\",\"changed\":[\"modules/m/package.json\"],\"commit\":\"0123456789abcdef0123456789abcdef01234567\",\"merge\":\"0123456789abcdef0123456789abcdef01234567\",\"modules\":[\"modules/m\"],\"trees\":{\"modules/m\":{\"manifest\":\"0581b699d9d05517e69b21f5cedbeb2eee8aba2b205280b561be731594d7feef\",\"tree\":\"0123456789abcdef0123456789abcdef01234567\"}},\"workspace\":\"mvii1sxt979f67\"}},\"started\":\"2026-11-05T10:00:00Z\",\"state\":\"passed\",\"tool\":\"check\",\"v\":1}",
+62 -13
View File
@@ -44,7 +44,8 @@
"description": "End an ask this node holds for a caller that no longer waits for it: a step not yet running is ended dropped when the bus gives it, one running is cancelled; both end the step dropped, naming who dropped it and why. Writes dropped.<id> in the pauses state; the build module removes the key when it has acted.",
"callers": [
"seat:mesh-pipeline-runner",
"seat:mesh-builds"
"seat:mesh-builds",
"seat:mesh-delivery-checker"
],
"input": {
"type": "object",
@@ -261,6 +262,10 @@
"description": "when (RFC 3339 time)",
"format": "date-time"
},
"version": {
"type": "string",
"description": "the version MAJOR.MINOR.PATCH the builder reserved for the build, passed to it as MESH_VERSION; empty for a build that reserves none, which stamps none (design 47 G section 573)"
},
"build": {
"type": "object",
"properties": {
@@ -682,6 +687,10 @@
"type": "string",
"description": "when (RFC 3339 time)",
"format": "date-time"
},
"digest": {
"type": "string",
"description": "the sha256: digest of the language's toolchain program as the build module runs it: the program of the module that provides that language's toolchain, never the build module's own (design 47 G section 472)"
}
},
"required": [
@@ -1508,7 +1517,7 @@
},
"StepEnded": {
"type": "object",
"description": "a pipeline step's end, said by the build seat's holder on the node that ran it (ADR 0666 sections 7, 21): the runner takes it only from that holder's account, naming the ask, the commit and the fingerprint it was asked at",
"description": "an ask's end, said by the build seat's holder on the node that ran it, whatever its asker (design 47 G section 602): a pipeline step's end names the pipeline, the commit and the fingerprint it was asked at, which the runner takes only from that holder's account (ADR 0666 sections 7, 21); the end of any other ask names its asker, the ask, the node, the outcome and when, and neither commit nor fingerprint (design 47 G section 548)",
"properties": {
"v": {
"type": "integer",
@@ -1518,6 +1527,14 @@
"type": "string",
"description": "the ask's id"
},
"asker": {
"type": "string",
"description": "who asked it"
},
"ask": {
"type": "string",
"description": "the ask's id, by which a reader takes only its own asks"
},
"pipeline": {
"type": "string"
},
@@ -1598,18 +1615,20 @@
"ended": {
"type": "string",
"format": "date-time"
},
"at": {
"type": "string",
"description": "when it ended (RFC 3339 time)",
"format": "date-time"
}
},
"required": [
"id",
"pipeline",
"step",
"module",
"artifact",
"commit",
"fingerprint",
"asker",
"ask",
"node",
"outcome"
"outcome",
"at"
]
},
"DetectedStep": {
@@ -1721,6 +1740,33 @@
"phase",
"at"
]
},
"AskTaken": {
"type": "object",
"description": "an ask a build seat's holder took, said when it takes any ask, whatever its asker (design 47 G section 602)",
"properties": {
"asker": {
"type": "string"
},
"ask": {
"type": "string",
"description": "the ask's id"
},
"node": {
"type": "string",
"description": "the node that took it, as in the subject"
},
"at": {
"type": "string",
"format": "date-time"
}
},
"required": [
"asker",
"ask",
"node",
"at"
]
}
},
"events": [
@@ -1751,10 +1797,13 @@
"subject": "step-progress.<node>",
"body": {
"$ref": "#/defs/StepProgress"
},
"keep": {
"max-age-days": 1,
"max-mib": 16
}
},
{
"name": "ask-taken",
"subject": "ask-taken.<node>",
"body": {
"$ref": "#/defs/AskTaken"
}
}
]
-4
View File
@@ -431,10 +431,6 @@
{
"name": "step-progress",
"subject": "step-progress.<node>",
"keep": {
"max-age-days": 1,
"max-mib": 16
},
"body": {
"type": "object",
"description": "a composition step's progress, said once a minute while the assigner runs it (design 47 G section 496)",
@@ -6,6 +6,8 @@
"given": {
"v": 1,
"id": "m2kx9a1b3c4d5e",
"asker": "mesh-delivery-pipeline",
"ask": "m2kx9a1b3c4d5e",
"pipeline": "main.12.nats",
"step": "unit",
"module": "nats",
@@ -32,7 +34,8 @@
}
],
"started": "2026-11-10T10:00:00Z",
"ended": "2026-11-10T10:02:00Z"
"ended": "2026-11-10T10:02:00Z",
"at": "2026-11-10T10:02:00Z"
}
},
{
@@ -42,6 +45,8 @@
"given": {
"v": 1,
"id": "m2kx9a1b3c4d5f",
"asker": "mesh-delivery-pipeline",
"ask": "m2kx9a1b3c4d5f",
"pipeline": "main.12.nats",
"step": "integration",
"module": "nats",
@@ -51,7 +56,8 @@
"node": "g14",
"outcome": "could not run",
"said": "the sandbox could not fetch novox/mesh-sdk",
"output-object": "mesh-build-go_sent-objects/m2kx9a1b3c4d5f"
"output-object": "mesh-build-go_sent-objects/m2kx9a1b3c4d5f",
"at": "2026-11-10T10:02:00Z"
}
},
{
@@ -76,5 +82,31 @@
"phase": "fetch",
"at": "2026-11-11T10:01:00Z"
}
},
{
"name": "a builder's build ended, naming its asker and no commit or fingerprint (G 548)",
"of": "event:step-ended",
"subject": "mesh.seat.node-build-go.event.step-ended.ace",
"given": {
"v": 1,
"id": "m2kx9a1b3c4d6a",
"asker": "mesh-delivery-builder",
"ask": "m2kx9a1b3c4d6a",
"node": "ace",
"outcome": "failed",
"said": "the build failed",
"at": "2026-11-11T10:03:00Z"
}
},
{
"name": "an ask taken, whatever its asker (G 602)",
"of": "event:ask-taken",
"subject": "mesh.seat.node-build-go.event.ask-taken.ace",
"given": {
"asker": "mesh-delivery-builder",
"ask": "m2kx9a1b3c4d6a",
"node": "ace",
"at": "2026-11-11T10:00:00Z"
}
}
]
@@ -41,6 +41,17 @@
"recipe": "1"
}
},
{
"name": "a node's toolchain with its program's digest (G 472)",
"of": "state:toolchains/<node>.<language>",
"given": {
"v": 1,
"language": "go",
"version": "1.26.0",
"recipe": "1",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
},
{
"name": "a build ask",
"of": "accept:delivery",
@@ -60,6 +71,26 @@
}
}
},
{
"name": "a build ask with the version the builder reserved (G 573)",
"of": "accept:delivery",
"subject": "mesh.seat.node-build-go.accept.delivery",
"given": {
"id": "a1b3",
"kind": "build",
"language": "go",
"asker": "mesh-delivery-builder",
"version": "1.4.2",
"build": {
"module": "nats",
"artifacts": [
{
"artifact": "go"
}
]
}
}
},
{
"name": "a check ask with its fetch, siblings and levels",
"of": "accept:check",
@@ -6,6 +6,8 @@
"given": {
"v": 1,
"id": "m2kx9a1b3c4d5e",
"asker": "mesh-delivery-pipeline",
"ask": "m2kx9a1b3c4d5e",
"pipeline": "main.12.nats",
"step": "lint",
"module": "nats",
@@ -15,7 +17,8 @@
"node": "ace",
"outcome": "passed",
"started": "2026-11-10T10:00:00Z",
"ended": "2026-11-10T10:02:00Z"
"ended": "2026-11-10T10:02:00Z",
"at": "2026-11-10T10:02:00Z"
}
},
{
@@ -25,6 +28,8 @@
"given": {
"v": 1,
"id": "m2kx9a1b3c4d5f",
"asker": "mesh-delivery-pipeline",
"ask": "m2kx9a1b3c4d5f",
"pipeline": "main.12.nats",
"step": "lint",
"module": "nats",
@@ -34,7 +39,8 @@
"node": "g14",
"outcome": "could not run",
"said": "the sandbox could not fetch novox/mesh-sdk",
"output-object": "mesh-build-go_sent-objects/m2kx9a1b3c4d5f"
"output-object": "mesh-build-go_sent-objects/m2kx9a1b3c4d5f",
"at": "2026-11-10T10:02:00Z"
}
},
{
@@ -59,5 +65,31 @@
"phase": "fetch",
"at": "2026-11-11T10:01:00Z"
}
},
{
"name": "a builder's build ended, naming its asker and no commit or fingerprint (G 548)",
"of": "event:step-ended",
"subject": "mesh.seat.node-build-image.event.step-ended.ace",
"given": {
"v": 1,
"id": "m2kx9a1b3c4d6a",
"asker": "mesh-delivery-builder",
"ask": "m2kx9a1b3c4d6a",
"node": "ace",
"outcome": "failed",
"said": "the build failed",
"at": "2026-11-11T10:03:00Z"
}
},
{
"name": "an ask taken, whatever its asker (G 602)",
"of": "event:ask-taken",
"subject": "mesh.seat.node-build-image.event.ask-taken.ace",
"given": {
"asker": "mesh-delivery-builder",
"ask": "m2kx9a1b3c4d6a",
"node": "ace",
"at": "2026-11-11T10:00:00Z"
}
}
]
@@ -41,6 +41,17 @@
"recipe": "1"
}
},
{
"name": "a node's toolchain with its program's digest (G 472)",
"of": "state:toolchains/<node>.<language>",
"given": {
"v": 1,
"language": "go",
"version": "1.26.0",
"recipe": "1",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
},
{
"name": "a build ask",
"of": "accept:delivery",
@@ -60,6 +71,26 @@
}
}
},
{
"name": "a build ask with the version the builder reserved (G 573)",
"of": "accept:delivery",
"subject": "mesh.seat.node-build-image.accept.delivery",
"given": {
"id": "a1b3",
"kind": "build",
"language": "go",
"asker": "mesh-delivery-builder",
"version": "1.4.2",
"build": {
"module": "nats",
"artifacts": [
{
"artifact": "go"
}
]
}
}
},
{
"name": "a step ended on a transport fault, given again by the bus",
"of": "state:steps/<node>.<id>",
@@ -6,6 +6,8 @@
"given": {
"v": 1,
"id": "m2kx9a1b3c4d5e",
"asker": "mesh-delivery-pipeline",
"ask": "m2kx9a1b3c4d5e",
"pipeline": "main.12.nats",
"step": "unit",
"module": "nats",
@@ -32,7 +34,8 @@
}
],
"started": "2026-11-10T10:00:00Z",
"ended": "2026-11-10T10:02:00Z"
"ended": "2026-11-10T10:02:00Z",
"at": "2026-11-10T10:02:00Z"
}
},
{
@@ -42,6 +45,8 @@
"given": {
"v": 1,
"id": "m2kx9a1b3c4d5f",
"asker": "mesh-delivery-pipeline",
"ask": "m2kx9a1b3c4d5f",
"pipeline": "main.12.nats",
"step": "integration",
"module": "nats",
@@ -51,7 +56,8 @@
"node": "g14",
"outcome": "could not run",
"said": "the sandbox could not fetch novox/mesh-sdk",
"output-object": "mesh-build-go_sent-objects/m2kx9a1b3c4d5f"
"output-object": "mesh-build-go_sent-objects/m2kx9a1b3c4d5f",
"at": "2026-11-10T10:02:00Z"
}
},
{
@@ -76,5 +82,31 @@
"phase": "fetch",
"at": "2026-11-11T10:01:00Z"
}
},
{
"name": "a builder's build ended, naming its asker and no commit or fingerprint (G 548)",
"of": "event:step-ended",
"subject": "mesh.seat.node-build-node.event.step-ended.ace",
"given": {
"v": 1,
"id": "m2kx9a1b3c4d6a",
"asker": "mesh-delivery-builder",
"ask": "m2kx9a1b3c4d6a",
"node": "ace",
"outcome": "failed",
"said": "the build failed",
"at": "2026-11-11T10:03:00Z"
}
},
{
"name": "an ask taken, whatever its asker (G 602)",
"of": "event:ask-taken",
"subject": "mesh.seat.node-build-node.event.ask-taken.ace",
"given": {
"asker": "mesh-delivery-builder",
"ask": "m2kx9a1b3c4d6a",
"node": "ace",
"at": "2026-11-11T10:00:00Z"
}
}
]
@@ -41,6 +41,17 @@
"recipe": "1"
}
},
{
"name": "a node's toolchain with its program's digest (G 472)",
"of": "state:toolchains/<node>.<language>",
"given": {
"v": 1,
"language": "go",
"version": "1.26.0",
"recipe": "1",
"digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
},
{
"name": "a build ask",
"of": "accept:delivery",
@@ -60,6 +71,26 @@
}
}
},
{
"name": "a build ask with the version the builder reserved (G 573)",
"of": "accept:delivery",
"subject": "mesh.seat.node-build-node.accept.delivery",
"given": {
"id": "a1b3",
"kind": "build",
"language": "go",
"asker": "mesh-delivery-builder",
"version": "1.4.2",
"build": {
"module": "nats",
"artifacts": [
{
"artifact": "go"
}
]
}
}
},
{
"name": "a check ask with the group's tagged package",
"of": "accept:check",
-2
View File
@@ -62,8 +62,6 @@ export declare const versionDeliveredStream: "SEAT_mesh-wants_version-delivered"
export declare const versionDeliveredSubject: "mesh.seat.mesh-wants.event.version-delivered";
export declare const stepProgressStream: "SEAT_mesh-wants_step-progress";
export declare function stepProgressSubject(node: string): string;
export declare const stepProgressSubjectAll: "mesh.seat.mesh-wants.event.step-progress.*";
-2
View File
@@ -64,8 +64,6 @@ export const versionDeliveredStream = "SEAT_mesh-wants_version-delivered";
export const versionDeliveredSubject = "mesh.seat.mesh-wants.event.version-delivered";
export const stepProgressStream = "SEAT_mesh-wants_step-progress";
export function stepProgressSubject(node) {
return "mesh.seat.mesh-wants.event.step-progress." + node;
}
+7 -2
View File
@@ -28,6 +28,7 @@ export declare const events: {
readonly stepEnded: "step-ended";
readonly toolchainReported: "toolchain-reported";
readonly stepProgress: "step-progress";
readonly askTaken: "ask-taken";
};
export declare const family: { readonly name: "node-build-go.events"; readonly maxAgeDays: 7 };
@@ -44,12 +45,14 @@ export declare function toolchainReportedSubject(node: string): string;
export declare const toolchainReportedSubjectAll: "mesh.seat.node-build-go.event.toolchain-reported.*";
export declare const stepProgressStream: "SEAT_node-build-go_step-progress";
export declare function stepProgressSubject(node: string): string;
export declare const stepProgressSubjectAll: "mesh.seat.node-build-go.event.step-progress.*";
export declare function askTakenSubject(node: string): string;
export declare const askTakenSubjectAll: "mesh.seat.node-build-go.event.ask-taken.*";
export declare const deliverySubject: "mesh.seat.node-build-go.accept.delivery";
export declare const checkSubject: "mesh.seat.node-build-go.accept.check";
@@ -112,6 +115,8 @@ export declare function detectedStepsByModuleArtifactKey(module: string, artifac
export declare function parseDetectedStepsByModuleArtifactKey(_key: string): { module: string; artifact: string } | undefined;
export type AskArtifact = buildStep.AskArtifact;
export type AskTaken = buildStep.AskTaken;
export type AskTakenEvent = buildStep.AskTakenEvent;
export type BuildAnswer = buildStep.BuildAnswer;
export type BuiltArtifact = buildStep.BuiltArtifact;
export type BuiltArtifactResolvedItem = buildStep.BuiltArtifactResolvedItem;
+7 -2
View File
@@ -26,6 +26,7 @@ export const events = {
stepEnded: "step-ended",
toolchainReported: "toolchain-reported",
stepProgress: "step-progress",
askTaken: "ask-taken",
};
export const family = { name: "node-build-go.events", maxAgeDays: 7 };
@@ -46,14 +47,18 @@ export function toolchainReportedSubject(node) {
export const toolchainReportedSubjectAll = "mesh.seat.node-build-go.event.toolchain-reported.*";
export const stepProgressStream = "SEAT_node-build-go_step-progress";
export function stepProgressSubject(node) {
return "mesh.seat.node-build-go.event.step-progress." + node;
}
export const stepProgressSubjectAll = "mesh.seat.node-build-go.event.step-progress.*";
export function askTakenSubject(node) {
return "mesh.seat.node-build-go.event.ask-taken." + node;
}
export const askTakenSubjectAll = "mesh.seat.node-build-go.event.ask-taken.*";
export const deliverySubject = "mesh.seat.node-build-go.accept.delivery";
export const checkSubject = "mesh.seat.node-build-go.accept.check";
+31 -7
View File
@@ -15,6 +15,7 @@ export declare const events: {
readonly stepEnded: "step-ended";
readonly toolchainReported: "toolchain-reported";
readonly stepProgress: "step-progress";
readonly askTaken: "ask-taken";
};
/** one artifact of a build ask: built from the fetched tree, or copied from an upstream pin */
@@ -25,6 +26,16 @@ export interface AskArtifact {
"version"?: string;
}
/** an ask a build seat's holder took, said when it takes any ask, whatever its asker (design 47 G section 602) */
export interface AskTaken {
/** the ask's id */
"ask": string;
"asker": string;
"at": string;
/** the node that took it, as in the subject */
"node": string;
}
export interface BuildAnswer {
"artifacts": BuiltArtifact[];
"imports"?: string[];
@@ -392,23 +403,31 @@ export interface StepAsk {
"step"?: StepRun;
/** the layout version */
"v"?: number;
/** the version MAJOR.MINOR.PATCH the builder reserved for the build, passed to it as MESH_VERSION; empty for a build that reserves none, which stamps none (design 47 G section 573) */
"version"?: string;
}
/** a pipeline step's end, said by the build seat's holder on the node that ran it (ADR 0666 sections 7, 21): the runner takes it only from that holder's account, naming the ask, the commit and the fingerprint it was asked at */
/** an ask's end, said by the build seat's holder on the node that ran it, whatever its asker (design 47 G section 602): a pipeline step's end names the pipeline, the commit and the fingerprint it was asked at, which the runner takes only from that holder's account (ADR 0666 sections 7, 21); the end of any other ask names its asker, the ask, the node, the outcome and when, and neither commit nor fingerprint (design 47 G section 548) */
export interface StepEnded {
"artifact": string;
"artifact"?: string;
/** the ask's id, by which a reader takes only its own asks */
"ask": string;
/** who asked it */
"asker": string;
/** when it ended (RFC 3339 time) */
"at": string;
/** for a rerun, the caller the runtime proved */
"by"?: string;
/** the packages not run because the ask's kept results held them */
"carried"?: KeptResult[];
"commit": string;
"commit"?: string;
"ended"?: string;
"fingerprint": string;
"fingerprint"?: string;
/** the ask's id */
"id": string;
/** the packages that passed at their digest, for the runner to keep */
"kept"?: KeptResult[];
"module": string;
"module"?: string;
/** the node that ran it, as in the subject */
"node": string;
/** never passed for a step that ran nothing */
@@ -417,12 +436,12 @@ export interface StepEnded {
"output"?: string;
/** the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16) */
"output-object"?: string;
"pipeline": string;
"pipeline"?: string;
"rerun"?: boolean;
/** why it failed or could not run, naming the part not heard */
"said"?: string;
"started"?: string;
"step": "lint" | "unit" | "integration";
"step"?: "lint" | "unit" | "integration";
"tests"?: TestCounts;
/** the layout version */
"v"?: number;
@@ -513,6 +532,8 @@ export interface TestCounts {
export interface Toolchain {
/** when (RFC 3339 time) */
"at"?: string;
/** the sha256: digest of the language's toolchain program as the build module runs it: the program of the module that provides that language's toolchain, never the build module's own (design 47 G section 472) */
"digest"?: string;
/** go or typescript */
"language": string;
"recipe": string;
@@ -643,3 +664,6 @@ export type ToolchainReportedEvent = ToolchainReported;
/** is the body of the event step-progress. */
export type StepProgressEvent = StepProgress;
/** is the body of the event ask-taken. */
export type AskTakenEvent = AskTaken;
@@ -15,6 +15,7 @@ export const events = {
stepEnded: "step-ended",
toolchainReported: "toolchain-reported",
stepProgress: "step-progress",
askTaken: "ask-taken",
};
export {};
+7 -2
View File
@@ -27,6 +27,7 @@ export declare const events: {
readonly stepEnded: "step-ended";
readonly toolchainReported: "toolchain-reported";
readonly stepProgress: "step-progress";
readonly askTaken: "ask-taken";
};
export declare const family: { readonly name: "node-build-image.events"; readonly maxAgeDays: 7 };
@@ -43,12 +44,14 @@ export declare function toolchainReportedSubject(node: string): string;
export declare const toolchainReportedSubjectAll: "mesh.seat.node-build-image.event.toolchain-reported.*";
export declare const stepProgressStream: "SEAT_node-build-image_step-progress";
export declare function stepProgressSubject(node: string): string;
export declare const stepProgressSubjectAll: "mesh.seat.node-build-image.event.step-progress.*";
export declare function askTakenSubject(node: string): string;
export declare const askTakenSubjectAll: "mesh.seat.node-build-image.event.ask-taken.*";
export declare const deliverySubject: "mesh.seat.node-build-image.accept.delivery";
export declare const checkSubject: "mesh.seat.node-build-image.accept.check";
@@ -109,6 +112,8 @@ export declare function detectedStepsByModuleArtifactKey(module: string, artifac
export declare function parseDetectedStepsByModuleArtifactKey(_key: string): { module: string; artifact: string } | undefined;
export type AskArtifact = buildStep.AskArtifact;
export type AskTaken = buildStep.AskTaken;
export type AskTakenEvent = buildStep.AskTakenEvent;
export type BuildAnswer = buildStep.BuildAnswer;
export type BuiltArtifact = buildStep.BuiltArtifact;
export type BuiltArtifactResolvedItem = buildStep.BuiltArtifactResolvedItem;
+7 -2
View File
@@ -25,6 +25,7 @@ export const events = {
stepEnded: "step-ended",
toolchainReported: "toolchain-reported",
stepProgress: "step-progress",
askTaken: "ask-taken",
};
export const family = { name: "node-build-image.events", maxAgeDays: 7 };
@@ -45,14 +46,18 @@ export function toolchainReportedSubject(node) {
export const toolchainReportedSubjectAll = "mesh.seat.node-build-image.event.toolchain-reported.*";
export const stepProgressStream = "SEAT_node-build-image_step-progress";
export function stepProgressSubject(node) {
return "mesh.seat.node-build-image.event.step-progress." + node;
}
export const stepProgressSubjectAll = "mesh.seat.node-build-image.event.step-progress.*";
export function askTakenSubject(node) {
return "mesh.seat.node-build-image.event.ask-taken." + node;
}
export const askTakenSubjectAll = "mesh.seat.node-build-image.event.ask-taken.*";
export const deliverySubject = "mesh.seat.node-build-image.accept.delivery";
export const checkSubject = "mesh.seat.node-build-image.accept.check";
+31 -7
View File
@@ -15,6 +15,7 @@ export declare const events: {
readonly stepEnded: "step-ended";
readonly toolchainReported: "toolchain-reported";
readonly stepProgress: "step-progress";
readonly askTaken: "ask-taken";
};
/** one artifact of a build ask: built from the fetched tree, or copied from an upstream pin */
@@ -25,6 +26,16 @@ export interface AskArtifact {
"version"?: string;
}
/** an ask a build seat's holder took, said when it takes any ask, whatever its asker (design 47 G section 602) */
export interface AskTaken {
/** the ask's id */
"ask": string;
"asker": string;
"at": string;
/** the node that took it, as in the subject */
"node": string;
}
export interface BuildAnswer {
"artifacts": BuiltArtifact[];
"imports"?: string[];
@@ -392,23 +403,31 @@ export interface StepAsk {
"step"?: StepRun;
/** the layout version */
"v"?: number;
/** the version MAJOR.MINOR.PATCH the builder reserved for the build, passed to it as MESH_VERSION; empty for a build that reserves none, which stamps none (design 47 G section 573) */
"version"?: string;
}
/** a pipeline step's end, said by the build seat's holder on the node that ran it (ADR 0666 sections 7, 21): the runner takes it only from that holder's account, naming the ask, the commit and the fingerprint it was asked at */
/** an ask's end, said by the build seat's holder on the node that ran it, whatever its asker (design 47 G section 602): a pipeline step's end names the pipeline, the commit and the fingerprint it was asked at, which the runner takes only from that holder's account (ADR 0666 sections 7, 21); the end of any other ask names its asker, the ask, the node, the outcome and when, and neither commit nor fingerprint (design 47 G section 548) */
export interface StepEnded {
"artifact": string;
"artifact"?: string;
/** the ask's id, by which a reader takes only its own asks */
"ask": string;
/** who asked it */
"asker": string;
/** when it ended (RFC 3339 time) */
"at": string;
/** for a rerun, the caller the runtime proved */
"by"?: string;
/** the packages not run because the ask's kept results held them */
"carried"?: KeptResult[];
"commit": string;
"commit"?: string;
"ended"?: string;
"fingerprint": string;
"fingerprint"?: string;
/** the ask's id */
"id": string;
/** the packages that passed at their digest, for the runner to keep */
"kept"?: KeptResult[];
"module": string;
"module"?: string;
/** the node that ran it, as in the subject */
"node": string;
/** never passed for a step that ran nothing */
@@ -417,12 +436,12 @@ export interface StepEnded {
"output"?: string;
/** the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16) */
"output-object"?: string;
"pipeline": string;
"pipeline"?: string;
"rerun"?: boolean;
/** why it failed or could not run, naming the part not heard */
"said"?: string;
"started"?: string;
"step": "lint" | "unit" | "integration";
"step"?: "lint" | "unit" | "integration";
"tests"?: TestCounts;
/** the layout version */
"v"?: number;
@@ -513,6 +532,8 @@ export interface TestCounts {
export interface Toolchain {
/** when (RFC 3339 time) */
"at"?: string;
/** the sha256: digest of the language's toolchain program as the build module runs it: the program of the module that provides that language's toolchain, never the build module's own (design 47 G section 472) */
"digest"?: string;
/** go or typescript */
"language": string;
"recipe": string;
@@ -643,3 +664,6 @@ export type ToolchainReportedEvent = ToolchainReported;
/** is the body of the event step-progress. */
export type StepProgressEvent = StepProgress;
/** is the body of the event ask-taken. */
export type AskTakenEvent = AskTaken;
@@ -15,6 +15,7 @@ export const events = {
stepEnded: "step-ended",
toolchainReported: "toolchain-reported",
stepProgress: "step-progress",
askTaken: "ask-taken",
};
export {};
+7 -2
View File
@@ -27,6 +27,7 @@ export declare const events: {
readonly stepEnded: "step-ended";
readonly toolchainReported: "toolchain-reported";
readonly stepProgress: "step-progress";
readonly askTaken: "ask-taken";
};
export declare const family: { readonly name: "node-build-node.events"; readonly maxAgeDays: 7 };
@@ -43,12 +44,14 @@ export declare function toolchainReportedSubject(node: string): string;
export declare const toolchainReportedSubjectAll: "mesh.seat.node-build-node.event.toolchain-reported.*";
export declare const stepProgressStream: "SEAT_node-build-node_step-progress";
export declare function stepProgressSubject(node: string): string;
export declare const stepProgressSubjectAll: "mesh.seat.node-build-node.event.step-progress.*";
export declare function askTakenSubject(node: string): string;
export declare const askTakenSubjectAll: "mesh.seat.node-build-node.event.ask-taken.*";
export declare const deliverySubject: "mesh.seat.node-build-node.accept.delivery";
export declare const checkSubject: "mesh.seat.node-build-node.accept.check";
@@ -109,6 +112,8 @@ export declare function detectedStepsByModuleArtifactKey(module: string, artifac
export declare function parseDetectedStepsByModuleArtifactKey(_key: string): { module: string; artifact: string } | undefined;
export type AskArtifact = buildStep.AskArtifact;
export type AskTaken = buildStep.AskTaken;
export type AskTakenEvent = buildStep.AskTakenEvent;
export type BuildAnswer = buildStep.BuildAnswer;
export type BuiltArtifact = buildStep.BuiltArtifact;
export type BuiltArtifactResolvedItem = buildStep.BuiltArtifactResolvedItem;
+7 -2
View File
@@ -25,6 +25,7 @@ export const events = {
stepEnded: "step-ended",
toolchainReported: "toolchain-reported",
stepProgress: "step-progress",
askTaken: "ask-taken",
};
export const family = { name: "node-build-node.events", maxAgeDays: 7 };
@@ -45,14 +46,18 @@ export function toolchainReportedSubject(node) {
export const toolchainReportedSubjectAll = "mesh.seat.node-build-node.event.toolchain-reported.*";
export const stepProgressStream = "SEAT_node-build-node_step-progress";
export function stepProgressSubject(node) {
return "mesh.seat.node-build-node.event.step-progress." + node;
}
export const stepProgressSubjectAll = "mesh.seat.node-build-node.event.step-progress.*";
export function askTakenSubject(node) {
return "mesh.seat.node-build-node.event.ask-taken." + node;
}
export const askTakenSubjectAll = "mesh.seat.node-build-node.event.ask-taken.*";
export const deliverySubject = "mesh.seat.node-build-node.accept.delivery";
export const checkSubject = "mesh.seat.node-build-node.accept.check";
+31 -7
View File
@@ -15,6 +15,7 @@ export declare const events: {
readonly stepEnded: "step-ended";
readonly toolchainReported: "toolchain-reported";
readonly stepProgress: "step-progress";
readonly askTaken: "ask-taken";
};
/** one artifact of a build ask: built from the fetched tree, or copied from an upstream pin */
@@ -25,6 +26,16 @@ export interface AskArtifact {
"version"?: string;
}
/** an ask a build seat's holder took, said when it takes any ask, whatever its asker (design 47 G section 602) */
export interface AskTaken {
/** the ask's id */
"ask": string;
"asker": string;
"at": string;
/** the node that took it, as in the subject */
"node": string;
}
export interface BuildAnswer {
"artifacts": BuiltArtifact[];
"imports"?: string[];
@@ -392,23 +403,31 @@ export interface StepAsk {
"step"?: StepRun;
/** the layout version */
"v"?: number;
/** the version MAJOR.MINOR.PATCH the builder reserved for the build, passed to it as MESH_VERSION; empty for a build that reserves none, which stamps none (design 47 G section 573) */
"version"?: string;
}
/** a pipeline step's end, said by the build seat's holder on the node that ran it (ADR 0666 sections 7, 21): the runner takes it only from that holder's account, naming the ask, the commit and the fingerprint it was asked at */
/** an ask's end, said by the build seat's holder on the node that ran it, whatever its asker (design 47 G section 602): a pipeline step's end names the pipeline, the commit and the fingerprint it was asked at, which the runner takes only from that holder's account (ADR 0666 sections 7, 21); the end of any other ask names its asker, the ask, the node, the outcome and when, and neither commit nor fingerprint (design 47 G section 548) */
export interface StepEnded {
"artifact": string;
"artifact"?: string;
/** the ask's id, by which a reader takes only its own asks */
"ask": string;
/** who asked it */
"asker": string;
/** when it ended (RFC 3339 time) */
"at": string;
/** for a rerun, the caller the runtime proved */
"by"?: string;
/** the packages not run because the ask's kept results held them */
"carried"?: KeptResult[];
"commit": string;
"commit"?: string;
"ended"?: string;
"fingerprint": string;
"fingerprint"?: string;
/** the ask's id */
"id": string;
/** the packages that passed at their digest, for the runner to keep */
"kept"?: KeptResult[];
"module": string;
"module"?: string;
/** the node that ran it, as in the subject */
"node": string;
/** never passed for a step that ran nothing */
@@ -417,12 +436,12 @@ export interface StepEnded {
"output"?: string;
/** the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16) */
"output-object"?: string;
"pipeline": string;
"pipeline"?: string;
"rerun"?: boolean;
/** why it failed or could not run, naming the part not heard */
"said"?: string;
"started"?: string;
"step": "lint" | "unit" | "integration";
"step"?: "lint" | "unit" | "integration";
"tests"?: TestCounts;
/** the layout version */
"v"?: number;
@@ -513,6 +532,8 @@ export interface TestCounts {
export interface Toolchain {
/** when (RFC 3339 time) */
"at"?: string;
/** the sha256: digest of the language's toolchain program as the build module runs it: the program of the module that provides that language's toolchain, never the build module's own (design 47 G section 472) */
"digest"?: string;
/** go or typescript */
"language": string;
"recipe": string;
@@ -643,3 +664,6 @@ export type ToolchainReportedEvent = ToolchainReported;
/** is the body of the event step-progress. */
export type StepProgressEvent = StepProgress;
/** is the body of the event ask-taken. */
export type AskTakenEvent = AskTaken;
@@ -15,6 +15,7 @@ export const events = {
stepEnded: "step-ended",
toolchainReported: "toolchain-reported",
stepProgress: "step-progress",
askTaken: "ask-taken",
};
export {};
+12 -9
View File
@@ -204,15 +204,18 @@ func AskStepWatch(askID string) (string, error) {
// StepAsk is one ask of a build module: the part's `StepAsk`.
type StepAsk struct {
V int `json:"v"`
ID string `json:"id"`
Kind string `json:"kind"`
Language string `json:"language"`
Asker string `json:"asker"`
At time.Time `json:"at,omitzero"`
Build *BuildJob `json:"build,omitempty"`
Check *CheckJob `json:"check,omitempty"`
Compose *ComposeJob `json:"compose,omitempty"`
V int `json:"v"`
ID string `json:"id"`
Kind string `json:"kind"`
Language string `json:"language"`
Asker string `json:"asker"`
At time.Time `json:"at,omitzero"`
// Version is the version MAJOR.MINOR.PATCH the builder reserved for the build, which the build module passes as
// MESH_VERSION; empty for a build that reserves none, which stamps none (design 47 G §573).
Version string `json:"version,omitempty"`
Build *BuildJob `json:"build,omitempty"`
Check *CheckJob `json:"check,omitempty"`
Compose *ComposeJob `json:"compose,omitempty"`
// Run is a run ask's job (run.go): a program built from a change and run over the heads, on the Go seat's check
// stream alone, as a compose.
Run *RunJob `json:"run,omitempty"`
+22 -1
View File
@@ -300,9 +300,30 @@ func TestAskSubjectsStreamsAndKeys(t *testing.T) {
t.Fatal(err)
}
goSubj, _ := StepEndedSubject(AskGo, "ace")
if back, err := DecodeStepEnded(goSubj, raw); err != nil || back.Fingerprint != "fp-0123" || back.Tests.Unit != 14 {
if back, err := DecodeStepEnded(goSubj, raw); err != nil || back.Fingerprint != "fp-0123" || back.Tests.Unit != 14 ||
back.Asker != stepAsk().Asker || back.Ask != testAskID {
t.Errorf("round trip: %+v %v", back, err)
}
// 1966/CT12 (G §548, §602): the end of an ask outside a pipeline names its asker, the ask and when, never a commit.
at := time.Date(2026, 11, 11, 10, 3, 0, 0, time.UTC)
build := StepEnded{ID: testAskID, Asker: "mesh-delivery-builder", Ask: testAskID, Node: "ace", Outcome: OutcomePassed, At: at}
if raw, err := EncodeStepEnded(build); err != nil || strings.Contains(string(raw), "commit") {
t.Errorf("a builder's build end: %s %v", raw, err)
} else if back, err := DecodeStepEnded(goSubj, raw); err != nil || back.Asker != "mesh-delivery-builder" || !back.At.Equal(at) {
t.Errorf("a builder's build end reads back as %+v %v", back, err)
}
for name, bad := range map[string]func(*StepEnded){
"no asker": func(e *StepEnded) { e.Asker = "" },
"no time": func(e *StepEnded) { e.At = time.Time{} },
"a commit": func(e *StepEnded) { e.Commit = "0123456789abcdef0123456789abcdef01234567" },
"a fingerprint": func(e *StepEnded) { e.Fingerprint = "fp-0123" },
} {
e := build
bad(&e)
if _, err := EncodeStepEnded(e); err == nil {
t.Errorf("an end outside a pipeline with %s is said", name)
}
}
g14, _ := StepEndedSubject(AskGo, "g14")
if _, err := DecodeStepEnded(g14, raw); err == nil || !strings.Contains(err.Error(), "said on g14's subject") {
t.Errorf("an end said on another node's subject: %v", err)
+27 -8
View File
@@ -106,16 +106,20 @@ func (r StepRun) check(id string) error {
return nil
}
// StepEnded is a pipeline step's end, said by the build seat's holder on the node that ran it.
// StepEnded is an ask's end, said by the build seat's holder on the node that ran it, whatever its asker (design 47 G
// §602): a pipeline step's end names its pipeline, step, module, artifact, commit and fingerprint; the end of any other
// ask names its asker, the ask, the node, the outcome and when, and neither commit nor fingerprint (G §548).
type StepEnded struct {
V int `json:"v"`
ID string `json:"id"`
Pipeline string `json:"pipeline"`
Step string `json:"step"`
Module string `json:"module"`
Artifact string `json:"artifact"`
Commit string `json:"commit"`
Fingerprint string `json:"fingerprint"`
Asker string `json:"asker"`
Ask string `json:"ask"`
Pipeline string `json:"pipeline,omitempty"`
Step string `json:"step,omitempty"`
Module string `json:"module,omitempty"`
Artifact string `json:"artifact,omitempty"`
Commit string `json:"commit,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
Node string `json:"node"`
Outcome string `json:"outcome"`
Tests *TestCounts `json:"tests,omitempty"`
@@ -128,6 +132,7 @@ type StepEnded struct {
By string `json:"by,omitempty"`
Started time.Time `json:"started,omitzero"`
Ended time.Time `json:"ended,omitzero"`
At time.Time `json:"at,omitzero"`
}
// EndOf is the end of the step a holds, on node, with outcome: the ask's names copied, so the runner can match the ask,
@@ -137,7 +142,7 @@ func EndOf(a StepAsk, node, outcome string) (StepEnded, error) {
return StepEnded{}, fmt.Errorf("buildstep: the ask %s is no pipeline step", a.ID)
}
s := a.Step
e := StepEnded{V: StepEndedVersion, ID: a.ID, Pipeline: s.Pipeline, Step: s.Step, Module: s.Module, Artifact: s.Artifact,
e := StepEnded{V: StepEndedVersion, ID: a.ID, Asker: a.Asker, Ask: a.ID, Pipeline: s.Pipeline, Step: s.Step, Module: s.Module, Artifact: s.Artifact,
Commit: s.Commit, Fingerprint: s.Fingerprint, Node: node, Outcome: outcome, Rerun: s.Rerun, By: s.By}
return e, e.check()
}
@@ -149,6 +154,20 @@ func (e StepEnded) check() error {
if err := checkNode(e.Node); err != nil {
return err
}
if e.Pipeline == "" {
// G §548, §602: the end of an ask outside a pipeline names its asker, the ask and when, and no commit or
// fingerprint.
if !slices.Contains(StepOutcomes, e.Outcome) {
return fmt.Errorf("buildstep: the end of %s says %q, not one of %s", e.ID, e.Outcome, strings.Join(StepOutcomes, ", "))
}
if e.Asker == "" || e.Ask == "" || e.At.IsZero() {
return fmt.Errorf("buildstep: the end of %s, an ask outside a pipeline, names no asker, ask or time", e.ID)
}
if e.Commit != "" || e.Fingerprint != "" {
return fmt.Errorf("buildstep: the end of %s names a commit or a fingerprint and no pipeline", e.ID)
}
return nil
}
if !slices.Contains(PipelineSteps, e.Step) {
return fmt.Errorf("buildstep: the end of %s names the step %q", e.ID, e.Step)
}
+8 -5
View File
@@ -16,11 +16,14 @@ const ToolchainVersion = 1
// the part build-step's `Toolchain`, the layout every node-build seat gives that state; the three build modules share
// this neutral form (a seat's generated type is one package per seat). A test reads each seat's fixture strictly into it.
type Toolchain struct {
V int `json:"v,omitempty"`
Language string `json:"language"`
Version string `json:"version"`
Recipe string `json:"recipe"`
At time.Time `json:"at,omitzero"`
V int `json:"v,omitempty"`
Language string `json:"language"`
Version string `json:"version"`
Recipe string `json:"recipe"`
// Digest is the sha256: digest of the language's toolchain program as the build module runs it, the program of the
// module that provides that language's toolchain, never the build module's own (design 47 G §472).
Digest string `json:"digest,omitempty"`
At time.Time `json:"at,omitzero"`
}
func checkToolchainLanguage(language string) error {
+2 -2
View File
@@ -44,8 +44,8 @@ func TestTheToolchainsValueAndKeyAreTheSeatsLayout(t *testing.T) {
read++
}
}
if read != 3 {
t.Errorf("%d toolchain fixtures read, want 3", read)
if read != 6 { // 1966/CT12 (G §472): each seat's fixture with its program's digest too
t.Errorf("%d toolchain fixtures read, want 6", read)
}
raw, err := EncodeToolchain(Toolchain{Language: "go", Version: "go1.27.1", Recipe: "3", At: time.Date(2026, 11, 5, 10, 0, 0, 0, time.UTC)})
if err != nil {