The indexer's manifest-accepted event carries the manifest's bus-state entries whole (issue 1966 S5)

ADR 0595 §4, design 25 § 12.2: the bus module hears the accepted verdict
as an event with the entries, never reading the indexer's state; AcceptedOf
builds the body and EventID names it once per digest and judge.
This commit is contained in:
2026-11-03 13:24:04 +01:00
parent 510d983cc6
commit 2122ba52c0
2 changed files with 56 additions and 0 deletions
+28
View File
@@ -5,6 +5,8 @@ import (
"fmt"
"slices"
"time"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// The verdicts on manifests (novox/hq ADR 0578 §1, §3): the indexer judges every manifest it takes in once, with its own
@@ -28,6 +30,11 @@ const (
// raises it as a condition beside the indexer's finding.
ManifestRefusedEvent = "manifest-refused"
// ManifestAcceptedEvent is the indexer's event saying a manifest that asks for bus state was accepted
// (ManifestAccepted), carrying its bus-state entries whole, so the bus module creates them without reading the
// indexer's state (novox/hq ADR 0595 §4, design 25 § 12.2).
ManifestAcceptedEvent = "manifest-accepted"
// ManifestOutgrown is the finding of a manifest the indexer accepted before and a stricter judge finds problems in
// (novox/hq ADR 0579 §1): it stays accepted, its problems are the verdict's Warnings, and the watchman raises it as a
// warning until the manifest is mended.
@@ -154,3 +161,24 @@ type ManifestRefused struct {
func RefusedOf(digest string, v ManifestVerdict) ManifestRefused {
return ManifestRefused{V: Version, Module: v.Module, Digest: digest, Judge: v.Judge, Problems: v.Problems}
}
// ManifestAccepted is the body of the indexer's event ManifestAcceptedEvent: the module, the digest of its manifest, the
// judge, and every bus-state entry the manifest asks for, whole (novox/hq ADR 0595 §4).
type ManifestAccepted struct {
V int `json:"v"`
Module string `json:"module"`
Digest string `json:"digest"`
Judge string `json:"judge"`
BusState []catalogue.BusStateEntry `json:"bus-state"`
}
// AcceptedOf is the event body saying v, the verdict accepting the manifest m of digest.
func AcceptedOf(digest string, v ManifestVerdict, m catalogue.Manifest) ManifestAccepted {
return ManifestAccepted{V: Version, Module: v.Module, Digest: digest, Judge: v.Judge, BusState: m.BusState}
}
// EventID is the event's id, one per manifest digest and judge, so the bus takes it once:
// `manifest-accepted-<digest>-<judge>`.
func (a ManifestAccepted) EventID() string {
return ManifestAcceptedEvent + "-" + a.Digest + "-" + a.Judge
}
+28
View File
@@ -1,9 +1,13 @@
package delivery
import (
"encoding/json"
"reflect"
"strings"
"testing"
"time"
"git.novox.be/novox/mesh-sdk/go/catalogue"
)
// A verdict on a manifest round-trips, refuses what it cannot be, and a reader takes a missing one as accepted (novox/hq
@@ -72,4 +76,28 @@ func TestAManifestVerdictIsTheContractReadersTake(t *testing.T) {
if r, _ := TakeManifestVerdict(m.VerdictOf("x")); r || len(m.VerdictOf("x").Warnings) != 1 {
t.Fatalf("an outgrown module: %+v", m.VerdictOf("x"))
}
// 1966/AC6: the accepted event of a manifest with two bus-state entries carries both whole, and its id is
// manifest-accepted-<digest>-<judge>.
entries := []catalogue.BusStateEntry{
{Name: "drafts", Storage: catalogue.StorageKeyValue, Template: catalogue.TemplateState,
Options: map[string]json.RawMessage{catalogue.OptionPastValues: json.RawMessage(`5`)}},
{Name: "records", Storage: catalogue.StorageLedger, Template: catalogue.TemplateLedger,
Types: []catalogue.LedgerType{{Name: "decision", Operations: []catalogue.LedgerOperation{{Name: "submit", Effect: catalogue.EffectSetFields}}}}},
}
digest := strings.Repeat("d", 64)
accepted := AcceptedOf(digest, ManifestVerdict{Module: "mesh-knowledge", State: VerdictAccepted, Judge: "src2:j"},
catalogue.Manifest{Module: "mesh-knowledge", BusState: entries})
raw, err := json.Marshal(accepted)
if err != nil {
t.Fatal(err)
}
var heard ManifestAccepted
if err := json.Unmarshal(raw, &heard); err != nil || heard.Module != "mesh-knowledge" || heard.Digest != digest ||
heard.V != Version || !reflect.DeepEqual(heard.BusState, entries) {
t.Fatalf("the accepted event reads as %+v (%v)", heard, err)
}
if id := heard.EventID(); id != "manifest-accepted-"+digest+"-src2:j" {
t.Fatalf("the accepted event's id is %q", id)
}
}