From c16b38bd8349d3463ef63bb8541661d499038d82 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 5 Nov 2026 15:10:03 +0100 Subject: [PATCH] mesh-delivery-contracts: the seat mesh-catalog's events manifest-accepted and manifest-refused, said on the verdicts of a manifest (ADR 0604, ADR 0578; issue 1966) Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i --- contracts/go/seats/meshcatalog/contract.go | 42 +++++++- contracts/seats/mesh-catalog/seat.json | 101 ++++++++++++++++++++ contracts/ts/seats/meshcatalog/src/index.ts | 37 +++++++ 3 files changed, 179 insertions(+), 1 deletion(-) diff --git a/contracts/go/seats/meshcatalog/contract.go b/contracts/go/seats/meshcatalog/contract.go index 728a09b0..ce517dcb 100644 --- a/contracts/go/seats/meshcatalog/contract.go +++ b/contracts/go/seats/meshcatalog/contract.go @@ -25,6 +25,8 @@ const ( const ( EventSeatDefinitionChanged = "seat-definition-changed" EventSeatDefinitionRemoved = "seat-definition-removed" + EventManifestAccepted = "manifest-accepted" + EventManifestRefused = "manifest-refused" ) // Verbs is every verb the seat serves, in its definition's order: a new copy each call. @@ -34,7 +36,7 @@ func Verbs() []string { // Events is every event published on the seat's subject: a new copy each call. func Events() []string { - return []string{EventSeatDefinitionChanged, EventSeatDefinitionRemoved} + return []string{EventSeatDefinitionChanged, EventSeatDefinitionRemoved, EventManifestAccepted, EventManifestRefused} } // Family is where the seat's events are kept: the shared events stream, filtered to the seat's subjects. @@ -49,6 +51,12 @@ const SubjectSeatDefinitionChanged = "mesh.seat.mesh-catalog.event.seat-definiti // SubjectSeatDefinitionRemoved is where seat-definition-removed is published. const SubjectSeatDefinitionRemoved = "mesh.seat.mesh-catalog.event.seat-definition-removed" +// SubjectManifestAccepted is where manifest-accepted is published. +const SubjectManifestAccepted = "mesh.seat.mesh-catalog.event.manifest-accepted" + +// SubjectManifestRefused is where manifest-refused is published. +const SubjectManifestRefused = "mesh.seat.mesh-catalog.event.manifest-refused" + const ( StateManifests = "manifests" StateModules = "modules" @@ -436,6 +444,38 @@ type SeatDefinitionRemovedEvent struct { Seat string `json:"seat"` } +// ManifestAcceptedEventBusStateItem is a type of the contract. +type ManifestAcceptedEventBusStateItem struct { + Configuration map[string]any `json:"configuration,omitempty"` + Name string `json:"name"` + Options map[string]any `json:"options,omitempty"` + Storage string `json:"storage"` + Template string `json:"template,omitempty"` + Types []map[string]any `json:"types,omitempty"` +} + +// ManifestAcceptedEvent is the body of the event manifest-accepted. +type ManifestAcceptedEvent struct { + BusState []ManifestAcceptedEventBusStateItem `json:"bus-state"` + Digest string `json:"digest"` + Judge string `json:"judge"` + Module string `json:"module"` + // the indexer's revision of the verdict it says; a reader asks its first view again on a gap in it; zero from an indexer that does not say it + Revision int64 `json:"revision,omitempty"` + V int64 `json:"v"` +} + +// ManifestRefusedEvent is the body of the event manifest-refused. +type ManifestRefusedEvent struct { + Digest string `json:"digest"` + Judge string `json:"judge"` + Module string `json:"module"` + Problems []string `json:"problems"` + // the indexer's revision of the verdict it says; a reader asks its first view again on a gap in it; zero from an indexer that does not say it + Revision int64 `json:"revision,omitempty"` + V int64 `json:"v"` +} + // ManifestsByDigestValue is one value of the state manifests under the key . type ManifestsByDigestValue struct { // the manifest, UTF-8 JSON text diff --git a/contracts/seats/mesh-catalog/seat.json b/contracts/seats/mesh-catalog/seat.json index 9fb8846c..08301037 100644 --- a/contracts/seats/mesh-catalog/seat.json +++ b/contracts/seats/mesh-catalog/seat.json @@ -286,6 +286,107 @@ "seat" ] } + }, + { + "name": "manifest-accepted", + "body": { + "type": "object", + "properties": { + "v": { + "type": "integer" + }, + "module": { + "type": "string" + }, + "digest": { + "type": "string" + }, + "judge": { + "type": "string" + }, + "revision": { + "type": "integer", + "description": "the indexer's revision of the verdict it says; a reader asks its first view again on a gap in it; zero from an indexer that does not say it" + }, + "bus-state": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "storage": { + "type": "string" + }, + "template": { + "type": "string" + }, + "options": { + "type": "object" + }, + "configuration": { + "type": "object" + }, + "types": { + "type": "array", + "items": { + "type": "object" + } + } + }, + "required": [ + "name", + "storage" + ] + } + } + }, + "required": [ + "v", + "module", + "digest", + "judge", + "bus-state" + ] + } + }, + { + "name": "manifest-refused", + "body": { + "type": "object", + "properties": { + "v": { + "type": "integer" + }, + "module": { + "type": "string" + }, + "digest": { + "type": "string" + }, + "judge": { + "type": "string" + }, + "revision": { + "type": "integer", + "description": "the indexer's revision of the verdict it says; a reader asks its first view again on a gap in it; zero from an indexer that does not say it" + }, + "problems": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "v", + "module", + "digest", + "judge", + "problems" + ] + } } ], "states": [ diff --git a/contracts/ts/seats/meshcatalog/src/index.ts b/contracts/ts/seats/meshcatalog/src/index.ts index 4b590fe3..92b3b5a4 100644 --- a/contracts/ts/seats/meshcatalog/src/index.ts +++ b/contracts/ts/seats/meshcatalog/src/index.ts @@ -15,6 +15,8 @@ export const verbs = { export const events = { seatDefinitionChanged: "seat-definition-changed", seatDefinitionRemoved: "seat-definition-removed", + manifestAccepted: "manifest-accepted", + manifestRefused: "manifest-refused", } as const; export const family = { name: "mesh-catalog.events", maxAgeDays: 7 } as const; @@ -23,6 +25,10 @@ export const seatDefinitionChangedSubject = "mesh.seat.mesh-catalog.event.seat-d export const seatDefinitionRemovedSubject = "mesh.seat.mesh-catalog.event.seat-definition-removed"; +export const manifestAcceptedSubject = "mesh.seat.mesh-catalog.event.manifest-accepted"; + +export const manifestRefusedSubject = "mesh.seat.mesh-catalog.event.manifest-refused"; + export const states = { manifests: "manifests", modules: "modules", @@ -277,6 +283,37 @@ export interface SeatDefinitionRemovedEvent { "seat": string; } +export interface ManifestAcceptedEventBusStateItem { + "configuration"?: Record; + "name": string; + "options"?: Record; + "storage": string; + "template"?: string; + "types"?: Record[]; +} + +/** is the body of the event manifest-accepted. */ +export interface ManifestAcceptedEvent { + "bus-state": ManifestAcceptedEventBusStateItem[]; + "digest": string; + "judge": string; + "module": string; + /** the indexer's revision of the verdict it says; a reader asks its first view again on a gap in it; zero from an indexer that does not say it */ + "revision"?: number; + "v": number; +} + +/** is the body of the event manifest-refused. */ +export interface ManifestRefusedEvent { + "digest": string; + "judge": string; + "module": string; + "problems": string[]; + /** the indexer's revision of the verdict it says; a reader asks its first view again on a gap in it; zero from an indexer that does not say it */ + "revision"?: number; + "v": number; +} + /** is one value of the state manifests under the key . */ export interface ManifestsByDigestValue { /** the manifest, UTF-8 JSON text */