Never refuse what the judge accepted before: warn, and refuse only a new or changed manifest (ADR 0579)

Issue 1585: the indexer keeps an accepted manifest accepted when a stricter judge re-judges it, its problems as
warnings carried in its value; a merge's new manifests are judged in full. The watchman raises manifest-outgrown as
a warning until mended. The checker fails only on a manifest the change adds or changes and names the rest as
warnings. Every module pins mesh-sdk 19c2042.

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-01 02:45:18 +01:00
parent f4ecc6fa64
commit 0e819eea4d
26 changed files with 145 additions and 29 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-assigner
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2
View File
@@ -8,6 +8,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c h1:rlUCZ5if
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236 h1:JEkSnrmHs5QIRJGhtrghLC1+C0AxqMpef8a32d/BLPg=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc h1:kVq7sS4I0EnL8DcAA2a3YstnXS6WmYYzJz7eK7IZ9RY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc/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=
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-builder
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2
View File
@@ -8,6 +8,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c h1:rlUCZ5if
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236 h1:JEkSnrmHs5QIRJGhtrghLC1+C0AxqMpef8a32d/BLPg=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc h1:kVq7sS4I0EnL8DcAA2a3YstnXS6WmYYzJz7eK7IZ9RY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc/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=
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-checker
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2
View File
@@ -8,6 +8,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c h1:rlUCZ5if
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236 h1:JEkSnrmHs5QIRJGhtrghLC1+C0AxqMpef8a32d/BLPg=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc h1:kVq7sS4I0EnL8DcAA2a3YstnXS6WmYYzJz7eK7IZ9RY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc/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=
@@ -944,8 +944,11 @@ func TestTheIndexersJudgeJudgesTheChangesManifests(t *testing.T) {
name string
refused string
fails string
// untouched is the judge's refusal of mail, which the change leaves as it is: a warning, never a failure (ADR 0579 §2)
untouched string
}{
{name: "accepted"},
{name: "an untouched manifest's problem", untouched: "mail says no credential form"},
{name: "refused", refused: "web requires \"amqp\"\nweb has no id", fails: "the indexer's judge at mesh-delivery's trunk " + strings.Repeat("d", 40) + ` refuses the manifest of web: web requires "amqp"; web has no id`},
} {
b := newBench(t)
@@ -960,7 +963,7 @@ func TestTheIndexersJudgeJudgesTheChangesManifests(t *testing.T) {
judged = append(judged, *a.Compose)
read := composer.ManifestRead{Accepted: row.refused == "", Refused: row.refused}
verdict, _ := json.Marshal(composer.Verdict{V: composer.Version, SDK: "exe:1", Cases: []composer.CaseVerdict{{Name: JudgeCase,
Manifests: map[string]composer.ManifestRead{"web": read, "mail": {Accepted: true}}}}})
Manifests: map[string]composer.ManifestRead{"web": read, "mail": {Accepted: row.untouched == "", Refused: row.untouched}}}}})
result, _ := json.Marshal(delivery.ComposeAnswer{Key: "k", Verdict: verdict})
return delivery.Step{ID: a.ID, State: delivery.StepPassed, Result: result}
}
@@ -58,7 +58,8 @@ type TrunkManifests interface {
}
// judgeRequest is the judge's request over the catalogue as the case leaves it: every trunk manifest by its digest, each
// one a pull request touches replaced by the digest its candidate names; touched are those modules, sorted.
// one a pull request touches replaced by the digest its candidate names; touched are the modules whose manifest the
// change adds or changes (a digest the trunk does not hold for it), sorted (novox/hq ADR 0579 §2).
func judgeRequest(trunk map[string]string, pulls []Pull) (req composer.Request, touched []string) {
manifests := map[string]composer.Manifest{}
for module, digest := range trunk {
@@ -73,7 +74,9 @@ func judgeRequest(trunk map[string]string, pulls []Pull) (req composer.Request,
continue
}
manifests[module] = composer.Manifest{Digest: cm.Manifest}
seen[module] = true
if trunk[module] != cm.Manifest {
seen[module] = true
}
}
}
return composer.Request{V: composer.Version, Cases: []composer.Case{{Name: JudgeCase, Manifests: manifests}}},
@@ -122,12 +125,23 @@ func (st *state) judgeManifests(ctx context.Context) *delivery.Verdict {
if why != "" {
return fail(goModule, fmt.Sprintf("the indexer's judge at %s did not judge the change's manifests: %s", at, why))
}
var refused []string
for _, module := range touched {
if r, ok := cv.Manifests[module]; ok && !r.Accepted {
refused = append(refused, fmt.Sprintf("the indexer's judge at %s refuses the manifest of %s: %s", at, module,
strings.ReplaceAll(r.Refused, "\n", "; ")))
// Only a new or changed manifest is refused (ADR 0579 §2); one the change leaves as it is is named as a warning, never
// a failure: it is not refused for a rule it already broke.
var refused, warned []string
for _, module := range slices.Sorted(maps.Keys(cv.Manifests)) {
r := cv.Manifests[module]
if r.Accepted || module == judgeBetween {
continue
}
words := strings.ReplaceAll(r.Refused, "\n", "; ")
if slices.Contains(touched, module) {
refused = append(refused, fmt.Sprintf("the indexer's judge at %s refuses the manifest of %s: %s", at, module, words))
} else {
warned = append(warned, module+": "+words)
}
}
if len(warned) > 0 {
st.c.note("warnings of the indexer's judge on manifests the change leaves as they are (ADR 0579 §2): " + strings.Join(warned, " | "))
}
if between := cv.Manifests[judgeBetween]; between.Refused != "" {
st.c.note("the indexer's judge names problems between manifests that no one module's removal ends: " +
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-forge-bridge
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
@@ -4,6 +4,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101005726-af4e4e60a3a0 h1:q6ywchpT
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101005726-af4e4e60a3a0/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236 h1:JEkSnrmHs5QIRJGhtrghLC1+C0AxqMpef8a32d/BLPg=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc h1:kVq7sS4I0EnL8DcAA2a3YstnXS6WmYYzJz7eK7IZ9RY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc/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=
@@ -391,12 +391,13 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
// Every manifest judged at the start, so a judge that changed with this program judges every one again (ADR 0578
// §1), once the verdicts state is there; each merge judges them again (index.ApplyMessage).
verdicts.Ready(func(jetstream.KeyValue) {
j, err := ix.JudgeAll(ctx)
j, err := ix.JudgeAll(ctx, nil)
if err != nil {
logger.Printf("judging the manifests at start: %v", err)
return
}
logger.Printf("judged %d manifests at start: %d verdicts written, %d refused", j.Judged, j.Written, len(j.Refused))
logger.Printf("judged %d manifests at start: %d verdicts written, %d with problems, of which outgrown and kept accepted: %v",
j.Judged, j.Written, len(j.Refused), j.Outgrown)
})
// A build module says each time it wrote its toolchains key: its stream, and the indexer's durable consumer on it, are
// made by the controller as the forge's are. Where the stream is not there yet the indexer says so and is started again
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-indexer
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2
View File
@@ -8,6 +8,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c h1:rlUCZ5if
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236 h1:JEkSnrmHs5QIRJGhtrghLC1+C0AxqMpef8a32d/BLPg=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc h1:kVq7sS4I0EnL8DcAA2a3YstnXS6WmYYzJz7eK7IZ9RY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc/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=
@@ -138,7 +138,12 @@ func (ix *Indexer) ApplyMessage(ctx context.Context, f delivery.Forge) (Applied,
return applied, err
}
// Every manifest judged again: a rule between manifests can turn on the one this merge moved (ADR 0578 §1).
if _, err := ix.JudgeAll(ctx); err != nil {
// The merge's own manifests are fresh: one with no verdict yet is judged in full (ADR 0579 §1).
fresh := map[string]bool{}
for _, raw := range f.Manifests {
fresh[delivery.ManifestDigest([]byte(raw))] = true
}
if _, err := ix.JudgeAll(ctx, fresh); err != nil {
ix.logf("judge: the manifests are not judged after %s#%d: %v", f.Repository, f.Number, err)
}
}
@@ -29,12 +29,20 @@ var VerdictsBucket = delivery.VerdictsBucket
type Judged struct {
Judged, Written int
Refused map[string][]string
// Outgrown are the modules accepted before whose problems are now warnings (ADR 0579 §1).
Outgrown []string
}
// JudgeAll judges every manifest the modules state names, as one catalogue with the predefined list the indexer keeps,
// and writes what differs. A manifest the manifests state does not hold is left unjudged and said; a write that fails is
// said and the pass goes on, so one key never costs the others their verdict.
func (ix *Indexer) JudgeAll(ctx context.Context) (Judged, error) {
//
// **A stricter judge never refuses what it accepted before** (novox/hq ADR 0579 §1): a manifest whose verdict under its
// digest is accepted, or which the indexer held before any verdict (taken as accepted, ADR 0578 §3) and is not in fresh,
// stays accepted, the new problems written as the verdict's Warnings and carried in its module's value, which the
// watchman raises as manifest-outgrown. A manifest in fresh (the digests a merge just took in) with no verdict yet, and
// one already refused, is judged in full.
func (ix *Indexer) JudgeAll(ctx context.Context, fresh map[string]bool) (Judged, error) {
var out Judged
if ix.Verdicts == nil || ix.Modules == nil || ix.Manifests == nil {
return out, nil
@@ -79,7 +87,12 @@ func (ix *Indexer) JudgeAll(ctx context.Context) (Judged, error) {
out.Judged++
v := delivery.ManifestVerdict{Module: name, State: delivery.VerdictAccepted, Judge: id, At: ix.now()}
if problems := refused[name]; len(problems) > 0 {
v.State, v.Problems = delivery.VerdictRefused, problems
if ix.acceptedBefore(ctx, digests[name], fresh) {
v.Warnings = problems
out.Outgrown = append(out.Outgrown, name)
} else {
v.State, v.Problems = delivery.VerdictRefused, problems
}
}
wrote, err := ix.writeVerdict(ctx, digests[name], v)
if errors.Is(err, process.ErrNotYet) {
@@ -105,6 +118,20 @@ func (ix *Indexer) JudgeAll(ctx context.Context) (Judged, error) {
return out, nil
}
// acceptedBefore says whether the manifest of digest was accepted before this judgement: its verdict says accepted, or
// it has none and is not fresh (held before any verdict, so taken in under the judges that ran until then).
func (ix *Indexer) acceptedBefore(ctx context.Context, digest string, fresh map[string]bool) bool {
value, _, found, err := ix.Verdicts.Get(ctx, digest)
if err != nil {
return false // unread: judged in full, said by the write that follows
}
if !found {
return !fresh[digest]
}
prev, err := delivery.DecodeManifestVerdict(value)
return err == nil && !prev.Refused()
}
// writeVerdict writes v under the digest's key unless the verdict held there says the same (ManifestVerdict.Same); wrote
// says it was written.
func (ix *Indexer) writeVerdict(ctx context.Context, digest string, v delivery.ManifestVerdict) (wrote bool, err error) {
@@ -146,10 +173,10 @@ func (ix *Indexer) carryVerdict(ctx context.Context, name, digest string, v deli
if v.Refused() {
state = delivery.VerdictRefused
}
if cur.Verdict == state && slices.Equal(cur.Problems, v.Problems) {
if cur.Verdict == state && slices.Equal(cur.Problems, v.Problems) && slices.Equal(cur.Warnings, v.Warnings) {
return nil, false, nil
}
cur.Verdict, cur.Problems = state, v.Problems
cur.Verdict, cur.Problems, cur.Warnings = state, v.Problems, v.Warnings
if state == "" {
cur.Problems = nil
}
@@ -33,7 +33,8 @@ func TestTheIndexerJudgesEveryManifestOnce(t *testing.T) {
}
good := hold("good", `{"module":"good","version":"1"}`)
bad := hold("bad", `{"module":"bad","version":"1","requires":["amqp"]}`)
j, err := ix.JudgeAll(ctx)
// Both taken in by a merge: judged in full.
j, err := ix.JudgeAll(ctx, map[string]bool{good: true, bad: true})
if err != nil || j.Judged != 2 || j.Written != 2 || len(j.Refused) != 1 {
t.Fatalf("the first pass: %+v %v", j, err)
}
@@ -70,20 +71,41 @@ func TestTheIndexerJudgesEveryManifestOnce(t *testing.T) {
}
// A new judge that judges alike writes nothing and says nothing again.
ix.JudgeID = "judge-2"
if j, err := ix.JudgeAll(ctx); err != nil || j.Written != 0 || len(said) != 1 {
if j, err := ix.JudgeAll(ctx, nil); err != nil || j.Written != 0 || len(said) != 1 {
t.Fatalf("a judge that judges alike: %+v %v, said %d", j, err, len(said))
}
// The manifest mended: its new digest is accepted and the module's refusal goes.
hold("bad", `{"module":"bad","version":"2"}`)
if j, err := ix.JudgeAll(ctx); err != nil || j.Written != 1 || len(j.Refused) != 0 {
mended := hold("bad", `{"module":"bad","version":"2"}`)
if j, err := ix.JudgeAll(ctx, map[string]bool{mended: true}); err != nil || j.Written != 1 || len(j.Refused) != 0 {
t.Fatalf("mended: %+v %v", j, err)
}
if m := module("bad"); m.Verdict != "" || m.Problems != nil {
t.Fatalf("modules.bad still carries %+v", m)
}
// ADR 0579 §1: a manifest held before any verdict (taken in under the judges until then), which this judge finds a
// problem in, stays accepted with the problem as a warning, carried in its value and said nowhere as a refusal; the
// same problem in a manifest a merge takes in now, or in one whose digest changed, is refused in full.
old := hold("old", `{"module":"old","version":"1","requires":["amqp"]}`)
if j, err := ix.JudgeAll(ctx, nil); err != nil || len(j.Outgrown) != 1 || j.Outgrown[0] != "old" {
t.Fatalf("an outgrown manifest: %+v %v", j, err)
}
if v := verdict(old); v.Refused() || len(v.Warnings) != 1 || !strings.Contains(v.Warnings[0], `requires "amqp"`) {
t.Fatalf("old: %+v", v)
}
if m := module("old"); m.Verdict != "" || len(m.Warnings) != 1 || len(said) != 1 {
t.Fatalf("modules.old carries %+v, said %d", m, len(said))
}
changed := hold("old", `{"module":"old","version":"2","requires":["amqp"]}`)
fresh := hold("new", `{"module":"new","version":"1","requires":["amqp"]}`)
if j, err := ix.JudgeAll(ctx, map[string]bool{changed: true, fresh: true}); err != nil || len(j.Outgrown) != 0 {
t.Fatalf("a changed and a new manifest: %+v %v", j, err)
}
if !verdict(changed).Refused() || !verdict(fresh).Refused() || module("old").Verdict != delivery.VerdictRefused || len(module("old").Warnings) != 0 {
t.Fatalf("the changed and the new manifest are not refused: %+v %+v", verdict(changed), verdict(fresh))
}
// Without the verdicts state the indexer judges nothing.
ix.Verdicts = nil
if j, err := ix.JudgeAll(ctx); err != nil || j.Judged != 0 {
if j, err := ix.JudgeAll(ctx, nil); err != nil || j.Judged != 0 {
t.Fatalf("without the state: %+v %v", j, err)
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-teller
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2
View File
@@ -2,6 +2,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030201806-eff81f1220e2 h1:RF73nVI1
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261030201806-eff81f1220e2/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236 h1:JEkSnrmHs5QIRJGhtrghLC1+C0AxqMpef8a32d/BLPg=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc h1:kVq7sS4I0EnL8DcAA2a3YstnXS6WmYYzJz7eK7IZ9RY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc/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=
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-view
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2
View File
@@ -2,6 +2,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261031084708-acbf80ad910a h1:DcSvfEmd
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261031084708-acbf80ad910a/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236 h1:JEkSnrmHs5QIRJGhtrghLC1+C0AxqMpef8a32d/BLPg=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc h1:kVq7sS4I0EnL8DcAA2a3YstnXS6WmYYzJz7eK7IZ9RY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc/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=
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-delivery-watchman
go 1.26.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.54.0
)
+2
View File
@@ -8,6 +8,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c h1:rlUCZ5if
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236 h1:JEkSnrmHs5QIRJGhtrghLC1+C0AxqMpef8a32d/BLPg=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc h1:kVq7sS4I0EnL8DcAA2a3YstnXS6WmYYzJz7eK7IZ9RY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
github.com/antithesishq/antithesis-sdk-go v0.8.0-default-no-op h1:1BOWQJweNyvZMlpAHXGLiZQn9S+QXGcz3xh94lC0w6E=
github.com/antithesishq/antithesis-sdk-go v0.8.0-default-no-op/go.mod h1:FQyySiasQQM8735Ddel3MRojmy4dA1IqCeyJ5jmPMbI=
github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
@@ -50,6 +50,14 @@ func TestTheWatchmansFindings(t *testing.T) {
}
w.ModuleVerdict("nats", value(""), Put)
w.ModuleVerdict("power", nil, Delete)
// ADR 0579 §1: an accepted manifest a stricter judge outgrew is a warning until mended.
outgrown, _ := delivery.EncodeModule(delivery.Module{FP2: "src2:" + strings.Repeat("a", 64), Manifest: strings.Repeat("b", 64),
Repository: "novox/mesh-tools", Commit: "c", Warnings: []string{"says no credential form"}})
w.ModuleVerdict("node-tools", outgrown, Put)
if f := o.findings[FindingKey(ScopeModule, "node-tools", KindManifestOutgrown)]; f.Severity != Warning || !strings.Contains(f.Summary, "says no credential form") {
t.Fatalf("findings = %v", o.findings)
}
w.ModuleVerdict("node-tools", value(""), Put)
}, map[string]string{}},
{"WM4: a stuck key not moved is its finding, and its move deletes it", func(t *testing.T, w *Watchman, o *fakeOut, c *clock) {
w.Step("go", "n1.ask1", runningStep("ask1", t0), Put)
@@ -10,14 +10,20 @@ import (
// it, composing nothing of its own, until a mended manifest is merged.
const KindManifestRefused = "manifest-refused"
// KindManifestOutgrown is a module whose manifest the indexer accepted before and a stricter judge finds problems in
// (novox/hq ADR 0579 §1): it stays accepted and runs; the warning stands until the manifest is mended.
const KindManifestOutgrown = delivery.ManifestOutgrown
// ModuleVerdict is a change of the indexer's value of a module (delivery.ModulesBucket): a value carrying a refusal is a
// finding, one that does not (accepted, or not judged yet) or a deleted key ends it.
func (w *Watchman) ModuleVerdict(module string, value []byte, op Op) {
w.mu.Lock()
defer w.mu.Unlock()
key := FindingKey(ScopeModule, module, KindManifestRefused)
outgrown := FindingKey(ScopeModule, module, KindManifestOutgrown)
if op != Put {
w.unfind(key)
w.unfind(outgrown)
return
}
m, err := delivery.DecodeModule(value)
@@ -28,8 +34,20 @@ func (w *Watchman) ModuleVerdict(module string, value []byte, op Op) {
v := m.VerdictOf(module)
if refused, _ := delivery.TakeManifestVerdict(v); !refused {
w.unfind(key)
if v == nil || len(v.Warnings) == 0 {
w.unfind(outgrown)
return
}
w.find(Finding{Scope: ScopeModule, ID: module, Kind: KindManifestOutgrown, Severity: Warning, Source: delivery.ModulesBucket,
Summary: "the manifest of " + module + " breaks rules the indexer's judge holds it to now: " + strings.Join(v.Warnings, "; "),
Said: strings.Join(v.Warnings, "; "),
Headline: "The manifest of " + module + " needs mending",
Explanation: "A stricter judge found problems in a manifest it accepted before; " + module + " stays accepted and " +
"runs, and its next change is refused until they are mended (novox/hq ADR 0579).",
Needs: "a pull request that mends the manifest of " + module})
return
}
w.unfind(outgrown)
w.find(Finding{Scope: ScopeModule, ID: module, Kind: KindManifestRefused, Severity: Warning, Source: delivery.ModulesBucket,
Summary: v.Why(),
Said: strings.Join(v.Problems, "; "),
+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.20261101014012-a20bdf795236
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc
github.com/nats-io/nats.go v1.54.0
)
+2
View File
@@ -8,6 +8,8 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c h1:rlUCZ5if
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101013319-25a2cecd989c/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236 h1:JEkSnrmHs5QIRJGhtrghLC1+C0AxqMpef8a32d/BLPg=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014012-a20bdf795236/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc h1:kVq7sS4I0EnL8DcAA2a3YstnXS6WmYYzJz7eK7IZ9RY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261101014310-19c204273bdc/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=