Let grants, builder and checker decode manifests, and the checker judge a change with the indexer's judge (ADR 0578 §2, §3)

Issue 1585, S12: grants, builder and checker read with catalogue.Decode and grants holds a module the indexer
refused; the checker asks the Go build seat to run mesh-judge, built at mesh-delivery's trunk or at the group's
mesh-delivery head when it changes the judge, over the catalogue as the change leaves it, and fails on a refusal.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-01 02:15:54 +01:00
parent a4772a5c1d
commit efef7183ef
15 changed files with 296 additions and 17 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-grants
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261031230538-c28c645ca406
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101005736-7b09de1e5502
github.com/nats-io/nats.go v1.54.0
)
+2
View File
@@ -1,5 +1,7 @@
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261031230538-c28c645ca406 h1:Z4RcH5Ft4OAAG3F538NXIHP9F3pkyk3j0LtP9mqu1qQ=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261031230538-c28c645ca406/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101005736-7b09de1e5502 h1:XndvkzyAFNde/821lEfYObqMTURzmve/w9Ks+QrBBJ8=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101005736-7b09de1e5502/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op h1:Z/MZK75wC/NSrkgqeNIa7jexam9uWzhLmFTSCPI/kn0=
github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
+9 -1
View File
@@ -307,6 +307,13 @@ func (b *fakeBus) manifestOf(module, raw string) {
b.put(grants.ReadModules, module, delivery.Module{V: delivery.Version, FP2: "src2:" + strings.Repeat("ab", 32), Manifest: digest, Repository: "novox/x", Commit: "c"})
}
// refuse marks the indexer's refusal of module's manifest in its value (novox/hq ADR 0578 §1).
func (b *fakeBus) refuse(module, raw, problem string) {
b.put(grants.ReadModules, module, delivery.Module{V: delivery.Version, FP2: "src2:" + strings.Repeat("ab", 32),
Manifest: delivery.ManifestDigest([]byte(raw)), Repository: "novox/x", Commit: "c", Verdict: delivery.VerdictRefused,
Problems: []string{problem}})
}
func (b *fakeBus) assign(node, module string) {
b.put(grants.ReadAssignments, node+"."+module, map[string]any{"node": node, "module": module, "assigned": "2026-10-25T20:00:00Z"})
}
@@ -728,13 +735,14 @@ func TestGrants(t *testing.T) {
t.Run("a predefined-key fallback is read with no list; every refused manifest listed", func(t *testing.T) {
// mod-p's value falls back to a predefined key, as claude-code's managed_settings does, and no list is on the bus
// (issue 1945); mod-z's manifest carries a key mesh-sdk's reader refuses, and mod-z is assigned nowhere.
// (issue 1945); mod-z's manifest the indexer's judge refused (ADR 0578 §3), and mod-z is assigned nowhere.
const pManifest = `{"module":"mod-p","version":"1","own-secrets":{"broker":"/var/lib/p/broker"},` +
`"config":{"size":{"type":"number","description":"The size text shows in, in points.","predefined":"font-size","default":12,"runtime":true}}}`
const zManifest = `{"module":"mod-z","version":"1","no-such-key":true}`
b := fixture()
b.manifestOf("mod-p", pManifest)
b.manifestOf("mod-z", zManifest)
b.refuse("mod-z", zManifest, "it carries no-such-key")
b.assign("b", "mod-p")
// mesh-wireguard is provided by the mesh, not read from a repository: no manifest in the indexer, none refused,
// no gap, and its manifest is the one mesh-sdk provides (issue 1945).
+11 -5
View File
@@ -10,6 +10,7 @@ package grants
import (
"crypto/sha256"
"encoding/json"
"errors"
"fmt"
"slices"
"sort"
@@ -206,12 +207,11 @@ func (c *Manifests) get(r Reader, digest string) (catalogue.Manifest, error) {
if err != nil {
return catalogue.Manifest{}, err
}
// Read for its inputs, as every delivery part reads a manifest (issue 1751): the merge gate judged its config values,
// and the part reads its seats, buckets, logs and streams, never a value; so a value falling back to a predefined key
// is taken as it declares itself, where ParseManifest refused it with no list and placed its module nowhere (issue 1945).
m, err = catalogue.ParseManifestForInputs([]byte(v.JSON))
// Decoded, never judged (novox/hq ADR 0578 §3): the indexer's judge judged it, and its verdict is taken where the
// module's value is read (Inputs); a field this part does not know is set aside.
m, err = catalogue.Decode([]byte(v.JSON))
if err != nil {
return catalogue.Manifest{}, fmt.Errorf("the manifest %s is refused by mesh-sdk's reader: %w", digest, err)
return catalogue.Manifest{}, fmt.Errorf("the manifest %s does not decode: %w", digest, err)
}
c.mu.Lock()
defer c.mu.Unlock()
@@ -384,6 +384,12 @@ func ReadInputs(r Reader, cache *Manifests) Inputs {
in.NoFingerprint[module] = why
}
var m catalogue.Manifest
if err == nil {
// The indexer's refusal, carried in its value (ADR 0578 §3): held and named as a refused manifest.
if verdict := v.VerdictOf(module); verdict != nil && verdict.Refused() {
err = errors.New(verdict.Why())
}
}
if err == nil {
m, err = cache.get(r, v.Manifest)
}
+4 -2
View File
@@ -70,9 +70,11 @@ func TestTheLeaseCheckJudgesEveryDependencyOnTheController(t *testing.T) {
controllerHolds, want{reason: "manifest of mod-m could not be read", bothPhases: true}, func(b *fakeBus) {
delete(b.states[grants.ReadManifests], delivery.ManifestDigest([]byte(mManifest)))
}},
{"a manifest mesh-sdk refuses fails both phases, named",
{"a manifest the indexer's judge refuses fails both phases, named",
map[string]string{"mod-l": `{"module":"mod-l","version":"1"}`, "mod-r": `{"module":"mod-r","version":"1","waits":["mesh-controller.checked"]}`},
controllerHolds, want{reason: "manifest of mod-r could not be read", bothPhases: true}, nil},
controllerHolds, want{reason: "manifest of mod-r could not be read", bothPhases: true}, func(b *fakeBus) {
b.refuse("mod-r", `{"module":"mod-r","version":"1","waits":["mesh-controller.checked"]}`, "waits on what no record keeps")
}},
{"a lease already handed away leaves nothing to write",
map[string]string{},
handedAway, want{handedAway: true, reason: "there is nothing to write: the lease is handed to the operator's hand-over"}, nil},