diff --git a/parts/registry.json b/parts/registry.json new file mode 100644 index 0000000..af29f85 --- /dev/null +++ b/parts/registry.json @@ -0,0 +1,397 @@ +{ + "format": 1, + "part": "registry", + "description": "The verbs and events every registry seat shares, written once so the four cannot drift (design 51, design 26). Who may call each verb is the holder's trusted config value listing its callers (ADR 0363's form), checked against the caller the tool runner proved.", + "verbs": [ + { + "name": "publish", + "description": "Open a transfer, naming the artifact and the digest of every part; answers the digests the holder lacks, which the caller then sends by publish-part. A transfer already open answers the parts held, so a cut transfer goes on from there. With no parts and a version, the held digest is published under that version and nothing is stored (the trunk's claim).", + "callers": "the build modules", + "input": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the package's, image's, bundle's or archive's name" + }, + "version": { + "type": "string", + "description": "the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone" + }, + "kind": { + "type": "string", + "enum": [ + "package", + "image", + "bundle", + "archive", + "upstream" + ], + "description": "what it is" + }, + "tag": { + "type": "string", + "description": "the tag it carries, for a tagged version" + }, + "digest": { + "type": "string", + "description": "its digest, sha256: (a Go package's h1: hash beside it in the version's record)" + }, + "fingerprint": { + "type": "string", + "description": "the build's fingerprint" + }, + "commit": { + "type": "string", + "description": "the source commit it was built from" + }, + "transfer": { + "type": "string", + "description": "the transfer's name, the caller's own; the same name opens the same transfer again" + }, + "parts": { + "type": "array", + "items": { + "$ref": "#/defs/Part" + }, + "description": "every part's digest and size; none when the digest is already held" + } + }, + "required": [ + "transfer", + "name", + "kind", + "digest" + ] + }, + "answer": { + "type": "object", + "properties": { + "transfer": { + "type": "string", + "description": "the transfer" + }, + "lacks": { + "type": "array", + "items": { + "type": "string" + }, + "description": "the digests of the parts the holder lacks, to send by publish-part" + }, + "held": { + "type": "boolean", + "description": "the digest is held already: nothing to send; the outcome follows as an event" + } + }, + "required": [ + "transfer" + ] + } + }, + { + "name": "publish-part", + "description": "Send one chunk of one part of an open transfer; the last chunk of the last part ends the transfer, and the holder hashes what it received, asks builder_versions, stores it and says published or refused. A chunk's message stays under the bus's largest message (1 MiB), so at most 768 KiB of data, base64.", + "callers": "the build modules, and only the proved caller that opened the transfer", + "input": { + "type": "object", + "properties": { + "transfer": { + "type": "string", + "description": "the transfer" + }, + "part": { + "type": "string", + "description": "the part's digest" + }, + "sequence": { + "type": "integer", + "description": "the chunk's place in its part, from 0" + }, + "last": { + "type": "boolean", + "description": "this chunk is the part's last" + }, + "data": { + "type": "string", + "description": "the chunk's bytes, base64 (at most 768 KiB before encoding)" + } + }, + "required": [ + "transfer", + "part", + "sequence", + "last", + "data" + ] + }, + "answer": { + "type": "object", + "properties": { + "transfer": { + "type": "string", + "description": "the transfer" + }, + "part": { + "type": "string", + "description": "the part" + }, + "received": { + "type": "integer", + "description": "the chunks of the part held so far" + }, + "complete": { + "type": "boolean", + "description": "the part is whole and its bytes match its digest" + } + }, + "required": [ + "transfer", + "part" + ] + } + }, + { + "name": "versions", + "description": "The versions the seat holds of one name, newest first: each one's version, tag, digest, kind and when it was published.", + "callers": "any caller whose role grants it", + "input": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name" + }, + "kind": { + "type": "string", + "description": "narrowed to one kind (optional)" + } + }, + "required": [ + "name" + ] + }, + "answer": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name" + }, + "versions": { + "type": "array", + "items": { + "$ref": "#/defs/Artifact" + }, + "description": "newest first" + } + }, + "required": [ + "name", + "versions" + ] + } + }, + { + "name": "remove", + "description": "Remove one tagged version; the holder refuses an untagged one but for the retention removal of a bundle, archive or copied base by the artifact sweep's holder. Every removal emits removed with its reason.", + "callers": "the builder, for a tagged version; the artifact sweep's holder, for retention", + "input": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name" + }, + "version": { + "type": "string", + "description": "the version" + }, + "tag": { + "type": "string", + "description": "the tag (for a tagged version)" + }, + "digest": { + "type": "string", + "description": "the digest (for a bundle, archive or copied base)" + }, + "reason": { + "type": "string", + "enum": [ + "tag-gone", + "retention" + ], + "description": "why it goes" + } + }, + "required": [ + "name", + "reason" + ] + }, + "answer": { + "type": "object", + "properties": { + "removed": { + "type": "boolean", + "description": "it is gone" + }, + "artifact": { + "$ref": "#/defs/Artifact" + } + }, + "required": [ + "removed" + ] + } + } + ], + "events": [ + { + "name": "published", + "body": { + "$ref": "#/defs/Outcome" + } + }, + { + "name": "refused", + "body": { + "$ref": "#/defs/Outcome" + } + }, + { + "name": "removed", + "body": { + "$ref": "#/defs/Outcome" + } + } + ], + "defs": { + "Artifact": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the package's, image's, bundle's or archive's name" + }, + "version": { + "type": "string", + "description": "the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone" + }, + "kind": { + "type": "string", + "enum": [ + "package", + "image", + "bundle", + "archive", + "upstream" + ], + "description": "what it is" + }, + "tag": { + "type": "string", + "description": "the tag it carries, for a tagged version" + }, + "digest": { + "type": "string", + "description": "its digest, sha256: (a Go package's h1: hash beside it in the version's record)" + }, + "fingerprint": { + "type": "string", + "description": "the build's fingerprint" + }, + "commit": { + "type": "string", + "description": "the source commit it was built from" + } + }, + "required": [ + "name", + "kind", + "digest" + ], + "description": "one published thing, as every registry event and answer names it" + }, + "Part": { + "type": "object", + "properties": { + "digest": { + "type": "string", + "description": "the part's digest, sha256:: an image's layer or config, a package's file, a bundle's blob" + }, + "size": { + "type": "integer", + "description": "its size in bytes" + } + }, + "required": [ + "digest", + "size" + ], + "description": "one part of a transfer" + }, + "Outcome": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the package's, image's, bundle's or archive's name" + }, + "version": { + "type": "string", + "description": "the version the builder gave it (design 51 *The versions*); empty for a bundle or archive published by its digest alone" + }, + "kind": { + "type": "string", + "enum": [ + "package", + "image", + "bundle", + "archive", + "upstream" + ], + "description": "what it is" + }, + "tag": { + "type": "string", + "description": "the tag it carries, for a tagged version" + }, + "digest": { + "type": "string", + "description": "its digest, sha256: (a Go package's h1: hash beside it in the version's record)" + }, + "fingerprint": { + "type": "string", + "description": "the build's fingerprint" + }, + "commit": { + "type": "string", + "description": "the source commit it was built from" + }, + "holder": { + "type": "string", + "description": "the module holding the seat that said it" + }, + "transfer": { + "type": "string", + "description": "the transfer it ends, when it ended one" + }, + "reference": { + "type": "string", + "description": "the reference the seat answers: //@sha256:, or @ for a package (ADR 0605 §9)" + }, + "reason": { + "type": "string", + "description": "why: a refusal's cause, or a removal's (retention, tag-gone, by-hand)" + } + }, + "required": [ + "name", + "kind", + "digest", + "holder" + ], + "description": "the body of published, refused and removed" + } + } +} diff --git a/seats/container-image-registry/fixtures/events.json b/seats/container-image-registry/fixtures/events.json new file mode 100644 index 0000000..8bd60c9 --- /dev/null +++ b/seats/container-image-registry/fixtures/events.json @@ -0,0 +1,78 @@ +[ + { + "name": "published on the seat's subject", + "of": "event:published", + "subject": "mesh.seat.container-image-registry.event.published", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "image", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "distribution", + "transfer": "t1", + "reference": "container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + }, + { + "name": "refused on the seat's subject", + "of": "event:refused", + "subject": "mesh.seat.container-image-registry.event.refused", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "image", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "distribution", + "transfer": "t1", + "reference": "container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "reason": "retention" + } + }, + { + "name": "removed on the seat's subject", + "of": "event:removed", + "subject": "mesh.seat.container-image-registry.event.removed", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "image", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "distribution", + "transfer": "t1", + "reference": "container-image-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "reason": "retention" + } + }, + { + "name": "held on the seat's subject", + "of": "event:held", + "subject": "mesh.seat.container-image-registry.event.held", + "given": { + "name": "mesh-sdk", + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "reason": "kept by the sweep's rule", + "holder": "distribution", + "by": "mesh-artifact-sweep", + "at": "2026-11-04T12:00:00Z" + } + }, + { + "name": "released on the seat's subject", + "of": "event:released", + "subject": "mesh.seat.container-image-registry.event.released", + "given": { + "name": "mesh-sdk", + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "reason": "kept by the sweep's rule", + "holder": "distribution", + "by": "mesh-artifact-sweep", + "at": "2026-11-04T12:00:00Z" + } + } +] diff --git a/seats/container-image-registry/fixtures/verbs.json b/seats/container-image-registry/fixtures/verbs.json new file mode 100644 index 0000000..2c03cdc --- /dev/null +++ b/seats/container-image-registry/fixtures/verbs.json @@ -0,0 +1,97 @@ +[ + { + "name": "publish opens a transfer", + "of": "verb:publish.input", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "image", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ] + } + }, + { + "name": "a field the reader does not know is dropped", + "of": "verb:publish.input", + "why": "ADR 0608 §6: a reader ignores a field it does not know", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "image", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ], + "later": { + "x": 1 + } + }, + "wire": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "image", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ] + } + }, + { + "name": "publish answers what it lacks", + "of": "verb:publish.answer", + "given": { + "transfer": "t1", + "lacks": [ + "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ] + } + }, + { + "name": "a chunk of a part", + "of": "verb:publish-part.input", + "given": { + "transfer": "t1", + "part": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "sequence": 0, + "last": true, + "data": "aGVsbG8=" + } + }, + { + "name": "the versions held", + "of": "verb:versions.answer", + "given": { + "name": "mesh-sdk", + "versions": [ + { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc" + } + ] + } + } +] diff --git a/seats/container-image-registry/seat.json b/seats/container-image-registry/seat.json new file mode 100644 index 0000000..c289aad --- /dev/null +++ b/seats/container-image-registry/seat.json @@ -0,0 +1,264 @@ +{ + "format": 1, + "seat": "container-image-registry", + "scope": "mesh", + "grain": "whole", + "decision": "novox/hq ADR 0605", + "description": "The mesh's container images, in the one artifact store: the OCI distribution protocol's read side, an image's tags and mirroring an outside image.", + "delivers": "artifact-store", + "includes": [ + "registry" + ], + "verbs": [ + { + "name": "mirror", + "description": "Copy an outside image into the store by its pinned digest; emits published or refused.", + "callers": "mesh-build-image's holder of the image build seat", + "input": { + "type": "object", + "properties": { + "source": { + "type": "string", + "description": "the outside image's reference" + }, + "digest": { + "type": "string", + "description": "its pinned digest, sha256:" + }, + "name": { + "type": "string", + "description": "the name it is kept under" + } + }, + "required": [ + "source", + "digest", + "name" + ] + }, + "answer": { + "type": "object", + "properties": { + "reference": { + "type": "string", + "description": "the reference the seat answers" + }, + "digest": { + "type": "string", + "description": "the digest stored" + } + }, + "required": [ + "reference", + "digest" + ] + } + }, + { + "name": "tags", + "description": "The tags of one image and the digest each names.", + "callers": "any caller whose role grants it", + "input": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the image" + } + }, + "required": [ + "name" + ] + }, + "answer": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the image" + }, + "tags": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tag": { + "type": "string", + "description": "the tag" + }, + "digest": { + "type": "string", + "description": "its digest" + } + }, + "required": [ + "tag", + "digest" + ] + }, + "description": "every tag" + } + }, + "required": [ + "name", + "tags" + ] + } + }, + { + "name": "hold", + "description": "Keep one untagged bundle, archive or copied base from removal by retention, as the artifact sweep's rules keep it (ADR 0617 §2); never an image of the holder's own. Emits held.", + "callers": "the module that runs the artifact sweep alone", + "input": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name" + }, + "digest": { + "type": "string", + "description": "the digest" + }, + "reason": { + "type": "string", + "description": "which of the sweep's rules keeps it" + } + }, + "required": [ + "name", + "digest", + "reason" + ] + }, + "answer": { + "type": "object", + "properties": { + "held": { + "type": "boolean", + "description": "it is held" + }, + "since": { + "type": "string", + "description": "when the hold began, RFC 3339" + } + }, + "required": [ + "held" + ] + } + }, + { + "name": "release", + "description": "Let a hold go; emits released. By hand only through the holder's own tool, the operator's session as the proved caller, recorded as a hand act.", + "callers": "the module that runs the artifact sweep; the operator's session through the holder's tool", + "input": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name" + }, + "digest": { + "type": "string", + "description": "the digest" + }, + "reason": { + "type": "string", + "description": "why it is let go" + } + }, + "required": [ + "name", + "digest", + "reason" + ] + }, + "answer": { + "type": "object", + "properties": { + "released": { + "type": "boolean", + "description": "the hold is gone" + } + }, + "required": [ + "released" + ] + } + } + ], + "events": [ + { + "name": "held", + "body": { + "$ref": "#/defs/Hold" + } + }, + { + "name": "released", + "body": { + "$ref": "#/defs/Hold" + } + } + ], + "family": { + "name": "container-image-registry.events", + "max-age-days": 7 + }, + "provisions": [ + { + "name": "artifact-store", + "form": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "the store's address" + } + }, + "required": [ + "url" + ], + "description": "the artifact store's read side, the OCI distribution protocol's GET and HEAD, open on the mesh network (design 51)" + } + } + ], + "defs": { + "Hold": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name" + }, + "digest": { + "type": "string", + "description": "the digest" + }, + "reason": { + "type": "string", + "description": "why" + }, + "holder": { + "type": "string", + "description": "the module holding the seat" + }, + "by": { + "type": "string", + "description": "the caller the holder proved" + }, + "at": { + "type": "string", + "description": "when, RFC 3339" + } + }, + "required": [ + "name", + "digest", + "holder" + ], + "description": "the body of held and released" + } + } +} diff --git a/seats/go-package-registry/fixtures/events.json b/seats/go-package-registry/fixtures/events.json new file mode 100644 index 0000000..fde91ce --- /dev/null +++ b/seats/go-package-registry/fixtures/events.json @@ -0,0 +1,52 @@ +[ + { + "name": "published on the seat's subject", + "of": "event:published", + "subject": "mesh.seat.go-package-registry.event.published", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "gitea", + "transfer": "t1", + "reference": "mesh-sdk@0.1.19" + } + }, + { + "name": "refused on the seat's subject", + "of": "event:refused", + "subject": "mesh.seat.go-package-registry.event.refused", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "gitea", + "transfer": "t1", + "reference": "mesh-sdk@0.1.19", + "reason": "retention" + } + }, + { + "name": "removed on the seat's subject", + "of": "event:removed", + "subject": "mesh.seat.go-package-registry.event.removed", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "gitea", + "transfer": "t1", + "reference": "mesh-sdk@0.1.19", + "reason": "retention" + } + } +] diff --git a/seats/go-package-registry/fixtures/verbs.json b/seats/go-package-registry/fixtures/verbs.json new file mode 100644 index 0000000..338bf36 --- /dev/null +++ b/seats/go-package-registry/fixtures/verbs.json @@ -0,0 +1,97 @@ +[ + { + "name": "publish opens a transfer", + "of": "verb:publish.input", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ] + } + }, + { + "name": "a field the reader does not know is dropped", + "of": "verb:publish.input", + "why": "ADR 0608 §6: a reader ignores a field it does not know", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ], + "later": { + "x": 1 + } + }, + "wire": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ] + } + }, + { + "name": "publish answers what it lacks", + "of": "verb:publish.answer", + "given": { + "transfer": "t1", + "lacks": [ + "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ] + } + }, + { + "name": "a chunk of a part", + "of": "verb:publish-part.input", + "given": { + "transfer": "t1", + "part": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "sequence": 0, + "last": true, + "data": "aGVsbG8=" + } + }, + { + "name": "the versions held", + "of": "verb:versions.answer", + "given": { + "name": "mesh-sdk", + "versions": [ + { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc" + } + ] + } + } +] diff --git a/seats/go-package-registry/seat.json b/seats/go-package-registry/seat.json new file mode 100644 index 0000000..edf3998 --- /dev/null +++ b/seats/go-package-registry/seat.json @@ -0,0 +1,34 @@ +{ + "format": 1, + "seat": "go-package-registry", + "scope": "mesh", + "grain": "whole", + "decision": "novox/hq ADR 0605", + "description": "The mesh's Go modules: Go's module proxy protocol's read side, and publishing over the bus.", + "delivers": "go-package-registry", + "includes": [ + "registry" + ], + "family": { + "name": "go-package-registry.events", + "max-age-days": 7 + }, + "provisions": [ + { + "name": "go-package-registry", + "form": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "the read side's address" + } + }, + "required": [ + "url" + ], + "description": "form none: the Go module proxy's read side, answered anonymously, with no credential (design 51)" + } + } + ] +} diff --git a/seats/npm-package-registry/fixtures/events.json b/seats/npm-package-registry/fixtures/events.json new file mode 100644 index 0000000..f7cca82 --- /dev/null +++ b/seats/npm-package-registry/fixtures/events.json @@ -0,0 +1,52 @@ +[ + { + "name": "published on the seat's subject", + "of": "event:published", + "subject": "mesh.seat.npm-package-registry.event.published", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "gitea", + "transfer": "t1", + "reference": "mesh-sdk@0.1.19" + } + }, + { + "name": "refused on the seat's subject", + "of": "event:refused", + "subject": "mesh.seat.npm-package-registry.event.refused", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "gitea", + "transfer": "t1", + "reference": "mesh-sdk@0.1.19", + "reason": "retention" + } + }, + { + "name": "removed on the seat's subject", + "of": "event:removed", + "subject": "mesh.seat.npm-package-registry.event.removed", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "gitea", + "transfer": "t1", + "reference": "mesh-sdk@0.1.19", + "reason": "retention" + } + } +] diff --git a/seats/npm-package-registry/fixtures/verbs.json b/seats/npm-package-registry/fixtures/verbs.json new file mode 100644 index 0000000..338bf36 --- /dev/null +++ b/seats/npm-package-registry/fixtures/verbs.json @@ -0,0 +1,97 @@ +[ + { + "name": "publish opens a transfer", + "of": "verb:publish.input", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ] + } + }, + { + "name": "a field the reader does not know is dropped", + "of": "verb:publish.input", + "why": "ADR 0608 §6: a reader ignores a field it does not know", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ], + "later": { + "x": 1 + } + }, + "wire": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ] + } + }, + { + "name": "publish answers what it lacks", + "of": "verb:publish.answer", + "given": { + "transfer": "t1", + "lacks": [ + "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ] + } + }, + { + "name": "a chunk of a part", + "of": "verb:publish-part.input", + "given": { + "transfer": "t1", + "part": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "sequence": 0, + "last": true, + "data": "aGVsbG8=" + } + }, + { + "name": "the versions held", + "of": "verb:versions.answer", + "given": { + "name": "mesh-sdk", + "versions": [ + { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc" + } + ] + } + } +] diff --git a/seats/npm-package-registry/seat.json b/seats/npm-package-registry/seat.json new file mode 100644 index 0000000..3330edd --- /dev/null +++ b/seats/npm-package-registry/seat.json @@ -0,0 +1,34 @@ +{ + "format": 1, + "seat": "npm-package-registry", + "scope": "mesh", + "grain": "whole", + "decision": "novox/hq ADR 0109; novox/hq ADR 0605", + "description": "The mesh's npm packages: the npm registry protocol's read side, and publishing over the bus.", + "delivers": "npm-package-registry", + "includes": [ + "registry" + ], + "family": { + "name": "npm-package-registry.events", + "max-age-days": 7 + }, + "provisions": [ + { + "name": "npm-package-registry", + "form": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "the read side's address" + } + }, + "required": [ + "url" + ], + "description": "form none: the npm registry's read side, answered anonymously, with no credential (design 51)" + } + } + ] +} diff --git a/seats/oci-artifact-registry/fixtures/events.json b/seats/oci-artifact-registry/fixtures/events.json new file mode 100644 index 0000000..0928933 --- /dev/null +++ b/seats/oci-artifact-registry/fixtures/events.json @@ -0,0 +1,78 @@ +[ + { + "name": "published on the seat's subject", + "of": "event:published", + "subject": "mesh.seat.oci-artifact-registry.event.published", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "bundle", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "distribution", + "transfer": "t1", + "reference": "oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + } + }, + { + "name": "refused on the seat's subject", + "of": "event:refused", + "subject": "mesh.seat.oci-artifact-registry.event.refused", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "bundle", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "distribution", + "transfer": "t1", + "reference": "oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "reason": "retention" + } + }, + { + "name": "removed on the seat's subject", + "of": "event:removed", + "subject": "mesh.seat.oci-artifact-registry.event.removed", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "bundle", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "holder": "distribution", + "transfer": "t1", + "reference": "oci-artifact-registry/mesh-sdk/lib@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "reason": "retention" + } + }, + { + "name": "held on the seat's subject", + "of": "event:held", + "subject": "mesh.seat.oci-artifact-registry.event.held", + "given": { + "name": "mesh-sdk", + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "reason": "kept by the sweep's rule", + "holder": "distribution", + "by": "mesh-artifact-sweep", + "at": "2026-11-04T12:00:00Z" + } + }, + { + "name": "released on the seat's subject", + "of": "event:released", + "subject": "mesh.seat.oci-artifact-registry.event.released", + "given": { + "name": "mesh-sdk", + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "reason": "kept by the sweep's rule", + "holder": "distribution", + "by": "mesh-artifact-sweep", + "at": "2026-11-04T12:00:00Z" + } + } +] diff --git a/seats/oci-artifact-registry/fixtures/verbs.json b/seats/oci-artifact-registry/fixtures/verbs.json new file mode 100644 index 0000000..697b2ca --- /dev/null +++ b/seats/oci-artifact-registry/fixtures/verbs.json @@ -0,0 +1,97 @@ +[ + { + "name": "publish opens a transfer", + "of": "verb:publish.input", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "bundle", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ] + } + }, + { + "name": "a field the reader does not know is dropped", + "of": "verb:publish.input", + "why": "ADR 0608 §6: a reader ignores a field it does not know", + "given": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "bundle", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ], + "later": { + "x": 1 + } + }, + "wire": { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "bundle", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc", + "transfer": "t1", + "parts": [ + { + "digest": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "size": 1048576 + } + ] + } + }, + { + "name": "publish answers what it lacks", + "of": "verb:publish.answer", + "given": { + "transfer": "t1", + "lacks": [ + "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + ] + } + }, + { + "name": "a chunk of a part", + "of": "verb:publish-part.input", + "given": { + "transfer": "t1", + "part": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "sequence": 0, + "last": true, + "data": "aGVsbG8=" + } + }, + { + "name": "the versions held", + "of": "verb:versions.answer", + "given": { + "name": "mesh-sdk", + "versions": [ + { + "name": "mesh-sdk", + "version": "0.1.19", + "kind": "package", + "digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "fingerprint": "f1", + "commit": "cccccccccccccccccccccccccccccccccccccccc" + } + ] + } + } +] diff --git a/seats/oci-artifact-registry/seat.json b/seats/oci-artifact-registry/seat.json new file mode 100644 index 0000000..52921d3 --- /dev/null +++ b/seats/oci-artifact-registry/seat.json @@ -0,0 +1,169 @@ +{ + "format": 1, + "seat": "oci-artifact-registry", + "scope": "mesh", + "grain": "whole", + "decision": "novox/hq ADR 0605", + "description": "The mesh's bundles and archives, by digest, in the one artifact store: the OCI distribution protocol's read side.", + "delivers": "artifact-store", + "includes": [ + "registry" + ], + "verbs": [ + { + "name": "hold", + "description": "Keep one untagged bundle, archive or copied base from removal by retention, as the artifact sweep's rules keep it (ADR 0617 §2); never an image of the holder's own. Emits held.", + "callers": "the module that runs the artifact sweep alone", + "input": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name" + }, + "digest": { + "type": "string", + "description": "the digest" + }, + "reason": { + "type": "string", + "description": "which of the sweep's rules keeps it" + } + }, + "required": [ + "name", + "digest", + "reason" + ] + }, + "answer": { + "type": "object", + "properties": { + "held": { + "type": "boolean", + "description": "it is held" + }, + "since": { + "type": "string", + "description": "when the hold began, RFC 3339" + } + }, + "required": [ + "held" + ] + } + }, + { + "name": "release", + "description": "Let a hold go; emits released. By hand only through the holder's own tool, the operator's session as the proved caller, recorded as a hand act.", + "callers": "the module that runs the artifact sweep; the operator's session through the holder's tool", + "input": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name" + }, + "digest": { + "type": "string", + "description": "the digest" + }, + "reason": { + "type": "string", + "description": "why it is let go" + } + }, + "required": [ + "name", + "digest", + "reason" + ] + }, + "answer": { + "type": "object", + "properties": { + "released": { + "type": "boolean", + "description": "the hold is gone" + } + }, + "required": [ + "released" + ] + } + } + ], + "events": [ + { + "name": "held", + "body": { + "$ref": "#/defs/Hold" + } + }, + { + "name": "released", + "body": { + "$ref": "#/defs/Hold" + } + } + ], + "family": { + "name": "oci-artifact-registry.events", + "max-age-days": 7 + }, + "provisions": [ + { + "name": "artifact-store", + "form": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "the store's address" + } + }, + "required": [ + "url" + ], + "description": "the artifact store's read side, the OCI distribution protocol's GET and HEAD, open on the mesh network (design 51)" + } + } + ], + "defs": { + "Hold": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "the name" + }, + "digest": { + "type": "string", + "description": "the digest" + }, + "reason": { + "type": "string", + "description": "why" + }, + "holder": { + "type": "string", + "description": "the module holding the seat" + }, + "by": { + "type": "string", + "description": "the caller the holder proved" + }, + "at": { + "type": "string", + "description": "when, RFC 3339" + } + }, + "required": [ + "name", + "digest", + "holder" + ], + "description": "the body of held and released" + } + } +}