From b48e9ca6ce981df439ac5ca5e18b60fef98cd2d5 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 10 Nov 2026 03:46:09 +0100 Subject: [PATCH] =?UTF-8?q?D6k:=20keep=20a=20take-in's=20new=20manifests?= =?UTF-8?q?=20unjudged=20on=20the=20bus=20until=20a=20judge=20pass=20judge?= =?UTF-8?q?s=20them=20(issue=201966,=20ADR=200668=20=C2=A74)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A judge pass that failed lost the set of manifests the take-in newly wrote, which lived only in its memory: the next pass found no verdict, took each as accepted before any verdict (ADR 0579 §1), and wrote a refusal as a warning. The take-in now keeps each new digest in the indexer's own state unjudged before it writes the module naming it; every judge pass judges those as fresh and ends a key once its verdict is written or no module holds it. indexer_read_unjudged reads the state; indexer_judge judges it again by hand. Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ --- .../mesh-delivery-indexer/integration_test.go | 2 +- .../cmd/mesh-delivery-indexer/main.go | 5 +- .../internal/index/candidates.go | 3 + .../internal/index/pending.go | 2 + .../internal/index/pending_test.go | 2 +- .../internal/index/toolchains.go | 4 + .../internal/index/unjudged.go | 111 ++++++++++++++++++ .../internal/index/verdicts.go | 8 ++ .../internal/index/verdicts_test.go | 32 +++++ .../internal/index/views.go | 2 + .../mesh-delivery-indexer/manifest_test.go | 4 +- modules/mesh-delivery-indexer/module.json | 4 +- 12 files changed, 173 insertions(+), 6 deletions(-) create mode 100644 modules/mesh-delivery-indexer/internal/index/unjudged.go diff --git a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/integration_test.go b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/integration_test.go index a9e3c7c8..09d21fa0 100644 --- a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/integration_test.go +++ b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/integration_test.go @@ -87,7 +87,7 @@ func TestIndexerWhole(t *testing.T) { // 1238/AC2, AC10; 1585/T14, T15 // The states and the stream the controller makes from the indexer's manifest (old sections, ADR 0595 §11). for bucket, history := range map[string]uint8{index.PendingBucket: 1, index.VerdictsBucket: index.VerdictsHistory, index.GraphBucket: 1, index.TakenBucket: 1, index.PackagesBucket: 1, - index.SeatDefinitionsBucket: 1, index.RequirementsBucket: 1, findingsBucket: 1, index.HoldsBucket: 1} { + index.SeatDefinitionsBucket: 1, index.RequirementsBucket: 1, findingsBucket: 1, index.HoldsBucket: 1, index.UnjudgedBucket: 1} { if _, err := js.CreateKeyValue(ctx, jetstream.KeyValueConfig{Bucket: bucket, History: history}); err != nil { t.Fatal(err) } diff --git a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/main.go b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/main.go index d6bce20d..23d17e0e 100644 --- a/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/main.go +++ b/modules/mesh-delivery-indexer/cmd/mesh-delivery-indexer/main.go @@ -415,6 +415,9 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro // The module graph (ADR 0603 §2): a state this delivery brings, bound when it appears; until then no graph is written. graph := process.AwaitBucket(ctx, js, conn, index.GraphBucket, "no module graph is written", logger.Printf) ownBuildState := process.AwaitBucket(ctx, js, conn, index.OwnBuildBucket, "which build this indexer runs is not kept", logger.Printf) + // The manifests a take-in wrote and no judge pass judged yet (issue 1966): a state this delivery brings, bound when it + // appears; until then a take-in's new manifests are kept for their judging in its memory alone. + unjudged := process.AwaitBucket(ctx, js, conn, index.UnjudgedBucket, "a take-in's new manifests are kept for their judging in its memory alone", logger.Printf) tryRecovery := process.AwaitBucket(ctx, js, conn, index.TryRecoveryBucket, "how the recovery of the open tries went is not kept", logger.Printf) findings := process.AwaitBucket(ctx, js, conn, findingsBucket, "no finding of the indexer is written", logger.Printf) // The seat definitions (design 26, DLV-I17): a state this delivery brings, bound when it appears; until then none is kept. @@ -423,7 +426,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro seatBus := &seatBus{defs: awaitedSource{ctx, seatDefs}, marks: awaitedSource{ctx, marks}} seatReader, saySeats := followSeatList(seatBus, saySeatDefinition(js, cred), logger.Printf) readWhenBound(seatReader, seatDefs, marks) - ix := &index.Indexer{Findings: awaitedStore{b: findings}, OldSections: awaitedStore{b: oldSections}, Requirements: awaitedStore{b: requirements}, Store: kvStore{candidates}, Modules: kvStore{modules}, Manifests: kvStore{manifests}, Taken: awaitedStore{b: taken}, Builds: known, + ix := &index.Indexer{Findings: awaitedStore{b: findings}, OldSections: awaitedStore{b: oldSections}, Unjudged: awaitedStore{b: unjudged}, Requirements: awaitedStore{b: requirements}, Store: kvStore{candidates}, Modules: kvStore{modules}, Manifests: kvStore{manifests}, Taken: awaitedStore{b: taken}, Builds: known, Verdicts: awaitedStore{b: verdicts}, SayRefused: sayRefused(conn, cred, logger.Printf), SayAccepted: sayAccepted(conn, cred), Predefined: awaitedStore{b: predefined}, ConfigCandidates: awaitedStore{b: configCandidates}, Logf: logger.Printf, Named: namedVia(calls.Call), Trunk: trunkVia(calls.Call), Contains: containsVia(calls.Call), Read: readVia(calls.Call), diff --git a/modules/mesh-delivery-indexer/internal/index/candidates.go b/modules/mesh-delivery-indexer/internal/index/candidates.go index 191eca68..54463a6b 100644 --- a/modules/mesh-delivery-indexer/internal/index/candidates.go +++ b/modules/mesh-delivery-indexer/internal/index/candidates.go @@ -68,6 +68,9 @@ type Indexer struct { // OldSections is the state of how many accepted modules use each old section (oldsections.go, issue 1966 D4); nil keeps no // count and the judge refuses no use of an old section. OldSections Store + // Unjudged is the state of the manifest digests a take-in wrote and no judge pass judged yet (unjudged.go, issue 1966); + // nil keeps them only in the take-in's memory. + Unjudged Store // Requirements is the requirements state (requirements.go, DLV-I7): what each consumer's go.sum requires of each mesh // Go module, kept at each merge; nil keeps none. Requirements Store diff --git a/modules/mesh-delivery-indexer/internal/index/pending.go b/modules/mesh-delivery-indexer/internal/index/pending.go index 46b42f5c..962b8ff2 100644 --- a/modules/mesh-delivery-indexer/internal/index/pending.go +++ b/modules/mesh-delivery-indexer/internal/index/pending.go @@ -877,6 +877,8 @@ func (ix *Indexer) dry() *dryRun { x.Predefined, d.predefined = over(ix.Predefined) x.ConfigCandidates, d.configs = over(ix.ConfigCandidates) x.OldSections, d.oldSections = over(ix.OldSections) + // What the trunk holds unjudged is read through, as fresh; what the dry run would keep stays in its overlay (issue 1966). + x.Unjudged, _ = over(ix.Unjudged) ix.mu.Lock() x.source = sourceNow{rev: ix.source.rev, heads: maps.Clone(ix.source.heads)} x.previews = maps.Clone(ix.previews) diff --git a/modules/mesh-delivery-indexer/internal/index/pending_test.go b/modules/mesh-delivery-indexer/internal/index/pending_test.go index 91d401c3..672aa599 100644 --- a/modules/mesh-delivery-indexer/internal/index/pending_test.go +++ b/modules/mesh-delivery-indexer/internal/index/pending_test.go @@ -901,7 +901,7 @@ func TestTakeIn(t *testing.T) { // 1585/T3-T13 (ADR 0633) t.Run("the dry run names every field of the indexer", func(t *testing.T) { // dry (pending.go) builds an indexer field by field: a field added to Indexer is named there, or this fails. named := map[string]bool{} - for _, f := range []string{"Store", "Modules", "Manifests", "Predefined", "ConfigCandidates", "Taken", "Verdicts", "OldSections", + for _, f := range []string{"Store", "Modules", "Manifests", "Predefined", "ConfigCandidates", "Taken", "Verdicts", "OldSections", "Unjudged", "JudgeID", "SayRefused", "SayAccepted", "Packages", "Graph", "Files", "GoSum", "GoMod", "Now", "Builds", "Named", "Trunk", "Read", "Contains", "Logf", "ReadOpen", "OwnBuild", "Message", "Pending", "SayTakeIn", "Requirements", "Findings", "SeatDefinitions", "ReadFile", "SaySeatDefinition", "Holds", "Counted", "AskEngines", "HoldBounds", "OpenTries", "TryRecovery", "OwnBuildState"} { diff --git a/modules/mesh-delivery-indexer/internal/index/toolchains.go b/modules/mesh-delivery-indexer/internal/index/toolchains.go index 71044311..2ffb0617 100644 --- a/modules/mesh-delivery-indexer/internal/index/toolchains.go +++ b/modules/mesh-delivery-indexer/internal/index/toolchains.go @@ -415,6 +415,10 @@ func (ix *Indexer) writeOverlay(ctx context.Context, overlay, finals map[string] } if next.Manifest != "" && (!held || cur.Manifest != next.Manifest) { w.taken(next.Manifest) // a new module, or a changed manifest: fresh, judged in full (ADR 0579 §1) + // Kept on the bus before the module names it, so a judge pass that fails does not lose it (issue 1966). + if err := ix.keepUnjudged(ctx, next.Manifest, key, w); err != nil { + return nil, false, err + } } data, err := meshcatalogclient.EncodeModule(next) wrote = err == nil && !unchanged(data, false, value, found) diff --git a/modules/mesh-delivery-indexer/internal/index/unjudged.go b/modules/mesh-delivery-indexer/internal/index/unjudged.go new file mode 100644 index 00000000..772551b8 --- /dev/null +++ b/modules/mesh-delivery-indexer/internal/index/unjudged.go @@ -0,0 +1,111 @@ +package index + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "maps" + "slices" + + "git.novox.be/novox/mesh-sdk/go/process" +) + +// What a take-in newly wrote is kept until judged (issue 1966, ADR 0668 §4; ADR 0579 §1). A manifest a take-in writes new +// is fresh: judged in full, never taken as accepted before. A judge pass that fails (the verdicts state not on the bus, a +// restart between the write and the pass) used to lose that set, which lived only in the take-in's memory: the next pass +// found no verdict, took the manifest as held before any verdict, and wrote a refusal as a warning. So the take-in writes +// each digest into the indexer's own state unjudged before it writes the module naming it, every judge pass judges those +// digests as fresh, and a pass deletes a digest's key once its verdict is written or no module holds it any more. The +// tool indexer_read_unjudged reads the state; indexer_judge judges again by hand, which ends what it holds. +const ( + // UnjudgedState is the indexer's state of the digests a take-in wrote and no judge pass judged yet: the bucket + // mesh-delivery-indexer_unjudged, one key per manifest digest. + UnjudgedState = "unjudged" + UnjudgedBucket = Module + "_" + UnjudgedState +) + +// UnjudgedValue is one key of the unjudged state: the module whose new manifest the digest is, and the merge that wrote it. +type UnjudgedValue struct { + V int `json:"v"` + Module string `json:"module"` + Repository string `json:"repository,omitempty"` + Merge string `json:"merge,omitempty"` +} + +// keepUnjudged writes the digest into the unjudged state before the module naming it is written. A state not on the bus +// yet (an indexer whose delivery brings it) is said and the take-in goes on, judged from its memory alone as before; +// any other failure fails the write, so the module is not written with its digest unkept. +func (ix *Indexer) keepUnjudged(ctx context.Context, digest, module string, w *mergeWrite) error { + if ix.Unjudged == nil { + return nil + } + v := UnjudgedValue{V: 1, Module: module} + if w != nil { + v.Repository, v.Merge = w.repository, w.merge + } + data, err := json.Marshal(v) + if err != nil { + return err + } + err = write(ctx, ix.Unjudged, digest, func(value []byte, found bool) ([]byte, bool, error) { + if found { + return nil, false, nil // kept already: the first take-in that wrote it stands + } + return data, false, nil + }) + if errors.Is(err, process.ErrNotYet) { + ix.logf("judge: the state %s is not on the bus yet, so the new manifest %s of %s is kept for its judging only in this take-in", UnjudgedBucket, digest, module) + return nil + } + if err != nil { + return fmt.Errorf("%s.%s: %w", UnjudgedState, digest, err) + } + return nil +} + +// withUnjudged is fresh with every digest the unjudged state holds; a state that cannot be listed is said and fresh +// alone is judged. +func (ix *Indexer) withUnjudged(ctx context.Context, fresh map[string]bool) map[string]bool { + if ix.Unjudged == nil { + return fresh + } + keys, err := ix.Unjudged.Keys(ctx) + if err != nil { + if !errors.Is(err, process.ErrNotYet) { + ix.logf("judge: the state %s cannot be listed (%v), so only this take-in's new manifests are judged as new", UnjudgedBucket, err) + } + return fresh + } + if len(keys) == 0 { + return fresh + } + out := maps.Clone(fresh) + if out == nil { + out = map[string]bool{} + } + for _, k := range keys { + out[k] = true + } + return out +} + +// endUnjudged deletes each key of the unjudged state whose digest the pass judged with its verdict written, or which no +// module holds any more (a later merge replaced it): what is left waits for the next pass. +func (ix *Indexer) endUnjudged(ctx context.Context, judged, held map[string]bool) { + if ix.Unjudged == nil { + return + } + keys, err := ix.Unjudged.Keys(ctx) + if err != nil { + return + } + for _, k := range slices.Sorted(slices.Values(keys)) { + if held[k] && !judged[k] { + continue + } + if err := write(ctx, ix.Unjudged, k, func(_ []byte, found bool) ([]byte, bool, error) { return nil, found, nil }); err != nil { + ix.logf("judge: %s.%s is not ended: %v; judged again as new by the next pass", UnjudgedState, k, err) + } + } +} diff --git a/modules/mesh-delivery-indexer/internal/index/verdicts.go b/modules/mesh-delivery-indexer/internal/index/verdicts.go index 75bdf287..0746bb07 100644 --- a/modules/mesh-delivery-indexer/internal/index/verdicts.go +++ b/modules/mesh-delivery-indexer/internal/index/verdicts.go @@ -84,11 +84,17 @@ func (ix *Indexer) judgeOverHeld(ctx context.Context, fresh map[string]bool, ove } if over == nil { ix.SayUnsaid(ctx) // a manifest-accepted a pass before failed to publish is said again first (DLV-I9b) + // What a take-in wrote and no pass judged yet is fresh too, whichever pass judges it (unjudged.go, issue 1966). + fresh = ix.withUnjudged(ctx, fresh) } held, err := ix.heldModules(ctx) if err != nil { return out, err } + heldDigests, judgedDigests := map[string]bool{}, map[string]bool{} + for _, m := range held { + heldDigests[m.Manifest] = m.Manifest != "" + } trunkOf := map[string]string{} // a judged change's module to the trunk's manifest digest it changes (DLV-I15) // The known packages a manifest's `packages` may name (DLV-I14). The digest judged the trunk does not hold (a pull // request's candidate, one the trunk no longer names) is not judged on them: the checker judges a change's names, @@ -212,6 +218,7 @@ func (ix *Indexer) judgeOverHeld(ctx context.Context, fresh map[string]bool, ove ix.logf("judge: the verdict on %s (digest %s) is not written: %v", name, digests[name], err) continue } + judgedDigests[digests[name]] = true if wrote && over != nil { out.Written++ ix.logf("judge: %s judged again by %s: %s", digests[name], id, v.State) @@ -243,6 +250,7 @@ func (ix *Indexer) judgeOverHeld(ctx context.Context, fresh map[string]bool, ove if over != nil { return out, nil } + ix.endUnjudged(ctx, judgedDigests, heldDigests) if err := ix.keepOldSections(ctx, judge.CountOldSections(accepted), judge.CountOwnerReads(accepted)); err != nil { ix.logf("judge: the count of the old sections is not kept: %v", err) } diff --git a/modules/mesh-delivery-indexer/internal/index/verdicts_test.go b/modules/mesh-delivery-indexer/internal/index/verdicts_test.go index 681b4cfd..204c20b5 100644 --- a/modules/mesh-delivery-indexer/internal/index/verdicts_test.go +++ b/modules/mesh-delivery-indexer/internal/index/verdicts_test.go @@ -13,6 +13,7 @@ import ( "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshcatalog" "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-forge-bridge/forgemsg" "git.novox.be/novox/mesh-sdk/go/catalogue" + "git.novox.be/novox/mesh-sdk/go/process" "mesh-delivery-indexer/judge" ) @@ -137,6 +138,37 @@ func TestTheIndexerJudgesEveryManifestOnce(t *testing.T) { if err := ix.writeOverlay(ctx, map[string]meshcatalog.ModulesByModuleValue{"old": same}, nil, w); err != nil || !w.fresh[other] { t.Fatalf("a changed digest is not fresh: %v %v", w.fresh, err) } + // 1966 (ADR 0668 §4, ADR 0579 §1): what a take-in newly wrote is kept on the bus until judged. A take-in writes a + // manifest a judge refuses in full, its judge pass fails on the verdicts state, and the next pass, which knows nothing + // of that take-in (a start, a pass kicked by a message), still refuses it in full, never as a warning, and ends the key. + ix.Unjudged = newMem() + keptDigest, err := ix.keepManifest(ctx, "kept", `{"module":"kept","version":"1","requires":["amqp"]}`) + if err != nil { + t.Fatal(err) + } + kw := &mergeWrite{repository: "novox/mesh-catalog", merge: "m-kept"} + keptValue := meshcatalog.ModulesByModuleValue{Fp2: "src2:" + strings.Repeat("e", 64), Manifest: keptDigest, Repository: "novox/mesh-catalog", Commit: "c3"} + if err := ix.writeOverlay(ctx, map[string]meshcatalog.ModulesByModuleValue{"kept": keptValue}, nil, kw); err != nil || !kw.fresh[keptDigest] { + t.Fatalf("the take-in's write: %v, fresh %v", err, kw.fresh) + } + if value, _, found, _ := ix.Unjudged.Get(ctx, keptDigest); !found || !strings.Contains(string(value), `"module":"kept"`) || !strings.Contains(string(value), "m-kept") { + t.Fatalf("the new manifest is not kept as unjudged: %s", value) + } + ix.Verdicts.(*memStore).failWrite = func(string) error { return process.ErrNotYet } + if _, err := ix.JudgeAll(ctx, kw.fresh); err == nil { + t.Fatal("a pass whose verdicts state is not on the bus did not fail") + } + ix.Verdicts.(*memStore).failWrite = nil + if j, err := ix.JudgeAll(ctx, nil); err != nil || slices.Contains(j.Outgrown, "kept") { + t.Fatalf("the next pass: %+v %v", j, err) + } + if v := verdict(keptDigest); !meshcatalogclient.VerdictRefuses(v) || len(v.Warnings) != 0 { + t.Fatalf("a refusal of a manifest whose judge pass failed became %+v", v) + } + if keys, err := ix.Unjudged.Keys(ctx); err != nil || len(keys) != 0 { + t.Fatalf("the unjudged state still holds %v (%v) after its verdict is written", keys, err) + } + ix.Unjudged = nil // 1966/AC10: a newly accepted manifest asking for bus state is said once as manifest-accepted, carrying both entries // whole; a verdict already held says nothing. var accepted []meshcatalog.ManifestAcceptedEvent diff --git a/modules/mesh-delivery-indexer/internal/index/views.go b/modules/mesh-delivery-indexer/internal/index/views.go index 3bb6ac6f..7bcffe38 100644 --- a/modules/mesh-delivery-indexer/internal/index/views.go +++ b/modules/mesh-delivery-indexer/internal/index/views.go @@ -32,6 +32,7 @@ var ReadTools = []ViewedTool{ {Tool: "indexer_read_taken", State: "taken", Words: "each repository's merge the indexer took in last."}, {Tool: "indexer_read_findings", State: mcc.FindingsState, Words: "the indexer's findings, which the condition keeper raises and clears."}, {Tool: "indexer_read_seat_definitions", State: SeatDefinitionsState, Words: "the seat definitions the trunk's and each open pull request's contracts modules hold, resolved, or why one does not parse."}, + {Tool: "indexer_read_unjudged", State: UnjudgedState, Words: "the manifests a take-in newly wrote that no judge pass judged yet, by digest, each with its module and merge; indexer_judge judges them."}, } // ViewedTool is one tool over one state of the indexer's. @@ -53,4 +54,5 @@ var ViewedStates = map[string]string{ "taken": TakenBucket, mcc.FindingsState: mcc.FindingsBucket(Module), SeatDefinitionsState: SeatDefinitionsBucket, + UnjudgedState: UnjudgedBucket, } diff --git a/modules/mesh-delivery-indexer/manifest_test.go b/modules/mesh-delivery-indexer/manifest_test.go index 1519ab5f..c5fa5e79 100644 --- a/modules/mesh-delivery-indexer/manifest_test.go +++ b/modules/mesh-delivery-indexer/manifest_test.go @@ -116,7 +116,7 @@ func TestManifestDeclarations(t *testing.T) { // 1238/AC1, 1444 (reads the build if want := []state{{Name: "candidates", History: 10}, {Name: "heard", History: 64}, {Name: "manifests", History: 1}, {Name: "modules", History: 20}, {Name: "predefined", History: 5}, {Name: "config-candidates", History: 5}, {Name: "taken", History: 1}, {Name: "takeins", History: 1}, {Name: "verdicts", History: 5}, {Name: "oldsections", History: 1}, {Name: "try-recovery", History: 1}, {Name: "own-build", History: 1}, {Name: index.PackagesState, History: index.PackagesHistory}, {Name: graph.State, History: graph.History}, {Name: views.MarksState, History: 1}, {Name: mcc.FindingsState, History: 5}, {Name: views.StatusState, History: 1}, {Name: index.RequirementsState, History: 5}, {Name: index.SeatDefinitionsState, History: 5}, - {Name: index.HoldsState, History: 5}, {Name: index.EngineReadsState, History: 1}, {Name: index.HoldBoundsState, History: 1, KeyTTL: true}, {Name: index.PendingState, History: 1}}; !reflect.DeepEqual(m.State, want) { // DLV-I7, DLV-I17, ADR 0632 §2 + {Name: index.HoldsState, History: 5}, {Name: index.EngineReadsState, History: 1}, {Name: index.HoldBoundsState, History: 1, KeyTTL: true}, {Name: index.PendingState, History: 1}, {Name: index.UnjudgedState, History: 1}}; !reflect.DeepEqual(m.State, want) { // DLV-I7, DLV-I17, ADR 0632 §2 t.Errorf("state = %+v, want %+v", m.State, want) } // D-11 (ADR 0634 §1): the holders and buckets the indexer names (internal/index/names.go) are its manifest's: its own @@ -176,7 +176,7 @@ func TestManifestDeclarations(t *testing.T) { // 1238/AC1, 1444 (reads the build index.SeatDefinitionTool, index.SeatDefinitionsAgainTool, index.OutOfStepTool, // DLV-I19 index.HoldsTool, index.EngineReadsTool, // ADR 0632 §2: the mesh-wide holds and the engines' reads they weigh index.PendingTool, index.TakeInPendingTool, index.DropPendingTool, index.TryCandidatesTool, index.DropTryCandidateTool, index.RecoverTriesTool, index.TakeInMergeTool, index.FingerprintsAgainTool) // issue 1966; 1585/T12, T13 (ADR 0633 §5) - if !reflect.DeepEqual(m.Tools, want) || len(want) != 39 { + if !reflect.DeepEqual(m.Tools, want) || len(want) != 40 { t.Errorf("tools = %v, want %v", m.Tools, want) } // Every read tool of the indexer a reader of this repository invokes is one it serves (the checker's seventh first diff --git a/modules/mesh-delivery-indexer/module.json b/modules/mesh-delivery-indexer/module.json index 67f8e7a5..41198549 100644 --- a/modules/mesh-delivery-indexer/module.json +++ b/modules/mesh-delivery-indexer/module.json @@ -36,6 +36,7 @@ "indexer_read_taken", "indexer_read_findings", "indexer_read_seat_definitions", + "indexer_read_unjudged", "indexer_first_views", "indexer_first_view_again", "indexer_config_readers", @@ -94,7 +95,8 @@ { "name": "holds", "history": 5 }, { "name": "engine-reads", "history": 1 }, { "name": "hold-bounds", "history": 1, "key-ttl": true }, - { "name": "pending", "history": 1 } + { "name": "pending", "history": 1 }, + { "name": "unjudged", "history": 1 } ], "emits": [ "take-in.pending",