Keep every strict read of a manifest in the indexer's judge, and add no test to the budget

Issue 1585, S5-S8: the indexer's fingerprint reads go through judge.ForInputs, so judge/ is the one place in
mesh-delivery that calls mesh-sdk's rules; the command's request judging moves into judge.Request, tested in the
judge's table; two predefined tests become one.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-01 02:21:32 +01:00
parent 5b6602544e
commit 4f6f38e16a
8 changed files with 74 additions and 89 deletions
@@ -12,8 +12,6 @@ import (
"fmt"
"io"
"os"
"sort"
"strings"
"git.novox.be/novox/mesh-sdk/go/composer"
@@ -23,9 +21,6 @@ import (
// Package is this command's import path in the indexer's Go module (the directory delivery.ComposeJob's Dir names).
const Package = "mesh-delivery-indexer/cmd/mesh-judge"
// Between names, in a case's verdict, the problems between manifests that name no module of the case.
const Between = "(between manifests)"
func main() { os.Exit(run(os.Args[1:], os.Stdin, os.Stdout, os.Stderr)) }
func run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
@@ -51,7 +46,7 @@ func run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
fmt.Fprintln(stderr, "mesh-judge:", err)
return 1
}
v, err := Judge(r)
v, err := judge.Request(r)
if err != nil {
fmt.Fprintln(stderr, "mesh-judge:", err)
return 1
@@ -64,39 +59,3 @@ func run(args []string, stdin io.Reader, stdout, stderr io.Writer) int {
fmt.Fprintln(stdout, string(out))
return 0
}
// Judge judges every case of r: each case's manifests as one catalogue (judge.Shelf), every manifest accepted or
// refused with its problems; problems between manifests that name none of them under Between. The verdict's SDK
// names this judge (judge.Identity). A manifest left as a digest is refused as a request it cannot run.
func Judge(r composer.Request) (composer.Verdict, error) {
v := composer.Verdict{V: composer.Version, SDK: judge.Identity()}
seen := map[string]bool{}
for _, c := range r.Cases {
if seen[c.Name] {
return composer.Verdict{}, fmt.Errorf("the case %q is named twice", c.Name)
}
seen[c.Name] = true
raws := map[string][]byte{}
for name, m := range c.Manifests {
if len(m.Raw) == 0 {
return composer.Verdict{}, fmt.Errorf("%w: %s (digest %s)", composer.ErrUnfilled, name, m.Digest)
}
raws[name] = m.Raw
}
refused, unnamed := judge.Shelf(raws, r.Predefined, 0)
cv := composer.CaseVerdict{Name: c.Name, Manifests: map[string]composer.ManifestRead{}}
for name := range raws {
if problems := refused[name]; len(problems) > 0 {
cv.Manifests[name] = composer.ManifestRead{Refused: strings.Join(problems, "\n")}
continue
}
cv.Manifests[name] = composer.ManifestRead{Accepted: true}
}
if len(unnamed) > 0 {
sort.Strings(unnamed)
cv.Manifests[Between] = composer.ManifestRead{Refused: strings.Join(unnamed, "\n")}
}
v.Cases = append(v.Cases, cv)
}
return v, nil
}
@@ -1,40 +0,0 @@
package main
import (
"bytes"
"encoding/json"
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/composer"
)
// The command the checker runs (novox/hq ADR 0578 §2): a composer request in, one line of a composer verdict out, each
// manifest accepted or refused with its problems; a request it cannot run exits non-zero.
func TestTheCommandJudgesARequest(t *testing.T) {
r := composer.Request{V: composer.Version, Cases: []composer.Case{{Name: "change", Manifests: map[string]composer.Manifest{
"a": {Raw: json.RawMessage(`{"module":"a","version":"1"}`)},
"b": {Raw: json.RawMessage(`{"module":"b","version":"1","requires":["amqp"]}`)},
}}}}
raw, _ := json.Marshal(r)
var out, errs bytes.Buffer
if code := run(nil, bytes.NewReader(raw), &out, &errs); code != 0 {
t.Fatalf("exit %d: %s", code, errs.String())
}
var v composer.Verdict
if err := json.Unmarshal(out.Bytes(), &v); err != nil || v.V != composer.Version || len(v.Cases) != 1 || v.SDK == "" {
t.Fatalf("verdict %s: %v", out.String(), err)
}
c := v.Cases[0]
if !c.Manifests["a"].Accepted || c.Manifests["b"].Accepted || !strings.Contains(c.Manifests["b"].Refused, `requires "amqp"`) {
t.Fatalf("case: %+v", c)
}
r.Cases[0].Manifests["c"] = composer.Manifest{Digest: strings.Repeat("a", 64)}
raw, _ = json.Marshal(r)
if code := run(nil, bytes.NewReader(raw), &out, &errs); code == 0 {
t.Fatal("a manifest left as a digest was judged")
}
if code := run(nil, strings.NewReader("{"), &out, &errs); code == 0 {
t.Fatal("a request that is no JSON was judged")
}
}
@@ -9,6 +9,8 @@ import (
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/delivery"
"mesh-delivery-indexer/judge"
)
// The reasons a module has no fingerprint of the new form while the indexer writes none for any module (novox/hq
@@ -67,7 +69,7 @@ func inputsOf(module, raw, tree string, locks map[string]string, base baseFP) mo
// gives the merge's value (novox/hq ADR 0499 clause 2); a message that does not carry the object of each such path gives it
// none, naming the paths (clause 3). Every other module keeps its directory's tree, whatever objects are given.
func inputsOfNamed(module, raw, tree string, locks, objects map[string]string, base baseFP) moduleInputs {
m, err := catalogue.ParseManifestForInputs([]byte(raw))
m, err := judge.ForInputs([]byte(raw))
if err != nil {
return moduleInputs{None2: None2Unreadable + err.Error()}
}
@@ -7,8 +7,9 @@ import (
"slices"
"strings"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/delivery"
"mesh-delivery-indexer/judge"
)
// applyMerged writes, for each module whose manifest the merged message carries (each directory of the merge commit that
@@ -153,7 +154,7 @@ func (ix *Indexer) namedObjects(ctx context.Context, f delivery.Forge) (map[stri
objects := map[string]map[string]string{}
need := map[string][]string{}
for dir, raw := range f.Manifests {
m, err := catalogue.ParseManifestForInputs([]byte(raw))
m, err := judge.ForInputs([]byte(raw))
if err != nil {
continue // inputsOfNamed says why
}
@@ -19,9 +19,7 @@ func TestAManifestFallingBackToAPredefinedKeyIsRead(t *testing.T) { // 1751
t.Errorf("%s: inputs = %+v, want the manifest read and its inputs kept", module, in)
}
}
}
func TestAPredefinedKeyOfAnotherTypeThanItsValueIsStillRefused(t *testing.T) { // 1751: the read judges what it can
// A predefined key of another type than its value is still refused: the read judges what it can.
raw := strings.Replace(fixture(t, "catalogue-835bf22b-xterm"), `"predefined": "font-size"`, `"predefined": "font-size", "trusted": "yes"`, 1)
if in := inputsOf("xterm", raw, "newtree", nil, func(string) (string, string) { return "", "none" }); in.Kept != nil {
t.Errorf("inputs = %+v, want a manifest the catalogue refuses still refused", in)
@@ -10,6 +10,8 @@ import (
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/delivery"
"mesh-delivery-indexer/judge"
)
// The new-form fingerprint of a module is written, and written again with no merge, when what it is of changes
@@ -385,7 +387,7 @@ func (ix *Indexer) manifestRaw(ctx context.Context, digest string) (string, cata
if err != nil {
return "", catalogue.Manifest{}, err
}
m, err := catalogue.ParseManifestForInputs([]byte(kept.JSON))
m, err := judge.ForInputs([]byte(kept.JSON))
return kept.JSON, m, err
}
@@ -24,6 +24,7 @@ import (
"sync"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/composer"
)
// Manifest judges one manifest alone: decoded strictly, and every rule a manifest is held to by itself. The list of
@@ -43,6 +44,12 @@ func Manifest(raw []byte, predefined catalogue.PredefinedList) (m catalogue.Mani
return m, nil
}
// ForInputs is Manifest worded as the strict parser words a refusal: the indexer's read of a manifest for the inputs of its
// fingerprint, which keeps a refused manifest's reason in its value (None2) as it always has.
func ForInputs(raw []byte) (catalogue.Manifest, error) {
return catalogue.ParseManifestForInputs(raw)
}
// listed is how the strict parser words a refusal of several problems, one per line after its header.
const listed = "this manifest cannot be used:\n - "
@@ -160,6 +167,45 @@ func Named(problem string, shelf catalogue.Shelf) []string {
return out
}
// Unnamed names, in a request's case verdict, the problems between manifests that no one module's removal ends.
const Unnamed = "(between manifests)"
// Request judges every case of a composer request (mesh-sdk composer.Request), what cmd/mesh-judge answers the checker:
// each case's manifests as one catalogue (Shelf), every manifest accepted or refused with its problems, one per line; the
// problems no module's removal ends under Between. The verdict's SDK names this judge (Identity). A manifest left as a
// digest, or a case named twice, is a request it cannot run.
func Request(r composer.Request) (composer.Verdict, error) {
v := composer.Verdict{V: composer.Version, SDK: Identity()}
seen := map[string]bool{}
for _, c := range r.Cases {
if seen[c.Name] {
return composer.Verdict{}, fmt.Errorf("the case %q is named twice", c.Name)
}
seen[c.Name] = true
raws := map[string][]byte{}
for name, m := range c.Manifests {
if len(m.Raw) == 0 {
return composer.Verdict{}, fmt.Errorf("%w: %s (digest %s)", composer.ErrUnfilled, name, m.Digest)
}
raws[name] = m.Raw
}
refused, unnamed := Shelf(raws, r.Predefined, 0)
cv := composer.CaseVerdict{Name: c.Name, Manifests: map[string]composer.ManifestRead{}}
for name := range raws {
if problems := refused[name]; len(problems) > 0 {
cv.Manifests[name] = composer.ManifestRead{Refused: strings.Join(problems, "\n")}
continue
}
cv.Manifests[name] = composer.ManifestRead{Accepted: true}
}
if len(unnamed) > 0 {
cv.Manifests[Unnamed] = composer.ManifestRead{Refused: strings.Join(unnamed, "\n")}
}
v.Cases = append(v.Cases, cv)
}
return v, nil
}
var (
identityOnce sync.Once
identity string
@@ -1,11 +1,13 @@
package judge
import (
"encoding/json"
"reflect"
"strings"
"testing"
"git.novox.be/novox/mesh-sdk/go/catalogue"
"git.novox.be/novox/mesh-sdk/go/composer"
)
// The judge (novox/hq ADR 0578 §1): a manifest alone is accepted, or refused with each problem; an unknown field is
@@ -64,4 +66,19 @@ func TestTheJudge(t *testing.T) {
if id := Identity(); !strings.HasPrefix(id, "exe:") || id != Identity() {
t.Errorf("identity %q", id)
}
// What cmd/mesh-judge answers the checker (ADR 0578 §2): a composer request in, a verdict out, each manifest accepted
// or refused; a manifest left as a digest is a request it cannot run.
r := composer.Request{V: composer.Version, Cases: []composer.Case{{Name: "change", Manifests: map[string]composer.Manifest{
"a": {Raw: json.RawMessage(`{"module":"a","version":"1"}`)},
"b": {Raw: json.RawMessage(`{"module":"b","version":"1","requires":["amqp"]}`)},
}}}}
v, err := Request(r)
if err != nil || v.V != composer.Version || len(v.Cases) != 1 || v.SDK != Identity() || !v.Cases[0].Manifests["a"].Accepted ||
v.Cases[0].Manifests["b"].Accepted || !strings.Contains(v.Cases[0].Manifests["b"].Refused, `requires "amqp"`) {
t.Fatalf("request: %+v %v", v, err)
}
r.Cases[0].Manifests["c"] = composer.Manifest{Digest: strings.Repeat("a", 64)}
if _, err := Request(r); err == nil {
t.Fatal("a manifest left as a digest was judged")
}
}