indexer, mesh-catalog contract: manifest-accepted carries problems, the validator's strings

Builds: design 47 G §692, §668

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-11 22:48:51 +01:00
parent aa34cd20dd
commit e089fd9c3c
5 changed files with 41 additions and 2 deletions
@@ -1428,6 +1428,8 @@ type ManifestAcceptedEvent struct {
Digest string `json:"digest"`
Judge string `json:"judge"`
Module string `json:"module"`
// each problem the indexer's re-judgement finds in a manifest it keeps accepted because its digest is unchanged: the manifest validator's strings, the same items its verdict writes as warnings, in the same order; an empty list when none (design 47 G section 668, 692)
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"`
+9 -1
View File
@@ -678,6 +678,13 @@
"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"
},
"description": "each problem the indexer's re-judgement finds in a manifest it keeps accepted because its digest is unchanged: the manifest validator's strings, the same items its verdict writes as warnings, in the same order; an empty list when none (design 47 G section 668, 692)"
},
"bus-state": {
"type": "array",
"items": {
@@ -717,7 +724,8 @@
"module",
"digest",
"judge",
"bus-state"
"bus-state",
"problems"
]
}
},
+2
View File
@@ -878,6 +878,8 @@ export interface ManifestAcceptedEvent {
"digest": string;
"judge": string;
"module": string;
/** each problem the indexer's re-judgement finds in a manifest it keeps accepted because its digest is unchanged: the manifest validator's strings, the same items its verdict writes as warnings, in the same order; an empty list when none (design 47 G section 668, 692) */
"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;
@@ -0,0 +1,25 @@
package index
import (
"encoding/json"
"reflect"
"strings"
"testing"
"git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog"
)
// Design 47 G §668, §692: manifest-accepted's problems are the validator's strings, the same the verdict writes as
// warnings, in the same order; a mended manifest says an empty list, never null.
func TestManifestAcceptedProblemsAreTheVerdictsWarnings(t *testing.T) {
warnings := []string{`requires "amqp", which no module provides`, "a second problem"}
got := acceptedOf("sha256:aa", meshcatalog.VerdictsByDigestValue{Module: "m", Judge: "j", Warnings: warnings}, 3, []byte(`{"module":"m","version":"1.0"}`))
if !reflect.DeepEqual(got.Problems, warnings) {
t.Errorf("problems %v, want the verdict's warnings %v", got.Problems, warnings)
}
mended := acceptedOf("sha256:bb", meshcatalog.VerdictsByDigestValue{Module: "m", Judge: "j"}, 4, []byte(`{"module":"m","version":"2.0"}`))
raw, _ := json.Marshal(mended)
if !strings.Contains(string(raw), `"problems":[]`) {
t.Errorf("a mended manifest's event is %s, want an empty problems list", raw)
}
}
@@ -20,7 +20,9 @@ func refusedOf(digest string, v meshcatalog.VerdictsByDigestValue) meshcatalog.M
// acceptedEvent is the body of manifest-accepted for the verdict v accepting the manifest m of digest, its bus-state
// entries whole (novox/hq ADR 0595 §4); an empty list when m asks for none.
func acceptedEvent(digest string, v meshcatalog.VerdictsByDigestValue, m catalogue.Manifest) meshcatalog.ManifestAcceptedEvent {
return meshcatalog.ManifestAcceptedEvent{V: keys.Version, Module: v.Module, Digest: digest, Judge: v.Judge, BusState: busStateOf(m.BusState)}
// problems are the manifest validator's strings, the verdict's warnings in their order, an empty list when none (design 47 G §668, §692).
problems := append([]string{}, v.Warnings...)
return meshcatalog.ManifestAcceptedEvent{V: keys.Version, Module: v.Module, Digest: digest, Judge: v.Judge, BusState: busStateOf(m.BusState), Problems: problems}
}
// busStateOf is the manifest's bus-state entries in the event's form (the same JSON).