diff --git a/contracts/parts/build-step.json b/contracts/parts/build-step.json index b92efdb3..872d1435 100644 --- a/contracts/parts/build-step.json +++ b/contracts/parts/build-step.json @@ -42,7 +42,10 @@ { "name": "drop", "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. in the pauses state; the build module removes the key when it has acted.", - "callers": "the build seats' asker (the builder and the checker)", + "callers": [ + "seat:mesh-pipeline-runner", + "seat:mesh-builds" + ], "input": { "type": "object", "properties": { @@ -67,7 +70,153 @@ "answer": { "type": "object", "description": "whether the ask was held here" - } + }, + "class": "act" + }, + { + "name": "kept-artifact", + "description": "The one build this node keeps instead of storing it through the seat oci-artifact-registry: the new build of that seat's holder, when the running holder refused or did not answer the store (design 47 *The artifact store's holder takes its own new build even when its seat is the one broken*). Answers where the bytes are, as an object by their digest on the bus (the old objects form, ADR 0619 \u00a72), never in the answer; the node-engine checks what it fetched against the digest and applies nothing that differs. A module that claims no oci-artifact-registry is refused by name, so a store outage never becomes a delivery from build nodes; so is a build this node no longer keeps, or keeps under another digest.", + "input": { + "type": "object", + "properties": { + "module": { + "type": "string", + "description": "the module, the holder of oci-artifact-registry", + "minLength": 1 + }, + "fp": { + "type": "string", + "description": "its build's fingerprint", + "minLength": 1 + }, + "digest": { + "type": "string", + "description": "the artifact's sha256, 64 lowercase hex digits, as the builder's done key names it", + "pattern": "^[0-9a-f]{64}$" + } + }, + "required": [ + "module", + "fp", + "digest" + ] + }, + "answer": { + "type": "object", + "properties": { + "module": { + "type": "string", + "description": "the module asked" + }, + "fp": { + "type": "string", + "description": "the fingerprint asked" + }, + "digest": { + "type": "string", + "description": "the digest of the bytes kept", + "pattern": "^[0-9a-f]{64}$" + }, + "size": { + "type": "integer", + "description": "bytes" + }, + "store": { + "type": "string", + "description": "the object store the bytes are in, the build module's kept builds, as its manifest's objects names it on the bus" + }, + "object": { + "type": "string", + "description": "the object's name in it: the digest" + }, + "refused": { + "type": "string", + "enum": [ + "claims no oci-artifact-registry", + "not kept", + "digest differs" + ], + "description": "why nothing is answered: the module claims no oci-artifact-registry, this node keeps no build of it at that fingerprint (never kept, or swept), or keeps it under another digest" + }, + "words": { + "type": "string", + "description": "the refusal in words, naming the module" + }, + "error": { + "type": "string", + "description": "why it could not answer" + } + }, + "required": [ + "module", + "fp" + ] + }, + "callers": [ + "seat:node-engine" + ], + "class": "read" + }, + { + "name": "steps", + "description": "Which pipeline steps an artifact can run, found by its language's convention (design 47 *Pipeline steps and the policy*): lint always, unit and integration tests where its packages hold them. Kept by the artifact's fingerprint; again finds them anew.", + "callers": [ + "seat:mesh-pipeline-runner", + "seat:mesh-catalog" + ], + "input": { + "type": "object", + "properties": { + "module": { + "type": "string" + }, + "artifact": { + "type": "string", + "description": "the artifact reference, :" + }, + "fingerprint": { + "type": "string" + }, + "fetch": { + "$ref": "#/defs/Fetch" + }, + "again": { + "type": "boolean", + "description": "find them anew, not from the kept answer" + } + }, + "required": [ + "module", + "artifact", + "fetch" + ] + }, + "answer": { + "type": "object", + "properties": { + "artifact": { + "type": "string" + }, + "fingerprint": { + "type": "string" + }, + "steps": { + "type": "array", + "items": { + "$ref": "#/defs/DetectedStep" + } + }, + "kept": { + "type": "boolean", + "description": "answered from the kept answer" + } + }, + "required": [ + "artifact", + "steps" + ] + }, + "class": "act" } ], "defs": { @@ -83,7 +232,7 @@ }, "kind": { "type": "string", - "description": "build, check or compose" + "description": "build, check, compose or step" }, "language": { "type": "string", @@ -220,6 +369,10 @@ "type": "string" }, "description": "package to the tagged version a build pins" + }, + "step": { + "$ref": "#/defs/StepRun", + "description": "a pipeline step: lint, unit tests or integration tests of one artifact at one commit, sent by the runner as the accepted kind step (design 47 *The steps and who serves them*)" } }, "required": [ @@ -253,6 +406,10 @@ "items": { "type": "string" } + }, + "kept": { + "type": "string", + "description": "the digest of the artifact this node kept for the artifact store's holder instead of storing it through the seat oci-artifact-registry (the verb kept-artifact serves it); the keeping node is the step's own; absent when every artifact was stored" } }, "required": [ @@ -665,11 +822,21 @@ "type": "object", "description": "the TypeScript module's group package: the group's tagged version of the SDK ({name, version}), placed from the registry in each member whatever its lock names, or the group's package member ({repository, commit, ref}), packed by the fetch and served to the members in place of the registry's", "properties": { - "name": { "type": "string" }, - "version": { "type": "string" }, - "repository": { "type": "string" }, - "commit": { "type": "string" }, - "ref": { "type": "string" } + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "commit": { + "type": "string" + }, + "ref": { + "type": "string" + } } }, "beside": { @@ -872,7 +1039,7 @@ }, "StepResult": { "type": "object", - "description": "what a step answered, by the kind of ask: a build's artifacts, toolchain, imports and out-of-step modules; a check's fetch and levels; a compose's built, key and verdict; a run's built, key, exit, output and said; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the five", + "description": "what a step answered, by the kind of ask: a build's artifacts, toolchain, imports, out-of-step modules and the artifact it kept; a check's fetch and levels; a compose's built, key and verdict; a run's built, key, exit, output and said; a declined ask's declined, needs and lacks. The fields of the kinds do not meet, so one layout holds the five", "properties": { "artifacts": { "type": "array", @@ -895,6 +1062,10 @@ "type": "string" } }, + "kept": { + "type": "string", + "description": "the digest of the artifact this node kept for the artifact store's holder instead of storing it through the seat oci-artifact-registry (the verb kept-artifact serves it); the keeping node is the step's own; absent when every artifact was stored" + }, "fetch": { "$ref": "#/defs/FetchAnswer" }, @@ -1148,6 +1319,301 @@ "commit", "modules" ] + }, + "StepNames": { + "type": "object", + "description": "the names the registrations hold, which the lint step refuses fixed in code logic (ADR 0666 section 5, seams ruling M7): carried in the ask, never read by the build module from another part", + "properties": { + "modules": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "description": "every module the registrations name" + }, + "repositories": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "description": "every repository a registration's git origin names, as /" + }, + "branches": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "description": "every watched branch a registration names" + } + }, + "required": [ + "modules", + "repositories", + "branches" + ] + }, + "KeptResult": { + "type": "object", + "description": "a package's passing result the runner keeps, by the digest of what its tests read (ADR 0666 section 8): the step runs no package whose digest and level it names", + "properties": { + "package": { + "type": "string" + }, + "digest": { + "type": "string", + "description": "sha256: of what the package's tests read" + }, + "level": { + "type": "string", + "description": "unit or integration" + }, + "toolchain": { + "$ref": "#/defs/ToolchainUsed" + }, + "pipeline": { + "type": "string", + "description": "the pipeline whose step kept it" + } + }, + "required": [ + "package", + "digest", + "level" + ] + }, + "TestCounts": { + "type": "object", + "description": "how many tests a step ran and carried, per level (ADR 0666 section 8: the pipeline's end names any repository or catalog module over the test budget)", + "properties": { + "unit": { + "type": "integer" + }, + "integration": { + "type": "integer" + } + } + }, + "StepRun": { + "type": "object", + "description": "one pipeline step of one artifact at one commit (ADR 0666 sections 7, 8, 17): the step a build seat runs in its sandbox from the change's own heads, the names the lint step needs and the kept results it may skip", + "properties": { + "pipeline": { + "type": "string", + "description": "the runner's pipeline key, .., a branch escaped as a key's name is" + }, + "step": { + "type": "string", + "enum": [ + "lint", + "unit", + "integration" + ], + "description": "the pipeline step" + }, + "module": { + "type": "string" + }, + "artifact": { + "type": "string", + "description": "the artifact reference, :" + }, + "branch": { + "type": "string", + "description": "the watched branch, or the branch of a run on request" + }, + "commit": { + "type": "string", + "description": "the commit the step runs at" + }, + "revision": { + "type": "integer", + "description": "the source revision of the watched branch the pipeline runs for; absent for a run on request" + }, + "fingerprint": { + "type": "string", + "description": "the artifact's build-input fingerprint at the commit" + }, + "fetch": { + "$ref": "#/defs/Fetch", + "description": "where the step reads the change's heads" + }, + "toolchain": { + "$ref": "#/defs/ToolchainUsed" + }, + "names": { + "$ref": "#/defs/StepNames" + }, + "kept": { + "type": "array", + "items": { + "$ref": "#/defs/KeptResult" + }, + "description": "the kept results of the artifact's packages, by digest and level (design 47 *Carried, not run*)" + }, + "rerun": { + "type": "boolean", + "description": "the step is asked again by the runner's rerun" + }, + "by": { + "type": "string", + "description": "for a rerun, the caller the runtime proved" + } + }, + "required": [ + "pipeline", + "step", + "module", + "artifact", + "commit", + "fingerprint", + "fetch", + "names" + ] + }, + "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", + "properties": { + "v": { + "type": "integer", + "description": "the layout version" + }, + "id": { + "type": "string", + "description": "the ask's id" + }, + "pipeline": { + "type": "string" + }, + "step": { + "type": "string", + "enum": [ + "lint", + "unit", + "integration" + ] + }, + "module": { + "type": "string" + }, + "artifact": { + "type": "string" + }, + "commit": { + "type": "string" + }, + "fingerprint": { + "type": "string" + }, + "node": { + "type": "string", + "description": "the node that ran it, as in the subject" + }, + "outcome": { + "type": "string", + "enum": [ + "passed", + "failed", + "nothing to run", + "could not run" + ], + "description": "never passed for a step that ran nothing" + }, + "tests": { + "$ref": "#/defs/TestCounts" + }, + "carried": { + "type": "array", + "items": { + "$ref": "#/defs/KeptResult" + }, + "description": "the packages not run because the ask's kept results held them" + }, + "kept": { + "type": "array", + "items": { + "$ref": "#/defs/KeptResult" + }, + "description": "the packages that passed at their digest, for the runner to keep" + }, + "said": { + "type": "string", + "description": "why it failed or could not run, naming the part not heard" + }, + "output": { + "type": "string", + "description": "the step's output when it fits the message" + }, + "output-object": { + "type": "string", + "description": "the output's object in the sender's sent store, when over the per-message limit (ADR 0666 section 16)" + }, + "rerun": { + "type": "boolean" + }, + "by": { + "type": "string", + "description": "for a rerun, the caller the runtime proved" + }, + "started": { + "type": "string", + "format": "date-time" + }, + "ended": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "id", + "pipeline", + "step", + "module", + "artifact", + "commit", + "fingerprint", + "node", + "outcome" + ] + }, + "DetectedStep": { + "type": "object", + "properties": { + "step": { + "type": "string", + "enum": [ + "lint", + "unit", + "integration" + ] + }, + "packages": { + "type": "array", + "items": { + "type": "string" + }, + "description": "the packages the step runs, by the language's convention" + } + }, + "required": [ + "step" + ] } - } + }, + "events": [ + { + "name": "step-ended", + "subject": "step-ended.", + "body": { + "$ref": "#/defs/StepEnded" + }, + "keep": { + "max-age-days": 90, + "max-mib": 128 + } + } + ] } diff --git a/contracts/seats/node-build-go/fixtures/events.json b/contracts/seats/node-build-go/fixtures/events.json new file mode 100644 index 00000000..06ad58d6 --- /dev/null +++ b/contracts/seats/node-build-go/fixtures/events.json @@ -0,0 +1,57 @@ +[ + { + "name": "a unit step ended passed on its node, with its counts and what it carried", + "of": "event:step-ended", + "subject": "mesh.seat.node-build-go.event.step-ended.ace", + "given": { + "v": 1, + "id": "m2kx9a1b3c4d5e", + "pipeline": "main.12.nats", + "step": "unit", + "module": "nats", + "artifact": "nats:program", + "commit": "0123456789abcdef0123456789abcdef01234567", + "fingerprint": "fp-0123", + "node": "ace", + "outcome": "passed", + "tests": { + "unit": 14 + }, + "carried": [ + { + "package": "./modules/nats/a", + "digest": "sha256:bbbb", + "level": "unit" + } + ], + "kept": [ + { + "package": "./modules/nats/b", + "digest": "sha256:cccc", + "level": "unit" + } + ], + "started": "2026-11-10T10:00:00Z", + "ended": "2026-11-10T10:02:00Z" + } + }, + { + "name": "an integration step that could not run, naming the part not heard", + "of": "event:step-ended", + "subject": "mesh.seat.node-build-go.event.step-ended.g14", + "given": { + "v": 1, + "id": "m2kx9a1b3c4d5f", + "pipeline": "main.12.nats", + "step": "integration", + "module": "nats", + "artifact": "nats:program", + "commit": "0123456789abcdef0123456789abcdef01234567", + "fingerprint": "fp-0123", + "node": "g14", + "outcome": "could not run", + "said": "the sandbox could not fetch novox/mesh-sdk", + "output-object": "mesh-build-go_sent-objects/m2kx9a1b3c4d5f" + } + } +] diff --git a/contracts/seats/node-build-go/fixtures/states.json b/contracts/seats/node-build-go/fixtures/states.json index 9af3c52c..b14fffbb 100644 --- a/contracts/seats/node-build-go/fixtures/states.json +++ b/contracts/seats/node-build-go/fixtures/states.json @@ -134,6 +134,37 @@ } } }, + { + "name": "a finished build step that kept its artifact on its node", + "of": "state:steps/.", + "given": { + "v": 1, + "id": "a1b3", + "tool": "build", + "node": "ace", + "state": "passed", + "started": "2026-11-05T10:00:00Z", + "ended": "2026-11-05T10:03:00Z", + "result": { + "artifacts": [ + { + "artifact": "go", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "reference": "container-image-registry/nats/go@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + ], + "toolchain": { + "language": "go", + "version": "1.26.0", + "recipe": "1" + }, + "imports": [ + "git.novox.be/novox/mesh-sdk/go" + ], + "kept": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + } + }, { "name": "a finished check step with its levels", "of": "state:steps/.", @@ -339,5 +370,53 @@ "why": "a newer fingerprint supersedes it", "at": "2026-11-05T10:00:00Z" } + }, + { + "name": "a step ask of the runner with the names and kept results", + "of": "accept:step", + "subject": "mesh.seat.node-build-go.accept.step", + "given": { + "v": 1, + "id": "m2kx9a1b3c4d5e", + "kind": "step", + "language": "go", + "asker": "mesh-delivery-pipeline", + "at": "2026-11-10T10:00:00Z", + "step": { + "pipeline": "main.12.nats", + "step": "unit", + "module": "nats", + "artifact": "nats:program", + "branch": "main", + "commit": "0123456789abcdef0123456789abcdef01234567", + "revision": 12, + "fingerprint": "fp-0123", + "fetch": { + "repository": "novox/mesh-catalog", + "commit": "0123456789abcdef0123456789abcdef01234567" + }, + "names": { + "modules": [ + "nats", + "mesh-sdk" + ], + "repositories": [ + "novox/mesh-catalog", + "novox/mesh-sdk" + ], + "branches": [ + "main" + ] + }, + "kept": [ + { + "package": "./modules/nats/a", + "digest": "sha256:bbbb", + "level": "unit", + "pipeline": "main.11.nats" + } + ] + } + } } ] diff --git a/contracts/seats/node-build-go/fixtures/verbs.json b/contracts/seats/node-build-go/fixtures/verbs.json index 727e95b6..1e4af4dd 100644 --- a/contracts/seats/node-build-go/fixtures/verbs.json +++ b/contracts/seats/node-build-go/fixtures/verbs.json @@ -7,5 +7,98 @@ "by": "mesh-delivery-builder", "why": "a newer fingerprint supersedes it" } + }, + { + "name": "kept-artifact asks", + "of": "verb:kept-artifact.input", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + } + }, + { + "name": "kept-artifact answers where the bytes are", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "size": 18874368, + "store": "mesh-build-go-kept", + "object": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + } + }, + { + "name": "kept-artifact refuses a module that is claims no oci-artifact-registry", + "of": "verb:kept-artifact.answer", + "given": { + "module": "mesh-delivery-gate", + "fp": "src2:aaaaaaaa", + "refused": "claims no oci-artifact-registry", + "words": "mesh-delivery-gate claims no oci-artifact-registry: its build is fetched from the store" + } + }, + { + "name": "kept-artifact refuses a build it no longer keeps", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "refused": "not kept", + "words": "this node keeps no build of artifact-store at src2:1480985e" + } + }, + { + "name": "kept-artifact refuses a build kept under another digest", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "refused": "digest differs", + "words": "artifact-store at src2:1480985e is kept as eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + } + }, + { + "name": "kept-artifact answers an error, never none", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "error": "the kept builds could not be read" + } + }, + { + "name": "steps asks an artifact's pipeline steps at a commit", + "of": "verb:steps.input", + "given": { + "module": "nats", + "artifact": "nats:program", + "fingerprint": "fp-0123", + "fetch": { + "repository": "novox/mesh-catalog", + "commit": "0123456789abcdef0123456789abcdef01234567" + } + } + }, + { + "name": "steps answers lint and unit tests", + "of": "verb:steps.answer", + "given": { + "artifact": "nats:program", + "fingerprint": "fp-0123", + "steps": [ + { + "step": "lint" + }, + { + "step": "unit", + "packages": [ + "./modules/nats" + ] + } + ] + } } ] diff --git a/contracts/seats/node-build-go/seat.json b/contracts/seats/node-build-go/seat.json index ccdd85cd..6bb7f53a 100644 --- a/contracts/seats/node-build-go/seat.json +++ b/contracts/seats/node-build-go/seat.json @@ -7,24 +7,51 @@ "decision": "novox/hq ADR 0525, ADR 0536, ADR 0553", "pulled-by-kind": true, "yields": true, + "acts": [ + { + "step": "build", + "on": "go", + "bound": "60m" + } + ], "accepts": [ { "name": "delivery", "body": { "$ref": "#/defs/StepAsk" - } + }, + "callers": [ + "seat:mesh-builds" + ] }, { "name": "check", "body": { "$ref": "#/defs/StepAsk" - } + }, + "callers": [ + "seat:mesh-delivery-checker", + "seat:mesh-catalog", + "seat:mesh-pipeline-runner" + ] + }, + { + "name": "step", + "body": { + "$ref": "#/defs/StepAsk" + }, + "callers": [ + "seat:mesh-pipeline-runner" + ] }, { "name": "recheck", "body": { "$ref": "#/defs/StepAsk" - } + }, + "callers": [ + "seat:mesh-delivery-checker" + ] } ], "description": "The Go build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.", @@ -91,5 +118,9 @@ "description": "the toolchains the nodes report", "history": 1 } - ] + ], + "family": { + "name": "node-build-go.events", + "max-age-days": 7 + } } diff --git a/contracts/seats/node-build-image/fixtures/events.json b/contracts/seats/node-build-image/fixtures/events.json new file mode 100644 index 00000000..1e20d2ed --- /dev/null +++ b/contracts/seats/node-build-image/fixtures/events.json @@ -0,0 +1,40 @@ +[ + { + "name": "a lint step ended passed on its node", + "of": "event:step-ended", + "subject": "mesh.seat.node-build-image.event.step-ended.ace", + "given": { + "v": 1, + "id": "m2kx9a1b3c4d5e", + "pipeline": "main.12.nats", + "step": "lint", + "module": "nats", + "artifact": "nats:program", + "commit": "0123456789abcdef0123456789abcdef01234567", + "fingerprint": "fp-0123", + "node": "ace", + "outcome": "passed", + "started": "2026-11-10T10:00:00Z", + "ended": "2026-11-10T10:02:00Z" + } + }, + { + "name": "a lint step that could not run, naming the part not heard", + "of": "event:step-ended", + "subject": "mesh.seat.node-build-image.event.step-ended.g14", + "given": { + "v": 1, + "id": "m2kx9a1b3c4d5f", + "pipeline": "main.12.nats", + "step": "lint", + "module": "nats", + "artifact": "nats:program", + "commit": "0123456789abcdef0123456789abcdef01234567", + "fingerprint": "fp-0123", + "node": "g14", + "outcome": "could not run", + "said": "the sandbox could not fetch novox/mesh-sdk", + "output-object": "mesh-build-go_sent-objects/m2kx9a1b3c4d5f" + } + } +] diff --git a/contracts/seats/node-build-image/fixtures/states.json b/contracts/seats/node-build-image/fixtures/states.json index 7e3ef453..c993e033 100644 --- a/contracts/seats/node-build-image/fixtures/states.json +++ b/contracts/seats/node-build-image/fixtures/states.json @@ -86,5 +86,45 @@ "why": "a newer fingerprint supersedes it", "at": "2026-11-05T10:00:00Z" } + }, + { + "name": "a lint step ask of the runner with the names", + "of": "accept:step", + "subject": "mesh.seat.node-build-image.accept.step", + "given": { + "v": 1, + "id": "m2kx9a1b3c4d5e", + "kind": "step", + "language": "image", + "asker": "mesh-delivery-pipeline", + "at": "2026-11-10T10:00:00Z", + "step": { + "pipeline": "main.12.nats", + "step": "lint", + "module": "nats", + "artifact": "nats:program", + "branch": "main", + "commit": "0123456789abcdef0123456789abcdef01234567", + "revision": 12, + "fingerprint": "fp-0123", + "fetch": { + "repository": "novox/mesh-catalog", + "commit": "0123456789abcdef0123456789abcdef01234567" + }, + "names": { + "modules": [ + "nats", + "mesh-sdk" + ], + "repositories": [ + "novox/mesh-catalog", + "novox/mesh-sdk" + ], + "branches": [ + "main" + ] + } + } + } } ] diff --git a/contracts/seats/node-build-image/fixtures/verbs.json b/contracts/seats/node-build-image/fixtures/verbs.json index 727e95b6..1e4af4dd 100644 --- a/contracts/seats/node-build-image/fixtures/verbs.json +++ b/contracts/seats/node-build-image/fixtures/verbs.json @@ -7,5 +7,98 @@ "by": "mesh-delivery-builder", "why": "a newer fingerprint supersedes it" } + }, + { + "name": "kept-artifact asks", + "of": "verb:kept-artifact.input", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + } + }, + { + "name": "kept-artifact answers where the bytes are", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "size": 18874368, + "store": "mesh-build-go-kept", + "object": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + } + }, + { + "name": "kept-artifact refuses a module that is claims no oci-artifact-registry", + "of": "verb:kept-artifact.answer", + "given": { + "module": "mesh-delivery-gate", + "fp": "src2:aaaaaaaa", + "refused": "claims no oci-artifact-registry", + "words": "mesh-delivery-gate claims no oci-artifact-registry: its build is fetched from the store" + } + }, + { + "name": "kept-artifact refuses a build it no longer keeps", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "refused": "not kept", + "words": "this node keeps no build of artifact-store at src2:1480985e" + } + }, + { + "name": "kept-artifact refuses a build kept under another digest", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "refused": "digest differs", + "words": "artifact-store at src2:1480985e is kept as eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + } + }, + { + "name": "kept-artifact answers an error, never none", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "error": "the kept builds could not be read" + } + }, + { + "name": "steps asks an artifact's pipeline steps at a commit", + "of": "verb:steps.input", + "given": { + "module": "nats", + "artifact": "nats:program", + "fingerprint": "fp-0123", + "fetch": { + "repository": "novox/mesh-catalog", + "commit": "0123456789abcdef0123456789abcdef01234567" + } + } + }, + { + "name": "steps answers lint and unit tests", + "of": "verb:steps.answer", + "given": { + "artifact": "nats:program", + "fingerprint": "fp-0123", + "steps": [ + { + "step": "lint" + }, + { + "step": "unit", + "packages": [ + "./modules/nats" + ] + } + ] + } } ] diff --git a/contracts/seats/node-build-image/seat.json b/contracts/seats/node-build-image/seat.json index 60295d98..d2329e72 100644 --- a/contracts/seats/node-build-image/seat.json +++ b/contracts/seats/node-build-image/seat.json @@ -12,19 +12,37 @@ "name": "delivery", "body": { "$ref": "#/defs/StepAsk" - } + }, + "callers": [ + "seat:mesh-builds" + ] }, { "name": "check", "body": { "$ref": "#/defs/StepAsk" - } + }, + "callers": [ + "seat:mesh-delivery-checker" + ] + }, + { + "name": "step", + "body": { + "$ref": "#/defs/StepAsk" + }, + "callers": [ + "seat:mesh-pipeline-runner" + ] }, { "name": "recheck", "body": { "$ref": "#/defs/StepAsk" - } + }, + "callers": [ + "seat:mesh-delivery-checker" + ] } ], "description": "The image build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.", @@ -91,5 +109,9 @@ "description": "the toolchains the nodes report", "history": 1 } - ] + ], + "family": { + "name": "node-build-image.events", + "max-age-days": 7 + } } diff --git a/contracts/seats/node-build-node/fixtures/events.json b/contracts/seats/node-build-node/fixtures/events.json new file mode 100644 index 00000000..0fb1ac2d --- /dev/null +++ b/contracts/seats/node-build-node/fixtures/events.json @@ -0,0 +1,57 @@ +[ + { + "name": "a unit step ended passed on its node, with its counts and what it carried", + "of": "event:step-ended", + "subject": "mesh.seat.node-build-node.event.step-ended.ace", + "given": { + "v": 1, + "id": "m2kx9a1b3c4d5e", + "pipeline": "main.12.nats", + "step": "unit", + "module": "nats", + "artifact": "nats:program", + "commit": "0123456789abcdef0123456789abcdef01234567", + "fingerprint": "fp-0123", + "node": "ace", + "outcome": "passed", + "tests": { + "unit": 14 + }, + "carried": [ + { + "package": "./modules/nats/a", + "digest": "sha256:bbbb", + "level": "unit" + } + ], + "kept": [ + { + "package": "./modules/nats/b", + "digest": "sha256:cccc", + "level": "unit" + } + ], + "started": "2026-11-10T10:00:00Z", + "ended": "2026-11-10T10:02:00Z" + } + }, + { + "name": "an integration step that could not run, naming the part not heard", + "of": "event:step-ended", + "subject": "mesh.seat.node-build-node.event.step-ended.g14", + "given": { + "v": 1, + "id": "m2kx9a1b3c4d5f", + "pipeline": "main.12.nats", + "step": "integration", + "module": "nats", + "artifact": "nats:program", + "commit": "0123456789abcdef0123456789abcdef01234567", + "fingerprint": "fp-0123", + "node": "g14", + "outcome": "could not run", + "said": "the sandbox could not fetch novox/mesh-sdk", + "output-object": "mesh-build-go_sent-objects/m2kx9a1b3c4d5f" + } + } +] diff --git a/contracts/seats/node-build-node/fixtures/states.json b/contracts/seats/node-build-node/fixtures/states.json index d8e5ea20..e2cd93a4 100644 --- a/contracts/seats/node-build-node/fixtures/states.json +++ b/contracts/seats/node-build-node/fixtures/states.json @@ -158,5 +158,53 @@ "why": "a newer fingerprint supersedes it", "at": "2026-11-05T10:00:00Z" } + }, + { + "name": "a step ask of the runner with the names and kept results", + "of": "accept:step", + "subject": "mesh.seat.node-build-node.accept.step", + "given": { + "v": 1, + "id": "m2kx9a1b3c4d5e", + "kind": "step", + "language": "typescript", + "asker": "mesh-delivery-pipeline", + "at": "2026-11-10T10:00:00Z", + "step": { + "pipeline": "main.12.nats", + "step": "unit", + "module": "nats", + "artifact": "nats:program", + "branch": "main", + "commit": "0123456789abcdef0123456789abcdef01234567", + "revision": 12, + "fingerprint": "fp-0123", + "fetch": { + "repository": "novox/mesh-catalog", + "commit": "0123456789abcdef0123456789abcdef01234567" + }, + "names": { + "modules": [ + "nats", + "mesh-sdk" + ], + "repositories": [ + "novox/mesh-catalog", + "novox/mesh-sdk" + ], + "branches": [ + "main" + ] + }, + "kept": [ + { + "package": "./modules/nats/a", + "digest": "sha256:bbbb", + "level": "unit", + "pipeline": "main.11.nats" + } + ] + } + } } ] diff --git a/contracts/seats/node-build-node/fixtures/verbs.json b/contracts/seats/node-build-node/fixtures/verbs.json index 727e95b6..1e4af4dd 100644 --- a/contracts/seats/node-build-node/fixtures/verbs.json +++ b/contracts/seats/node-build-node/fixtures/verbs.json @@ -7,5 +7,98 @@ "by": "mesh-delivery-builder", "why": "a newer fingerprint supersedes it" } + }, + { + "name": "kept-artifact asks", + "of": "verb:kept-artifact.input", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + } + }, + { + "name": "kept-artifact answers where the bytes are", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "digest": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "size": 18874368, + "store": "mesh-build-go-kept", + "object": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + } + }, + { + "name": "kept-artifact refuses a module that is claims no oci-artifact-registry", + "of": "verb:kept-artifact.answer", + "given": { + "module": "mesh-delivery-gate", + "fp": "src2:aaaaaaaa", + "refused": "claims no oci-artifact-registry", + "words": "mesh-delivery-gate claims no oci-artifact-registry: its build is fetched from the store" + } + }, + { + "name": "kept-artifact refuses a build it no longer keeps", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "refused": "not kept", + "words": "this node keeps no build of artifact-store at src2:1480985e" + } + }, + { + "name": "kept-artifact refuses a build kept under another digest", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "digest": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "refused": "digest differs", + "words": "artifact-store at src2:1480985e is kept as eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + } + }, + { + "name": "kept-artifact answers an error, never none", + "of": "verb:kept-artifact.answer", + "given": { + "module": "artifact-store", + "fp": "src2:1480985e", + "error": "the kept builds could not be read" + } + }, + { + "name": "steps asks an artifact's pipeline steps at a commit", + "of": "verb:steps.input", + "given": { + "module": "nats", + "artifact": "nats:program", + "fingerprint": "fp-0123", + "fetch": { + "repository": "novox/mesh-catalog", + "commit": "0123456789abcdef0123456789abcdef01234567" + } + } + }, + { + "name": "steps answers lint and unit tests", + "of": "verb:steps.answer", + "given": { + "artifact": "nats:program", + "fingerprint": "fp-0123", + "steps": [ + { + "step": "lint" + }, + { + "step": "unit", + "packages": [ + "./modules/nats" + ] + } + ] + } } ] diff --git a/contracts/seats/node-build-node/seat.json b/contracts/seats/node-build-node/seat.json index 74873ba1..d500250e 100644 --- a/contracts/seats/node-build-node/seat.json +++ b/contracts/seats/node-build-node/seat.json @@ -7,24 +7,49 @@ "decision": "novox/hq ADR 0525, ADR 0536, ADR 0553", "pulled-by-kind": true, "yields": true, + "acts": [ + { + "step": "build", + "on": "typescript", + "bound": "60m" + } + ], "accepts": [ { "name": "delivery", "body": { "$ref": "#/defs/StepAsk" - } + }, + "callers": [ + "seat:mesh-builds" + ] }, { "name": "check", "body": { "$ref": "#/defs/StepAsk" - } + }, + "callers": [ + "seat:mesh-delivery-checker" + ] + }, + { + "name": "step", + "body": { + "$ref": "#/defs/StepAsk" + }, + "callers": [ + "seat:mesh-pipeline-runner" + ] }, { "name": "recheck", "body": { "$ref": "#/defs/StepAsk" - } + }, + "callers": [ + "seat:mesh-delivery-checker" + ] } ], "description": "The Node build module on a node: it takes the asks of the builder and the checker, runs them as steps and answers.", @@ -91,5 +116,9 @@ "description": "the toolchains the nodes report", "history": 1 } - ] + ], + "family": { + "name": "node-build-node.events", + "max-age-days": 7 + } }