WM9, WM15: the manifest findings are the indexer's verdicts heard as events

manifest-refused raises manifest-refused; manifest-accepted, which carries problems, raises manifest-outgrown or clears it
and any refusal; the start seeds both from indexer_verdicts. The indexer's modules view (ModuleVerdict, views.modules,
indexer_read_modules) is no longer followed, and manifest-waits is no longer written (§500).

Builds: design 47 G §500, §196, §668

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
This commit is contained in:
2026-11-12 05:55:02 +01:00
parent faec6b5333
commit 1abc5ae6d9
10 changed files with 142 additions and 101 deletions
@@ -46,6 +46,13 @@ func consumed(w *watch.Watchman, subject string, body []byte, logf func(string,
return
}
w.Accepted(a)
case subject == meshcatalog.SubjectManifestRefused:
var r meshcatalog.ManifestRefusedEvent
if err := json.Unmarshal(body, &r); err != nil || r.Module == "" {
logf("a manifest-refused that does not read is left: %v", err)
return
}
w.ManifestRefused(r)
case pipelineSubject(w, subject, body):
case engineWaitSubject(w, subject, body):
case moduleWaitSubject(w, subject, body):
@@ -63,12 +63,12 @@ accounts {
}
`
// serveOwners serves the assigner's wants and the indexer's modules as their owners do, by their read tools and views
// serveOwners serves the assigner's wants as its owner does, by their read tools and views
// families (DLV-M5, ADR 0615): the watchman (n1) follows both, never their buckets.
func serveOwners(t *testing.T, ctx context.Context, js jetstream.JetStream, nc *nats.Conn) {
t.Helper()
viewstest.Serve(t, ctx, js, nc, watch.AssignerModule, wantsState, watch.AssignerModule+".assigner_read_wants", "n1_"+watch.WatchmanModule)
viewstest.Serve(t, ctx, js, nc, watch.IndexerModule, modulesState, watch.IndexerModule+".indexer_read_modules", "n1_"+watch.WatchmanModule)
}
// makeEvents makes EVENTS and the watchman's durable consumer of the build seats' events, as the controller and the grants part
@@ -194,8 +194,7 @@ func createdOr(e jetstream.KeyValueEntry, at time.Time) time.Time {
var firstViewsBucket = watch.WatchmanModule + "_" + views.StatusState
const (
wantsState = "wants"
modulesState = "modules"
wantsState = "wants"
// The owners' views families, as their manifests' `streams` name them.
)
@@ -261,16 +260,11 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
if err != nil {
return err
}
modules, err := reader.Follow(watch.IndexerModule, modulesState, watch.IndexerModule+".indexer_read_modules")
if err != nil {
return err
}
w := watch.New(&kvOut{ctx: ctx, presence: kvs.presence, pulse: kvs.pulse, stuk: kvs.stuck, findings: held, js: js, cred: cred}, time.Now)
w.Logf(logger.Printf)
// What the wants and the modules hold is ended by their own late read (watch.ReadLate), never by the start's end.
w.Awaits(watch.AssignerWantsBucket)
w.Awaits(watch.ModulesBucket)
// A test shortens how long a move may take; the mesh never sets it.
if v := strings.TrimSpace(getenv("MESH_DELIVERY_PULSE_BOUND")); v != "" {
d, err := time.ParseDuration(v)
@@ -416,6 +410,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
logger.Printf("take-in: no connection to ask %s (%v), so a wait the indexer held before this start is said only once a take-in event of it is heard", pendingTool, err)
} else {
seedTakeIn(w, calls.Call, logger.Printf)
seedVerdicts(w, calls.Call, logger.Printf)
calls.Close()
}
// The take-in events are the indexer's ordinary events (its emits), heard on the shared events stream through this
@@ -452,9 +447,6 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro
// Every part has registered: the hub pulls the module's durable, and the watchman's other consumers open.
hearConsumed(ctx, js, cred, hub, w, logger.Printf)
defer hub.Stop()
// The indexer's modules (ADR 0578 §1): a module whose value carries a refusal of its manifest is a finding.
verdictEach := func(e jetstream.KeyValueEntry) { w.ModuleVerdict(e.Key(), e.Value(), opOf(e)) }
go func() { errs <- readLate(ctx, w, modules, watch.ModulesBucket, verdictEach) }()
if haveSeen != nil {
go func() {
errs <- follow(ctx, haveSeen, func(e jetstream.KeyValueEntry) { w.Have(e.Key(), e.Value(), opOf(e)) })
@@ -522,6 +514,20 @@ func seedTakeIn(w *watch.Watchman, call func(key string, body any) (json.RawMess
logf("take-in: %s cannot be asked (%v), so a wait the indexer held before this start is said only once a take-in event of it is heard", pendingTool, err)
}
// seedVerdicts asks the indexer's verdicts and raises the findings they hold (design 47 G §500): a verdict said while the watchman was
// down is then not lost. An indexer that does not answer is said: the findings are then raised from the verdicts heard after.
func seedVerdicts(w *watch.Watchman, call func(key string, body any) (json.RawMessage, error), logf func(string, ...any)) {
raw, err := call(watch.VerdictsTool, map[string]any{"all": true})
if err == nil {
var rows []watch.VerdictRow
if rows, err = watch.DecodeVerdictRows(raw); err == nil {
w.SeedVerdicts(rows)
return
}
}
logf("verdicts: %s cannot be asked (%v), so a manifest refused before this start is said only once a verdict of it is heard", watch.VerdictsTool, err)
}
// takeInHeard hands one take-in event of the indexer to the watchman, by its name relative to the indexer, and acknowledges it;
// one that is not a take-in event is said and acknowledged, since hearing it again would not read it.
func takeInHeard(w *watch.Watchman, m jetstream.Msg, logf func(string, ...any)) {
@@ -75,6 +75,14 @@ func TestRunNeedsItsCredential(t *testing.T) { // 1135/AC6
t.Fatalf("created left %v", out.findings)
}
})
t.Run("design 47 G §500: the indexer's manifest-refused reaches the watchman by its subject", func(t *testing.T) {
out := &findingsOut{findings: map[string]bool{}}
w := watch.New(out, time.Now)
consumed(w, "mesh.seat.mesh-catalog.event.manifest-refused", []byte(`{"module":"m","digest":"d","problems":["x"]}`), func(string, ...any) {})
if !out.findings[watch.FindingKey(watch.ScopeModule, "m", watch.KindManifestRefused)] {
t.Fatalf("a refused manifest reached %v", out.findings)
}
})
t.Run("design 47 G §499, §541: a node-engine's wait-held and wait-ended reach the watchman by their subjects", func(t *testing.T) {
out := &findingsOut{findings: map[string]bool{}}
w := watch.New(out, time.Now)
@@ -64,6 +64,7 @@ func refusedKey(module, local string) string {
func (w *Watchman) Accepted(a meshcatalog.ManifestAcceptedEvent) {
w.mu.Lock()
defer w.mu.Unlock()
w.manifestAccepted(a.Module, a.Problems) // §500: the problems a stricter validator finds are the module's warning
asked := map[string]bool{}
for _, e := range a.BusState {
if e.Name == "" {
@@ -187,43 +187,32 @@ func TestTheWatchmansFindings(t *testing.T) {
next := "m.00000000000000000043"
w.TakeIn(takeInEvent(t, takein.TakeInPending, next), takeInBody(t, takein.TakeInPending, next, t0))
}, map[string]string{FindingKey(ScopeDelivery, "m.00000000000000000043", KindTakeInWaits): Warning}},
{"ADR 0578 §1: a module whose value carries a refusal of its manifest is a finding until it is accepted", func(t *testing.T, w *Watchman, o *fakeOut, c *clock) {
value := func(verdict string, problems ...string) []byte {
b, err := meshcatalogclient.EncodeModule(meshcatalog.ModulesByModuleValue{Fp2: "src2:" + strings.Repeat("a", 64), Manifest: strings.Repeat("b", 64),
Repository: "novox/mesh-catalog", Commit: "c", Verdict: verdict, Problems: problems})
if err != nil {
t.Fatal(err)
}
return b
}
w.ModuleVerdict("nats", value(meshcatalogclient.VerdictRefused, "removes a stream"), Put)
w.ModuleVerdict("power", value(meshcatalogclient.VerdictRefused, "shows nothing"), Put)
{"design 47 G §500: manifest-refused raises the refusal, manifest-accepted clears it and carries an outgrown manifest's problems", func(t *testing.T, w *Watchman, o *fakeOut, c *clock) {
w.ManifestRefused(meshcatalog.ManifestRefusedEvent{Module: "nats", Problems: []string{"removes a stream"}})
w.ManifestRefused(meshcatalog.ManifestRefusedEvent{Module: "power", Problems: []string{"shows nothing"}})
k := FindingKey(ScopeModule, "nats", KindManifestRefused)
if f := o.findings[k]; !strings.Contains(f.Summary, "refused the manifest of nats: removes a stream") {
t.Fatalf("findings = %v", o.findings)
}
w.ModuleVerdict("nats", value(""), Put)
w.ModuleVerdict("power", nil, Delete)
w.Accepted(meshcatalog.ManifestAcceptedEvent{Module: "nats", Digest: strings.Repeat("d", 64)})
w.Accepted(meshcatalog.ManifestAcceptedEvent{Module: "power", Digest: strings.Repeat("d", 64)})
// ADR 0579 §1: an accepted manifest a stricter judge outgrew is a warning until mended.
outgrown, _ := meshcatalogclient.EncodeModule(meshcatalog.ModulesByModuleValue{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)
w.Accepted(meshcatalog.ManifestAcceptedEvent{Module: "node-tools", Digest: strings.Repeat("d", 64), Problems: []string{"says no credential form"}})
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)
// Clause 3 of the record on a release's Approve: a manifest that waits for a judge that knows its fields is its own
// warning (a refusal in the value, naming the fields), not manifest-refused, and goes when it is accepted.
waiting, _ := meshcatalogclient.EncodeModule(meshcatalog.ModulesByModuleValue{Fp2: "src2:" + strings.Repeat("a", 64), Manifest: strings.Repeat("b", 64),
Repository: "novox/mesh-catalog", Commit: "c", Verdict: meshcatalogclient.VerdictRefused, Problems: []string{"waits"}, Unknown: []string{"core-credentials"}})
w.ModuleVerdict("nats", waiting, Put)
if f := o.findings[FindingKey(ScopeModule, "nats", KindManifestWaits)]; f.Severity != Warning || !strings.Contains(f.Summary, "core-credentials") {
w.Accepted(meshcatalog.ManifestAcceptedEvent{Module: "node-tools", Digest: strings.Repeat("e", 64), Problems: []string{}})
// The start seeds from the indexer's verdicts: the newest of each module counts.
w.SeedVerdicts([]VerdictRow{
{Module: "nats", State: meshcatalogclient.VerdictRefused, Problems: []string{"old"}, At: t0},
{Module: "nats", State: meshcatalogclient.VerdictAccepted, At: t0.Add(time.Hour)},
{Module: "power", State: meshcatalogclient.VerdictRefused, Problems: []string{"shows nothing"}, At: t0},
{Module: "node-tools", State: meshcatalogclient.VerdictAccepted, Warnings: []string{"w"}, At: t0}})
if len(o.findings) != 2 || o.findings[FindingKey(ScopeModule, "power", KindManifestRefused)].Kind == "" || o.findings[FindingKey(ScopeModule, "node-tools", KindManifestOutgrown)].Kind == "" {
t.Fatalf("findings = %v", o.findings)
}
if _, refused := o.findings[FindingKey(ScopeModule, "nats", KindManifestRefused)]; refused {
t.Fatalf("a waiting manifest was found refused: %v", o.findings)
}
w.ModuleVerdict("nats", value(""), Put)
w.Accepted(meshcatalog.ManifestAcceptedEvent{Module: "power"})
w.Accepted(meshcatalog.ManifestAcceptedEvent{Module: "node-tools"})
}, map[string]string{}},
{"DLV-W1, 1966/AC37-AC38 (ADR 0595 §4, design 25 § 12.2): an accepted entry the bus module says nothing of in five minutes is overdue until created; a refused one stands until created; a later verdict no longer asking ends both", func(t *testing.T, w *Watchman, o *fakeOut, c *clock) {
accepted := func(locals ...string) meshcatalog.ManifestAcceptedEvent {
@@ -25,13 +25,10 @@ const (
NodeHealthBucket = "mesh-host_health"
// AssignerWantsBucket is the assigner's state wants, followed by its views family (consumes: mesh-delivery-assigner.views.wants).
AssignerWantsBucket = AssignerModule + "_wants"
// ModulesBucket is the indexer's state modules, followed by its views family (consumes: mesh-delivery-indexer.views.modules).
ModulesBucket = IndexerModule + "_modules"
)
// The findings a value of another part is raised as, named by their words.
const (
FindingManifestOutgrown = "manifest-outgrown"
FindingManifestWaits = "manifest-waits"
FindingNodeAccountFallback = "node-account-fallback"
)
@@ -1,9 +1,13 @@
package watch
import (
"encoding/json"
"fmt"
"strings"
"time"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/clients/meshcatalogclient"
"git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
)
// KindManifestRefused is a module whose manifest the indexer's judge refused (novox/hq ADR 0578 §1): every reader holds
@@ -14,66 +18,96 @@ const KindManifestRefused = "manifest-refused"
// (novox/hq ADR 0579 §1): it stays accepted and runs; the warning stands until the manifest is mended.
const KindManifestOutgrown = FindingManifestOutgrown
// KindManifestWaits is a module whose manifest carries a field the indexer's judge does not know yet (novox/hq ADR 0578
// §1, amended): every reader holds it as a refused one and keeps what runs, and the warning stands until a judge knows the
// field or the manifest is mended.
const KindManifestWaits = FindingManifestWaits
// The manifest findings are the indexer's verdicts heard as events (design 47 G §500): `manifest-refused` raises the refusal, and
// `manifest-accepted`, which carries `problems` (what a stricter validator finds in a manifest it still accepts), raises
// `manifest-outgrown` or, with none, clears it and any refusal. The watchman seeds both from the indexer's verdicts at its start
// (VerdictsTool). `manifest-waits` is no longer written: every revision is judged by a validator built from its own heads (§16).
// ModuleVerdict is a change of the indexer's value of a module (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) {
// VerdictsTool is the indexer's tool that lists its verdicts, which seeds the findings at the start.
const VerdictsTool = IndexerModule + ".indexer_verdicts"
// VerdictRow is one verdict as the tool lists it (the fields the watchman reads).
type VerdictRow struct {
Module string `json:"module"`
State string `json:"state"`
Problems []string `json:"problems"`
Warnings []string `json:"warnings"`
At time.Time `json:"at"`
}
// ManifestRefused hears the seat mesh-catalog's manifest-refused: the module's manifest is refused until a mended one is accepted.
func (w *Watchman) ManifestRefused(e meshcatalog.ManifestRefusedEvent) {
if e.Module == "" {
w.say("a manifest-refused names no module, left")
return
}
w.mu.Lock()
defer w.mu.Unlock()
key := FindingKey(ScopeModule, module, KindManifestRefused)
outgrown := FindingKey(ScopeModule, module, KindManifestOutgrown)
waits := FindingKey(ScopeModule, module, KindManifestWaits)
if op != Put {
w.unfind(key)
w.unfind(outgrown)
w.unfind(waits)
return
}
m, err := meshcatalogclient.DecodeModule(value)
if err != nil {
w.say("the indexer's value of %s cannot be read, so whether its manifest is refused is left as it was: %v", module, err)
return
}
v := meshcatalogclient.ModuleVerdict(module, m)
if v != nil && meshcatalogclient.VerdictWaits(*v) {
w.unfind(key)
w.unfind(outgrown)
w.find(Finding{Scope: ScopeModule, ID: module, Kind: KindManifestWaits, Severity: Warning, Source: ModulesBucket,
Summary: meshcatalogclient.VerdictWhy(*v),
Said: strings.Join(v.Unknown, "; "),
Headline: "The manifest of " + module + " waits for a judge that knows its fields",
Explanation: "The manifest carries " + strings.Join(v.Unknown, ", ") + ", which the indexer's judge does not know yet, so every " +
"reader holds " + module + " as a refused one and keeps what runs; an indexer that knows the fields judges it again " +
"at its start, and the newest build of the indexer refuses a field it does not know.",
Needs: "nothing while a newer indexer is on its way; else a pull request that mends the manifest of " + module})
return
}
w.unfind(waits)
if refused, _ := meshcatalogclient.TakeVerdict(v); !refused {
w.unfind(key)
if v == nil || len(v.Warnings) == 0 {
w.unfind(outgrown)
return
w.verdict(e.Module, e.Problems, nil, true)
}
// manifestAccepted hears the problems a manifest-accepted carries (Accepted calls it, w.mu held): none clears the module's findings, some are its warning.
func (w *Watchman) manifestAccepted(module string, problems []string) {
w.verdict(module, nil, problems, false)
}
// SeedVerdicts raises, at the start, the findings of the newest verdict of each module the indexer's tool listed: a refused one, or an
// accepted one with warnings. A module whose newest verdict is accepted clears both.
func (w *Watchman) SeedVerdicts(rows []VerdictRow) {
newest := map[string]VerdictRow{}
for _, r := range rows {
if old, ok := newest[r.Module]; !ok || r.At.After(old.At) {
newest[r.Module] = r
}
w.find(Finding{Scope: ScopeModule, ID: module, Kind: KindManifestOutgrown, Severity: Warning, Source: 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).",
}
w.mu.Lock()
defer w.mu.Unlock()
for module, r := range newest {
switch r.State {
case meshcatalogclient.VerdictRefused:
w.verdict(module, r.Problems, nil, true)
case meshcatalogclient.VerdictAccepted:
w.verdict(module, nil, r.Warnings, false)
}
}
}
// DecodeVerdictRows reads the answer of the indexer's verdicts tool.
func DecodeVerdictRows(raw []byte) ([]VerdictRow, error) {
var a struct {
Verdicts []VerdictRow `json:"verdicts"`
}
if err := json.Unmarshal(raw, &a); err != nil {
return nil, fmt.Errorf("not an answer of the indexer's verdicts: %w", err)
}
return a.Verdicts, nil
}
// verdict writes and clears a module's manifest findings, w.mu held: a refusal (problems, refused) or an outgrown manifest (warnings).
func (w *Watchman) verdict(module string, problems, warnings []string, refused bool) {
refusedKey := FindingKey(ScopeModule, module, KindManifestRefused)
outgrownKey := FindingKey(ScopeModule, module, KindManifestOutgrown)
if refused {
w.unfind(outgrownKey)
w.find(Finding{Scope: ScopeModule, ID: module, Kind: KindManifestRefused, Severity: Warning, Source: "indexer.verdicts",
Summary: "the indexer's judge refused the manifest of " + module + ": " + strings.Join(problems, "; "),
Said: strings.Join(problems, "; "),
Headline: "The manifest of " + module + " is refused",
Explanation: "The indexer's judge refused it, so every node, the grants part and the assigner hold " + module + ": " +
"nothing of it changes until a mended manifest is merged, and every other module goes on.",
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: ModulesBucket,
Summary: meshcatalogclient.VerdictWhy(*v),
Said: strings.Join(v.Problems, "; "),
Headline: "The manifest of " + module + " is refused",
Explanation: "The indexer's judge refused it, so every node, the grants part and the assigner hold " + module + ": " +
"nothing of it changes until a mended manifest is merged, and every other module goes on.",
w.unfind(refusedKey)
if len(warnings) == 0 {
w.unfind(outgrownKey)
return
}
w.find(Finding{Scope: ScopeModule, ID: module, Kind: KindManifestOutgrown, Severity: Warning, Source: "indexer.verdicts",
Summary: "the manifest of " + module + " breaks rules the indexer's judge holds it to now: " + strings.Join(warnings, "; "),
Said: strings.Join(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})
}
@@ -126,11 +126,11 @@ func TestManifestStateAndReads(t *testing.T) { // 1135/AC6
}
// The join: its first view asked again by hand is a hand act, recorded through the seat (views.StatusTools). The waits the
// indexer holds at the watchman's start are asked of its tool (ADR 0633 §5), a verb edge as the view's.
if want := []string{"mesh-delivery-assigner.assigner_read_wants", "mesh-delivery-indexer.indexer_pending", "mesh-delivery-indexer.indexer_read_modules", "seat:mesh-hand-acts.hand-act", "seat:mesh-conditions.conditions"}; !reflect.DeepEqual(m.Invokes, want) {
if want := []string{"mesh-delivery-assigner.assigner_read_wants", "mesh-delivery-indexer.indexer_pending", "mesh-delivery-indexer.indexer_verdicts", "seat:mesh-hand-acts.hand-act", "seat:mesh-conditions.conditions"}; !reflect.DeepEqual(m.Invokes, want) {
t.Errorf("invokes = %v, want %v", m.Invokes, want)
}
// DLV-M5 its first views, 1585/T20 the indexer's take-in events, and DLV-W1 (ADR 0595 §4): the accepted verdicts and the bus module's created and refused, durably.
if want := []string{"mesh-delivery-assigner.views.wants", "mesh-delivery-indexer.take-in.pending", "mesh-delivery-indexer.take-in.taken", "mesh-delivery-indexer.views.modules", "mesh-catalog.manifest-accepted", "mesh-delivery.source-moved", "mesh-delivery.filling", "mesh-delivery.full", "mesh-delivery.room", "mesh-delivery.record-opened", "mesh-delivery.record-ended", "mesh-catalog.filling", "mesh-catalog.full", "mesh-catalog.room", "mesh-wants.filling", "mesh-wants.full", "mesh-wants.room", "mesh-grants.filling", "mesh-grants.full", "mesh-grants.room", "node-build-go.ask-taken", "node-build-go.step-progress", "node-build-go.step-ended", "node-build-image.ask-taken", "node-build-image.step-progress", "node-build-image.step-ended", "node-build-node.ask-taken", "node-build-node.step-progress", "node-build-node.step-ended", "mesh-pipeline-runner.pipeline-started", "mesh-pipeline-runner.step-started", "mesh-pipeline-runner.step-ended", "mesh-pipeline-runner.wait-held", "mesh-pipeline-runner.wait-ended", "mesh-wants.wait-held", "mesh-wants.wait-ended", "mesh-grants.wait-held", "mesh-grants.wait-ended", "mesh-delivery-builder.wait-held", "mesh-delivery-builder.wait-ended", "node-engine.wait-held", "node-engine.wait-ended", "mesh-broker.created", "mesh-broker.refused", "mesh-conditions.findings-asked"}; !reflect.DeepEqual(m.Consumes, want) {
if want := []string{"mesh-delivery-assigner.views.wants", "mesh-delivery-indexer.take-in.pending", "mesh-delivery-indexer.take-in.taken", "mesh-catalog.manifest-accepted", "mesh-catalog.manifest-refused", "mesh-delivery.source-moved", "mesh-delivery.filling", "mesh-delivery.full", "mesh-delivery.room", "mesh-delivery.record-opened", "mesh-delivery.record-ended", "mesh-catalog.filling", "mesh-catalog.full", "mesh-catalog.room", "mesh-wants.filling", "mesh-wants.full", "mesh-wants.room", "mesh-grants.filling", "mesh-grants.full", "mesh-grants.room", "node-build-go.ask-taken", "node-build-go.step-progress", "node-build-go.step-ended", "node-build-image.ask-taken", "node-build-image.step-progress", "node-build-image.step-ended", "node-build-node.ask-taken", "node-build-node.step-progress", "node-build-node.step-ended", "mesh-pipeline-runner.pipeline-started", "mesh-pipeline-runner.step-started", "mesh-pipeline-runner.step-ended", "mesh-pipeline-runner.wait-held", "mesh-pipeline-runner.wait-ended", "mesh-wants.wait-held", "mesh-wants.wait-ended", "mesh-grants.wait-held", "mesh-grants.wait-ended", "mesh-delivery-builder.wait-held", "mesh-delivery-builder.wait-ended", "node-engine.wait-held", "node-engine.wait-ended", "mesh-broker.created", "mesh-broker.refused", "mesh-conditions.findings-asked"}; !reflect.DeepEqual(m.Consumes, want) {
t.Errorf("consumes = %v, want %v", m.Consumes, want)
}
// 1952/WM1: the watchman holds the seat mesh-watchdogs at mesh scope, its first seat (novox/hq ADR 0564 §1, §4).
@@ -176,7 +176,6 @@ func TestManifestStateAndReads(t *testing.T) { // 1135/AC6
"health": {watch.NodeHealthBucket, bucket(m.Reads, "mesh-host.health")},
"wants": {watch.AssignerWantsBucket, bucket(m.Consumes, "mesh-delivery-assigner.views.wants")},
"provisions": {watch.ProvisionsBucket, bucket(m.Reads, "mesh-provisioner.provisions")},
"modules": {watch.ModulesBucket, bucket(m.Consumes, "mesh-delivery-indexer.views.modules")},
"assigner": {watch.AssignerModule + ".assigner_read_wants", entry(m.Invokes, "mesh-delivery-assigner.assigner_read_wants")},
"indexer": {watch.IndexerModule + ".indexer_pending", entry(m.Invokes, "mesh-delivery-indexer.indexer_pending")},
} {
+2 -2
View File
@@ -23,7 +23,7 @@
"invokes": [
"mesh-delivery-assigner.assigner_read_wants",
"mesh-delivery-indexer.indexer_pending",
"mesh-delivery-indexer.indexer_read_modules",
"mesh-delivery-indexer.indexer_verdicts",
"seat:mesh-hand-acts.hand-act",
"seat:mesh-conditions.conditions"
],
@@ -31,8 +31,8 @@
"mesh-delivery-assigner.views.wants",
"mesh-delivery-indexer.take-in.pending",
"mesh-delivery-indexer.take-in.taken",
"mesh-delivery-indexer.views.modules",
"mesh-catalog.manifest-accepted",
"mesh-catalog.manifest-refused",
"mesh-delivery.source-moved",
"mesh-delivery.filling",
"mesh-delivery.full",