From 6fb4236eb466da29413ff56319e8917061f9c46a Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 15:01:35 +0100 Subject: [PATCH] =?UTF-8?q?mesh-delivery-contracts:=20mesh-catalog's=20mod?= =?UTF-8?q?ules=20and=20module=20answers=20typed,=20a=20module's=20toolcha?= =?UTF-8?q?ins=20typed,=20fixtures=20captured=20from=20the=20seat's=20own?= =?UTF-8?q?=20read=20tools=20(ADR=200634=20=C2=A76;=20issue=201966)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- contracts/go/seats/meshcatalog/contract.go | 93 +++++++++--- .../go/seats/meshcatalog/contract_test.go | 12 +- .../seats/mesh-catalog/fixtures/states.json | 118 +++++++++++++-- contracts/seats/mesh-catalog/seat.json | 141 ++++++++++++++++-- contracts/ts/seats/meshcatalog/src/index.ts | 48 +++++- 5 files changed, 358 insertions(+), 54 deletions(-) diff --git a/contracts/go/seats/meshcatalog/contract.go b/contracts/go/seats/meshcatalog/contract.go index 243a0d33..728a09b0 100644 --- a/contracts/go/seats/meshcatalog/contract.go +++ b/contracts/go/seats/meshcatalog/contract.go @@ -8,6 +8,7 @@ import ( "encoding/json" "errors" "strings" + "time" ) // Seat is the seat's name. @@ -310,12 +311,37 @@ func DecodePackagesByPackageSeriesValue(raw []byte) (PackagesByPackageSeriesValu return v, nil } +// ToolchainUsed is a toolchain a fingerprint was computed with (ADR 0405 clause 7). +type ToolchainUsed struct { + Language string `json:"language"` + // the build module's recipe version + Recipe string `json:"recipe"` + // the installed toolchain's version + Version string `json:"version"` +} + // ModulesInput is what modules takes. type ModulesInput struct { } +// ModulesAnswerModulesItem is a type of the contract. +type ModulesAnswerModulesItem struct { + // the merge commit it was last changed at + Commit string `json:"commit"` + // its fingerprint (src2: and 64 hex digits); absent when it has none + Fp string `json:"fp,omitempty"` + Module string `json:"module"` + // why it has none + None string `json:"none,omitempty"` + // the module's directory in its repository, '.' for a root + Path string `json:"path,omitempty"` + Repository string `json:"repository"` +} + // ModulesAnswer is what modules answers. -type ModulesAnswer = map[string]any +type ModulesAnswer struct { + Modules []ModulesAnswerModulesItem `json:"modules"` +} // ModuleInput is what module takes. type ModuleInput struct { @@ -323,8 +349,26 @@ type ModuleInput struct { Module string `json:"module"` } +// ModuleAnswerModule is a type of the contract. +type ModuleAnswerModule struct { + // the merge commit it was last changed at + Commit string `json:"commit"` + // its fingerprint (src2: and 64 hex digits); absent when it has none + Fp string `json:"fp,omitempty"` + // the module's manifest as the trunk holds it + Manifest map[string]any `json:"manifest,omitempty"` + Module string `json:"module"` + // why it has none + None string `json:"none,omitempty"` + // the module's directory in its repository, '.' for a root + Path string `json:"path,omitempty"` + Repository string `json:"repository"` +} + // ModuleAnswer is what module answers. -type ModuleAnswer = map[string]any +type ModuleAnswer struct { + Module ModuleAnswerModule `json:"module"` +} // ProvidesInput is what provides takes. type ProvidesInput struct { @@ -435,9 +479,10 @@ type ModulesByModuleValue struct { Problems []string `json:"problems,omitempty"` Repository string `json:"repository"` // the source revision - Src int64 `json:"src,omitempty"` - Toolchains map[string]any `json:"toolchains,omitempty"` - Unknown []string `json:"unknown,omitempty"` + Src int64 `json:"src,omitempty"` + // by language: the toolchain FP2 was computed with + Toolchains map[string]ToolchainUsed `json:"toolchains,omitempty"` + Unknown []string `json:"unknown,omitempty"` // the layout version V int64 `json:"v,omitempty"` Verdict string `json:"verdict,omitempty"` @@ -477,12 +522,12 @@ type CandidatesByGroupValue struct { // VerdictsByDigestValue is one value of the state verdicts under the key . type VerdictsByDigestValue struct { // when (RFC 3339 time) - At string `json:"at,omitempty"` - Judge string `json:"judge,omitempty"` - Module string `json:"module"` - Problems []string `json:"problems,omitempty"` - State string `json:"state"` - Unknown []string `json:"unknown,omitempty"` + At *time.Time `json:"at,omitempty"` + Judge string `json:"judge,omitempty"` + Module string `json:"module"` + Problems []string `json:"problems,omitempty"` + State string `json:"state"` + Unknown []string `json:"unknown,omitempty"` // the layout version V int64 `json:"v,omitempty"` Warnings []string `json:"warnings,omitempty"` @@ -491,8 +536,8 @@ type VerdictsByDigestValue struct { // PredefinedByListValue is one value of the state predefined under the key list. type PredefinedByListValue struct { // when (RFC 3339 time) - At string `json:"at,omitempty"` - Commit string `json:"commit"` + At *time.Time `json:"at,omitempty"` + Commit string `json:"commit"` // the foundation's predefined list as kept List any `json:"list"` // the layout version @@ -521,7 +566,7 @@ type ConfigCandidatesByPullValueDeclaresValueValue struct { // ConfigCandidatesByPullValue is one value of the state config-candidates under the key . type ConfigCandidatesByPullValue struct { // when (RFC 3339 time) - At string `json:"at,omitempty"` + At *time.Time `json:"at,omitempty"` // module to key to declaration Declares map[string]map[string]ConfigCandidatesByPullValueDeclaresValueValue `json:"declares"` Head string `json:"head"` @@ -539,9 +584,9 @@ type PackagesByModuleValuePackagesItem struct { // PackagesByModuleValue is one value of the state packages under the key . type PackagesByModuleValue struct { // when (RFC 3339 time) - At string `json:"at,omitempty"` - Commit string `json:"commit"` - Dir string `json:"dir,omitempty"` + At *time.Time `json:"at,omitempty"` + Commit string `json:"commit"` + Dir string `json:"dir,omitempty"` // the Go module path Module string `json:"module"` Packages []PackagesByModuleValuePackagesItem `json:"packages"` @@ -561,9 +606,9 @@ type PackagesByPackageSeriesValueNewestContentsPackagesItem struct { // PackagesByPackageSeriesValueNewestContents is a type of the contract. type PackagesByPackageSeriesValueNewestContents struct { // when (RFC 3339 time) - At string `json:"at,omitempty"` - Commit string `json:"commit"` - Dir string `json:"dir,omitempty"` + At *time.Time `json:"at,omitempty"` + Commit string `json:"commit"` + Dir string `json:"dir,omitempty"` // the Go module path Module string `json:"module"` Packages []PackagesByPackageSeriesValueNewestContentsPackagesItem `json:"packages"` @@ -592,9 +637,9 @@ type PackagesByPackageSeriesValueNumberedContentsPackagesItem struct { // PackagesByPackageSeriesValueNumberedContents is a type of the contract. type PackagesByPackageSeriesValueNumberedContents struct { // when (RFC 3339 time) - At string `json:"at,omitempty"` - Commit string `json:"commit"` - Dir string `json:"dir,omitempty"` + At *time.Time `json:"at,omitempty"` + Commit string `json:"commit"` + Dir string `json:"dir,omitempty"` // the Go module path Module string `json:"module"` Packages []PackagesByPackageSeriesValueNumberedContentsPackagesItem `json:"packages"` @@ -617,7 +662,7 @@ type PackagesByPackageSeriesValueNumbered struct { // PackagesByPackageSeriesValue is one value of the state packages under the key .. type PackagesByPackageSeriesValue struct { // when (RFC 3339 time) - At string `json:"at,omitempty"` + At *time.Time `json:"at,omitempty"` GoModule string `json:"go-module,omitempty"` Name string `json:"name"` Newest *PackagesByPackageSeriesValueNewest `json:"newest,omitempty"` diff --git a/contracts/go/seats/meshcatalog/contract_test.go b/contracts/go/seats/meshcatalog/contract_test.go index 96bb633f..22bea547 100644 --- a/contracts/go/seats/meshcatalog/contract_test.go +++ b/contracts/go/seats/meshcatalog/contract_test.go @@ -17,13 +17,13 @@ func TestFixtures(t *testing.T) { decode func([]byte) (any, error) subjectIs *regexp.Regexp }{ - {name: "a manifest", subject: "", given: "{\"manifest\":\"{\\\"module\\\":\\\"nats\\\"}\",\"module\":\"nats\",\"v\":1}", wire: "{\"manifest\":\"{\\\"module\\\":\\\"nats\\\"}\",\"module\":\"nats\",\"v\":1}", + {name: "a manifest (xclip, read through mesh-catalog.module)", subject: "", given: "{\"manifest\":\"{\\\"build\\\":{\\\"artifacts\\\":[{\\\"binary\\\":\\\"xclip-tools\\\",\\\"from\\\":\\\"cmd/xclip-tools\\\",\\\"kind\\\":\\\"bundle\\\",\\\"language\\\":\\\"go\\\",\\\"loads\\\":[\\\"xclip-tools\\\"],\\\"name\\\":\\\"tools\\\",\\\"system\\\":\\\"arch\\\"}]},\\\"capabilities\\\":[\\\"package-manager\\\"],\\\"module\\\":\\\"xclip\\\",\\\"resources\\\":[{\\\"id\\\":\\\"package\\\",\\\"package\\\":\\\"xclip\\\",\\\"type\\\":\\\"package\\\"}],\\\"tools\\\":[\\\"xclip_copy\\\",\\\"xclip_paste\\\",\\\"xclip_targets\\\",\\\"xclip_session\\\"],\\\"version\\\":\\\"1\\\"}\",\"module\":\"xclip\",\"v\":1}", wire: "{\"manifest\":\"{\\\"build\\\":{\\\"artifacts\\\":[{\\\"binary\\\":\\\"xclip-tools\\\",\\\"from\\\":\\\"cmd/xclip-tools\\\",\\\"kind\\\":\\\"bundle\\\",\\\"language\\\":\\\"go\\\",\\\"loads\\\":[\\\"xclip-tools\\\"],\\\"name\\\":\\\"tools\\\",\\\"system\\\":\\\"arch\\\"}]},\\\"capabilities\\\":[\\\"package-manager\\\"],\\\"module\\\":\\\"xclip\\\",\\\"resources\\\":[{\\\"id\\\":\\\"package\\\",\\\"package\\\":\\\"xclip\\\",\\\"type\\\":\\\"package\\\"}],\\\"tools\\\":[\\\"xclip_copy\\\",\\\"xclip_paste\\\",\\\"xclip_targets\\\",\\\"xclip_session\\\"],\\\"version\\\":\\\"1\\\"}\",\"module\":\"xclip\",\"v\":1}", decode: func(b []byte) (any, error) { var v ManifestsByDigestValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, - {name: "a module", subject: "", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"fp2\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"repository\":\"novox/mesh-catalog\",\"v\":1}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"fp2\":\"src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\",\"repository\":\"novox/mesh-catalog\",\"v\":1}", + {name: "a module (xclip, read through mesh-catalog.modules; the inputs and toolchains no tool reads are not here)", subject: "", given: "{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp2\":\"src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56\",\"path\":\"modules/xclip\",\"repository\":\"novox/mesh-catalog\",\"v\":1}", wire: "{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp2\":\"src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56\",\"path\":\"modules/xclip\",\"repository\":\"novox/mesh-catalog\",\"v\":1}", decode: func(b []byte) (any, error) { var v ModulesByModuleValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, {name: "a candidate", subject: "", given: "{\"base\":3,\"group\":\"feat/registry\",\"heads\":\"0123456789ab\",\"pulls\":[{\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"modules\":[\"nats\"],\"number\":1,\"repository\":\"novox/mesh-sdk\"}],\"v\":1}", wire: "{\"base\":3,\"group\":\"feat/registry\",\"heads\":\"0123456789ab\",\"pulls\":[{\"head\":\"cccccccccccccccccccccccccccccccccccccccc\",\"modules\":[\"nats\"],\"number\":1,\"repository\":\"novox/mesh-sdk\"}],\"v\":1}", decode: func(b []byte) (any, error) { var v CandidatesByGroupValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, - {name: "a verdict", subject: "", given: "{\"judge\":\"trunk\",\"module\":\"nats\",\"state\":\"accepted\",\"v\":1}", wire: "{\"judge\":\"trunk\",\"module\":\"nats\",\"state\":\"accepted\",\"v\":1}", + {name: "a refused verdict (nats, read through the indexer's verdicts tool)", subject: "", given: "{\"at\":\"2026-11-04T18:51:12.614583047+01:00\",\"judge\":\"exe:661e6fb424d7ffea\",\"module\":\"nats\",\"problems\":[\"this is not a module manifest: a state is either a name or {name, history, ttl-seconds, per-machine, key-ttl}: json: unknown field \\\"read-only\\\" (read without state[2].read-only)\"],\"state\":\"refused\"}", wire: "{\"at\":\"2026-11-04T18:51:12.614583047+01:00\",\"judge\":\"exe:661e6fb424d7ffea\",\"module\":\"nats\",\"problems\":[\"this is not a module manifest: a state is either a name or {name, history, ttl-seconds, per-machine, key-ttl}: json: unknown field \\\"read-only\\\" (read without state[2].read-only)\"],\"state\":\"refused\"}", decode: func(b []byte) (any, error) { var v VerdictsByDigestValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, {name: "the predefined list", subject: "", given: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"list\":{\"streams\":[]},\"v\":1}", wire: "{\"commit\":\"cccccccccccccccccccccccccccccccccccccccc\",\"list\":{\"streams\":[]},\"v\":1}", decode: func(b []byte) (any, error) { var v PredefinedByListValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, @@ -41,6 +41,12 @@ func TestFixtures(t *testing.T) { err := json.Unmarshal(b, &v) return v, err }, subjectIs: nil}, + {name: "a module with its toolchain", subject: "", given: "{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp2\":\"src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56\",\"repository\":\"novox/mesh-catalog\",\"toolchains\":{\"go\":{\"language\":\"go\",\"recipe\":\"1\",\"version\":\"1.26.0\"}},\"v\":1}", wire: "{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp2\":\"src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56\",\"repository\":\"novox/mesh-catalog\",\"toolchains\":{\"go\":{\"language\":\"go\",\"recipe\":\"1\",\"version\":\"1.26.0\"}},\"v\":1}", + decode: func(b []byte) (any, error) { var v ModulesByModuleValue; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + {name: "the modules verb (captured: the first three modules)", subject: "", given: "{\"modules\":[{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp\":\"src2:5e4a1b4ad4ea6175c05e4655ce58aeb957547149d4c9805eb27636efd50c1c87\",\"module\":\"adwaita\",\"path\":\"modules/adwaita\",\"repository\":\"novox/mesh-catalog\"},{\"commit\":\"b112adcecc41d18f54190cbd2fc864199b70c518\",\"fp\":\"src2:7dd0db8e98224f46121a5ae05c0b9c5a430eff531a5120aa40b1a59237853a3f\",\"module\":\"amqp-email-forwarder\",\"path\":\".\",\"repository\":\"jschoubben/amqp-email-forwarder\"},{\"commit\":\"dd458cb155f5f5fa3ed824a23728e444be5b156a\",\"fp\":\"src2:a98f8152f0a837dd5ba883a15efaf110ba88100193157e4bdb1a93ba55209371\",\"module\":\"artifact-store-tools\",\"path\":\"modules/artifact-store-tools\",\"repository\":\"novox/mesh-catalog\"}]}", wire: "{\"modules\":[{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp\":\"src2:5e4a1b4ad4ea6175c05e4655ce58aeb957547149d4c9805eb27636efd50c1c87\",\"module\":\"adwaita\",\"path\":\"modules/adwaita\",\"repository\":\"novox/mesh-catalog\"},{\"commit\":\"b112adcecc41d18f54190cbd2fc864199b70c518\",\"fp\":\"src2:7dd0db8e98224f46121a5ae05c0b9c5a430eff531a5120aa40b1a59237853a3f\",\"module\":\"amqp-email-forwarder\",\"path\":\".\",\"repository\":\"jschoubben/amqp-email-forwarder\"},{\"commit\":\"dd458cb155f5f5fa3ed824a23728e444be5b156a\",\"fp\":\"src2:a98f8152f0a837dd5ba883a15efaf110ba88100193157e4bdb1a93ba55209371\",\"module\":\"artifact-store-tools\",\"path\":\"modules/artifact-store-tools\",\"repository\":\"novox/mesh-catalog\"}]}", + decode: func(b []byte) (any, error) { var v ModulesAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, + {name: "the module verb (captured: xclip)", subject: "", given: "{\"module\":{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp\":\"src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56\",\"manifest\":{\"build\":{\"artifacts\":[{\"binary\":\"xclip-tools\",\"from\":\"cmd/xclip-tools\",\"kind\":\"bundle\",\"language\":\"go\",\"loads\":[\"xclip-tools\"],\"name\":\"tools\",\"system\":\"arch\"}]},\"capabilities\":[\"package-manager\"],\"module\":\"xclip\",\"resources\":[{\"id\":\"package\",\"package\":\"xclip\",\"type\":\"package\"}],\"tools\":[\"xclip_copy\",\"xclip_paste\",\"xclip_targets\",\"xclip_session\"],\"version\":\"1\"},\"module\":\"xclip\",\"path\":\"modules/xclip\",\"repository\":\"novox/mesh-catalog\"}}", wire: "{\"module\":{\"commit\":\"f469eb387a3015569d9b16c66ed418e9dd098f64\",\"fp\":\"src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56\",\"manifest\":{\"build\":{\"artifacts\":[{\"binary\":\"xclip-tools\",\"from\":\"cmd/xclip-tools\",\"kind\":\"bundle\",\"language\":\"go\",\"loads\":[\"xclip-tools\"],\"name\":\"tools\",\"system\":\"arch\"}]},\"capabilities\":[\"package-manager\"],\"module\":\"xclip\",\"resources\":[{\"id\":\"package\",\"package\":\"xclip\",\"type\":\"package\"}],\"tools\":[\"xclip_copy\",\"xclip_paste\",\"xclip_targets\",\"xclip_session\"],\"version\":\"1\"},\"module\":\"xclip\",\"path\":\"modules/xclip\",\"repository\":\"novox/mesh-catalog\"}}", + decode: func(b []byte) (any, error) { var v ModuleAnswer; err := json.Unmarshal(b, &v); return v, err }, subjectIs: nil}, } for _, c := range cases { v, err := c.decode([]byte(c.given)) diff --git a/contracts/seats/mesh-catalog/fixtures/states.json b/contracts/seats/mesh-catalog/fixtures/states.json index 9d902dc9..0ad6086b 100644 --- a/contracts/seats/mesh-catalog/fixtures/states.json +++ b/contracts/seats/mesh-catalog/fixtures/states.json @@ -1,21 +1,22 @@ [ { - "name": "a manifest", + "name": "a manifest (xclip, read through mesh-catalog.module)", "of": "state:manifests/", "given": { "v": 1, - "module": "nats", - "manifest": "{\"module\":\"nats\"}" + "module": "xclip", + "manifest": "{\"build\":{\"artifacts\":[{\"binary\":\"xclip-tools\",\"from\":\"cmd/xclip-tools\",\"kind\":\"bundle\",\"language\":\"go\",\"loads\":[\"xclip-tools\"],\"name\":\"tools\",\"system\":\"arch\"}]},\"capabilities\":[\"package-manager\"],\"module\":\"xclip\",\"resources\":[{\"id\":\"package\",\"package\":\"xclip\",\"type\":\"package\"}],\"tools\":[\"xclip_copy\",\"xclip_paste\",\"xclip_targets\",\"xclip_session\"],\"version\":\"1\"}" } }, { - "name": "a module", + "name": "a module (xclip, read through mesh-catalog.modules; the inputs and toolchains no tool reads are not here)", "of": "state:modules/", "given": { "v": 1, "repository": "novox/mesh-catalog", - "commit": "cccccccccccccccccccccccccccccccccccccccc", - "fp2": "src2:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "commit": "f469eb387a3015569d9b16c66ed418e9dd098f64", + "path": "modules/xclip", + "fp2": "src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56" } }, { @@ -39,13 +40,16 @@ } }, { - "name": "a verdict", + "name": "a refused verdict (nats, read through the indexer's verdicts tool)", "of": "state:verdicts/", "given": { - "v": 1, "module": "nats", - "state": "accepted", - "judge": "trunk" + "state": "refused", + "problems": [ + "this is not a module manifest: a state is either a name or {name, history, ttl-seconds, per-machine, key-ttl}: json: unknown field \"read-only\" (read without state[2].read-only)" + ], + "judge": "exe:661e6fb424d7ffea", + "at": "2026-11-04T18:51:12.614583047+01:00" } }, { @@ -101,5 +105,99 @@ "name": "go-keys", "series": "0.1" } + }, + { + "name": "a module with its toolchain", + "of": "state:modules/", + "given": { + "v": 1, + "repository": "novox/mesh-catalog", + "commit": "f469eb387a3015569d9b16c66ed418e9dd098f64", + "fp2": "src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56", + "toolchains": { + "go": { + "language": "go", + "version": "1.26.0", + "recipe": "1" + } + } + } + }, + { + "name": "the modules verb (captured: the first three modules)", + "of": "verb:modules.answer", + "given": { + "modules": [ + { + "commit": "f469eb387a3015569d9b16c66ed418e9dd098f64", + "fp": "src2:5e4a1b4ad4ea6175c05e4655ce58aeb957547149d4c9805eb27636efd50c1c87", + "module": "adwaita", + "path": "modules/adwaita", + "repository": "novox/mesh-catalog" + }, + { + "commit": "b112adcecc41d18f54190cbd2fc864199b70c518", + "fp": "src2:7dd0db8e98224f46121a5ae05c0b9c5a430eff531a5120aa40b1a59237853a3f", + "module": "amqp-email-forwarder", + "path": ".", + "repository": "jschoubben/amqp-email-forwarder" + }, + { + "commit": "dd458cb155f5f5fa3ed824a23728e444be5b156a", + "fp": "src2:a98f8152f0a837dd5ba883a15efaf110ba88100193157e4bdb1a93ba55209371", + "module": "artifact-store-tools", + "path": "modules/artifact-store-tools", + "repository": "novox/mesh-catalog" + } + ] + } + }, + { + "name": "the module verb (captured: xclip)", + "of": "verb:module.answer", + "given": { + "module": { + "commit": "f469eb387a3015569d9b16c66ed418e9dd098f64", + "fp": "src2:b427bdde1f100e2f52490cfa9df0c5112dd3700226b4892349f0c14a15a4af56", + "manifest": { + "build": { + "artifacts": [ + { + "binary": "xclip-tools", + "from": "cmd/xclip-tools", + "kind": "bundle", + "language": "go", + "loads": [ + "xclip-tools" + ], + "name": "tools", + "system": "arch" + } + ] + }, + "capabilities": [ + "package-manager" + ], + "module": "xclip", + "resources": [ + { + "id": "package", + "package": "xclip", + "type": "package" + } + ], + "tools": [ + "xclip_copy", + "xclip_paste", + "xclip_targets", + "xclip_session" + ], + "version": "1" + }, + "module": "xclip", + "path": "modules/xclip", + "repository": "novox/mesh-catalog" + } + } } ] diff --git a/contracts/seats/mesh-catalog/seat.json b/contracts/seats/mesh-catalog/seat.json index d036149a..9fb8846c 100644 --- a/contracts/seats/mesh-catalog/seat.json +++ b/contracts/seats/mesh-catalog/seat.json @@ -16,7 +16,47 @@ }, "answer": { "type": "object", - "description": "what modules answers, as its description says" + "description": "every module the trunk holds, by name", + "properties": { + "modules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "module": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "path": { + "type": "string", + "description": "the module's directory in its repository, '.' for a root" + }, + "commit": { + "type": "string", + "description": "the merge commit it was last changed at" + }, + "fp": { + "type": "string", + "description": "its fingerprint (src2: and 64 hex digits); absent when it has none" + }, + "none": { + "type": "string", + "description": "why it has none" + } + }, + "required": [ + "module", + "repository", + "commit" + ] + } + } + }, + "required": [ + "modules" + ] } }, { @@ -37,7 +77,48 @@ }, "answer": { "type": "object", - "description": "what module answers, as its description says" + "description": "the module whole", + "properties": { + "module": { + "type": "object", + "properties": { + "module": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "path": { + "type": "string", + "description": "the module's directory in its repository, '.' for a root" + }, + "commit": { + "type": "string", + "description": "the merge commit it was last changed at" + }, + "fp": { + "type": "string", + "description": "its fingerprint (src2: and 64 hex digits); absent when it has none" + }, + "none": { + "type": "string", + "description": "why it has none" + }, + "manifest": { + "type": "object", + "description": "the module's manifest as the trunk holds it" + } + }, + "required": [ + "module", + "repository", + "commit" + ] + } + }, + "required": [ + "module" + ] } }, { @@ -84,7 +165,7 @@ }, { "name": "seat-definitions", - "description": "The seat list (ADR 0636 §4): with no seat, every trunk seat with its digest and the revision of the list; with a seat, that trunk definition resolved with the parts it includes. Reads only.", + "description": "The seat list (ADR 0636 \u00a74): with no seat, every trunk seat with its digest and the revision of the list; with a seat, that trunk definition resolved with the parts it includes. Reads only.", "optional": true, "input": { "properties": { @@ -163,7 +244,7 @@ } } ], - "description": "The catalog of the mesh: every module the trunk holds with its manifest, fingerprint and verdict, the packages published, and the seat list (ADR 0636 §1, §4).", + "description": "The catalog of the mesh: every module the trunk holds with its manifest, fingerprint and verdict, the packages published, and the seat list (ADR 0636 \u00a71, \u00a74).", "family": { "name": "mesh-catalog.events", "max-age-days": 7 @@ -344,8 +425,9 @@ "toolchains": { "type": "object", "additionalProperties": { - "description": "toolchain used" - } + "$ref": "#/defs/ToolchainUsed" + }, + "description": "by language: the toolchain FP2 was computed with" }, "paths": { "type": "object", @@ -543,7 +625,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" } }, "required": [ @@ -576,7 +659,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" }, "list": { "description": "the foundation's predefined list as kept" @@ -670,7 +754,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" } }, "required": [ @@ -735,7 +820,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" } }, "required": [ @@ -830,7 +916,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" } }, "required": [ @@ -904,7 +991,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" } }, "required": [ @@ -921,7 +1009,8 @@ }, "at": { "type": "string", - "description": "when (RFC 3339 time)" + "description": "when (RFC 3339 time)", + "format": "date-time" } }, "required": [ @@ -935,5 +1024,29 @@ "description": "the published packages", "history": 5 } - ] + ], + "defs": { + "ToolchainUsed": { + "type": "object", + "description": "a toolchain a fingerprint was computed with (ADR 0405 clause 7)", + "properties": { + "language": { + "type": "string" + }, + "version": { + "type": "string", + "description": "the installed toolchain's version" + }, + "recipe": { + "type": "string", + "description": "the build module's recipe version" + } + }, + "required": [ + "language", + "version", + "recipe" + ] + } + } } diff --git a/contracts/ts/seats/meshcatalog/src/index.ts b/contracts/ts/seats/meshcatalog/src/index.ts index 91fdcf23..4b590fe3 100644 --- a/contracts/ts/seats/meshcatalog/src/index.ts +++ b/contracts/ts/seats/meshcatalog/src/index.ts @@ -156,12 +156,36 @@ export function parsePackagesByPackageSeriesKey(key: string): { packagePart: str return { packagePart, series }; } +/** a toolchain a fingerprint was computed with (ADR 0405 clause 7) */ +export interface ToolchainUsed { + "language": string; + /** the build module's recipe version */ + "recipe": string; + /** the installed toolchain's version */ + "version": string; +} + /** is what modules takes. */ export interface ModulesInput { } +export interface ModulesAnswerModulesItem { + /** the merge commit it was last changed at */ + "commit": string; + /** its fingerprint (src2: and 64 hex digits); absent when it has none */ + "fp"?: string; + "module": string; + /** why it has none */ + "none"?: string; + /** the module's directory in its repository, '.' for a root */ + "path"?: string; + "repository": string; +} + /** is what modules answers. */ -export type ModulesAnswer = Record; +export interface ModulesAnswer { + "modules": ModulesAnswerModulesItem[]; +} /** is what module takes. */ export interface ModuleInput { @@ -169,8 +193,25 @@ export interface ModuleInput { "module": string; } +export interface ModuleAnswerModule { + /** the merge commit it was last changed at */ + "commit": string; + /** its fingerprint (src2: and 64 hex digits); absent when it has none */ + "fp"?: string; + /** the module's manifest as the trunk holds it */ + "manifest"?: Record; + "module": string; + /** why it has none */ + "none"?: string; + /** the module's directory in its repository, '.' for a root */ + "path"?: string; + "repository": string; +} + /** is what module answers. */ -export type ModuleAnswer = Record; +export interface ModuleAnswer { + "module": ModuleAnswerModule; +} /** is what provides takes. */ export interface ProvidesInput { @@ -279,7 +320,8 @@ export interface ModulesByModuleValue { "repository": string; /** the source revision */ "src"?: number; - "toolchains"?: Record; + /** by language: the toolchain FP2 was computed with */ + "toolchains"?: Record; "unknown"?: string[]; /** the layout version */ "v"?: number;