From a4e3a9cbe09bab0db46ffee7bbce65d4f0b31252 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 4 Nov 2026 12:12:44 +0100 Subject: [PATCH] CAT-K8: the search index is in the module's memory (bleve), built from the ledger and kept as it writes ask and holds on the ledger answer from a full-text index of the heads and the current versions' text and clauses; it is built at start (index not built is the answer meanwhile), a new version replaces its record's documents, a reserved, withdrawn or retracted record has none. A new pure Go dependency, bleve. Issue 1966. Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig --- .../cmd/mesh-knowledge/index.go | 221 ++++++++++++++++++ .../cmd/mesh-knowledge/index_test.go | 66 ++++++ .../cmd/mesh-knowledge/ledgerstore.go | 33 ++- modules/mesh-knowledge/go.mod | 26 +++ modules/mesh-knowledge/go.sum | 52 +++++ 5 files changed, 389 insertions(+), 9 deletions(-) create mode 100644 modules/mesh-knowledge/cmd/mesh-knowledge/index.go create mode 100644 modules/mesh-knowledge/cmd/mesh-knowledge/index_test.go diff --git a/modules/mesh-knowledge/cmd/mesh-knowledge/index.go b/modules/mesh-knowledge/cmd/mesh-knowledge/index.go new file mode 100644 index 00000000..a679712f --- /dev/null +++ b/modules/mesh-knowledge/cmd/mesh-knowledge/index.go @@ -0,0 +1,221 @@ +package main + +// The search index (novox/hq to-be 55 §1, ADR 0597 §12): a full-text index in the module's own memory, written with the +// pure Go library bleve. At start the module reads every head from the ledger and the bodies of every current version into +// it, then keeps it current as it writes; `ask` and `holds` answer from it, and refuse with "index not built" while it is +// built. Nothing but the module writes it and nothing outside it reads it. + +import ( + "context" + "errors" + "fmt" + "sort" + "strings" + "sync" + "time" + + "github.com/blevesearch/bleve/v2" + "github.com/blevesearch/bleve/v2/analysis/lang/en" + "github.com/blevesearch/bleve/v2/mapping" + "github.com/blevesearch/bleve/v2/search/query" +) + +// ErrIndexNotBuilt is the answer of a question asked while the index is built. +var ErrIndexNotBuilt = errors.New("index not built: the search index is being built from the ledger; ask again in a moment (get, list and propose answer at once)") + +// searchIndex is the index and what it holds. +type searchIndex struct { + mu sync.Mutex + idx bleve.Index + built bool + builtAt time.Time + docs int + // docsOf are the documents each record has in the index, so a new version replaces them. + docsOf map[Key][]string +} + +func newSearchIndex() (*searchIndex, error) { + m := bleve.NewIndexMapping() + text := mapping.NewTextFieldMapping() + text.Analyzer = en.AnalyzerName + doc := bleve.NewDocumentMapping() + for _, f := range []string{"title", "topic", "text", "clause"} { + doc.AddFieldMappingsAt(f, text) + } + m.DefaultMapping = doc + idx, err := bleve.NewMemOnly(m) + if err != nil { + return nil, err + } + return &searchIndex{idx: idx, docsOf: map[Key][]string{}}, nil +} + +type indexDoc struct { + Title string `json:"title,omitempty"` + Topic string `json:"topic,omitempty"` + Text string `json:"text,omitempty"` + Clause string `json:"clause,omitempty"` +} + +// put replaces the documents of a record by those of its served version: its title, topic and sections as one document, +// and each clause in force or proposed as one of its own. A reserved, withdrawn or retracted record has none. +func (s *searchIndex) put(r *Record) error { + s.mu.Lock() + defer s.mu.Unlock() + key := r.Key() + b := s.idx.NewBatch() + for _, id := range s.docsOf[key] { + b.Delete(id) + } + delete(s.docsOf, key) + if r.Status != StatusReserved && r.Status != StatusWithdrawn && r.Status != StatusRetracted { + var body strings.Builder + for _, sec := range r.Sections { + body.WriteString(sec.Text + "\n") + } + id := fmt.Sprintf("%s/%d", key.Kind, key.Number) + if err := b.Index(id, indexDoc{Title: r.Title, Topic: r.Topic, Text: body.String()}); err != nil { + return err + } + ids := []string{id} + for _, c := range r.Clauses { + if c.Status == ClauseRetracted { + continue + } + cid := fmt.Sprintf("%s#%d", id, c.N) + if err := b.Index(cid, indexDoc{Clause: c.Text}); err != nil { + return err + } + ids = append(ids, cid) + } + s.docsOf[key] = ids + } + s.docs = 0 + for _, ids := range s.docsOf { + s.docs += len(ids) + } + return s.idx.Batch(b) +} + +// search ranks the documents against the question's words: a title weighs twice, as the in-memory ranking did. +func (s *searchIndex) search(question string, limit int) ([]Hit, error) { + s.mu.Lock() + built := s.built + s.mu.Unlock() + if !built { + return nil, ErrIndexNotBuilt + } + var words []string + for _, w := range wordsOf(question) { + if !askingWords[w] && len(w) >= 3 { + words = append(words, w) + } + } + if len(words) == 0 { + return nil, nil + } + var should []query.Query + for _, w := range words { + for field, boost := range map[string]float64{"title": 2, "topic": 1, "text": 0.05, "clause": 1} { + q := bleve.NewMatchQuery(w) + q.SetField(field) + q.SetBoost(boost) + should = append(should, q) + } + } + req := bleve.NewSearchRequestOptions(bleve.NewDisjunctionQuery(should...), 5000, 0, false) + res, err := s.idx.Search(req) + if err != nil { + return nil, err + } + var hits []Hit + for _, h := range res.Hits { + var kind string + var number, clause int + rest := h.ID + if i := strings.IndexByte(rest, '#'); i >= 0 { + if _, err := fmt.Sscanf(rest[i+1:], "%d", &clause); err != nil { + continue + } + rest = rest[:i] + } + if i := strings.IndexByte(rest, '/'); i >= 0 { + kind = rest[:i] + if _, err := fmt.Sscanf(rest[i+1:], "%d", &number); err != nil { + continue + } + } + hits = append(hits, Hit{Key: Key{kind, number}, Clause: clause, Rank: h.Score}) + } + sort.SliceStable(hits, func(i, j int) bool { + if hits[i].Rank != hits[j].Rank { + return hits[i].Rank > hits[j].Rank + } + if hits[i].Key != hits[j].Key { + return hits[i].Key.Number > hits[j].Key.Number + } + return hits[i].Clause < hits[j].Clause + }) + if limit > 0 && len(hits) > limit { + hits = hits[:limit] + } + return hits, nil +} + +// IndexState says how the index stands: built or not, when, and how many documents it holds. +type IndexState struct { + Built bool `json:"built"` + BuiltAt time.Time `json:"built-at,omitempty"` + Docs int `json:"documents"` +} + +func (s *searchIndex) state() IndexState { + s.mu.Lock() + defer s.mu.Unlock() + return IndexState{Built: s.built, BuiltAt: s.builtAt, Docs: s.docs} +} + +// BuildIndex reads every record from the ledger into the index and marks it built; asked again it builds it anew. +func (s *ledgerStore) BuildIndex(ctx context.Context) error { + idx, err := newSearchIndex() + if err != nil { + return err + } + all, err := s.All(ctx) + if err != nil { + return err + } + for _, e := range all { + if err := idx.put(e.Current); err != nil { + return err + } + } + idx.mu.Lock() + idx.built, idx.builtAt = true, time.Now().UTC() + idx.mu.Unlock() + s.mu.Lock() + s.index = idx + s.mu.Unlock() + return nil +} + +// IndexState is how the module's index stands. +func (s *ledgerStore) IndexState() IndexState { + s.mu.Lock() + idx := s.index + s.mu.Unlock() + if idx == nil { + return IndexState{} + } + return idx.state() +} + +// indexed keeps the index current with a version the store wrote. +func (s *ledgerStore) indexed(r *Record, current bool) { + if s.index == nil || !current { + return + } + if err := s.index.put(r); err != nil && s.logf != nil { + s.logf("[mesh-knowledge] the search index could not take %s: %v", r.Key(), err) + } +} diff --git a/modules/mesh-knowledge/cmd/mesh-knowledge/index_test.go b/modules/mesh-knowledge/cmd/mesh-knowledge/index_test.go new file mode 100644 index 00000000..48220eba --- /dev/null +++ b/modules/mesh-knowledge/cmd/mesh-knowledge/index_test.go @@ -0,0 +1,66 @@ +package main + +import ( + "errors" + "testing" +) + +// The search index (to-be 55 §1, AC52): built from the ledger at start, refusing "index not built" meanwhile, kept current +// as the module writes, and answering the questions the knowledge base is asked as the in-memory ranking does: the records +// the questions are about come first. +func TestTheSearchIndexAnswersTheQuestionsAsTheStoreDoes(t *testing.T) { + f := newFakeLedger(t) + ls := newLedgerStore(f, newFakeStates()) + w := newWorld(t, ls, fixture()) + w.k.States = newFakeStates() + ls.indexAsync = true + if _, err := ls.Search(t.Context(), "merge window", 5); !errors.Is(err, ErrIndexNotBuilt) { + t.Fatalf("a question before the index was built: %v", err) + } + if _, err := w.k.Import("import@test", ImportAsk{}, fixture()); err != nil { + t.Fatal(err) + } + if err := ls.BuildIndex(t.Context()); err != nil { + t.Fatal(err) + } + if st := ls.IndexState(); !st.Built || st.Docs < 20 { + t.Fatalf("%+v", st) + } + mem := imported(t, newMemStore()) + for _, q := range []string{"merge window", "how is the tool runtime chosen", "what holds about resolved names", "a knowledge base the mesh writes"} { + want, _ := mem.k.Store.Search(t.Context(), q, 3) + got, err := ls.Search(t.Context(), q, 8) + if err != nil { + t.Fatal(err) + } + // The ranking differs (the index weighs by how rare a word is), so the record the store puts first is among the + // first few of the index's. + found := false + for _, h := range got { + found = found || (len(want) > 0 && h.Key == want[0].Key) + } + if len(want) > 0 && !found { + t.Errorf("%q: the store puts %v first, the index %v", q, want[0], got) + } + } + // A new version is in the index at once; a withdrawn record is out of it. + r, _ := w.k.ReserveNumber("author@g14", KindDecision, "a test record") + if hits, _ := ls.Search(t.Context(), "zebra quantum", 5); len(hits) != 0 { + t.Fatalf("%v", hits) + } + p := valid(r.Number) + p.Title = "Zebra quantum processors" + p.Sections[2].Text = "A zebra quantum processor." + if _, err := w.k.Propose("author@g14", p); err != nil { + t.Fatal(err) + } + if hits, _ := ls.Search(t.Context(), "zebra quantum", 5); len(hits) == 0 || hits[0].Key.Number != r.Number { + t.Fatalf("a proposed record is not in the index: %v", hits) + } + if _, err := w.k.WithdrawRecord("author@g14", Key{KindDecision, r.Number}, "not needed"); err != nil { + t.Fatal(err) + } + if hits, _ := ls.Search(t.Context(), "zebra quantum", 5); len(hits) != 0 { + t.Fatalf("a withdrawn record is in the index: %v", hits) + } +} diff --git a/modules/mesh-knowledge/cmd/mesh-knowledge/ledgerstore.go b/modules/mesh-knowledge/cmd/mesh-knowledge/ledgerstore.go index 909920c7..85e861cf 100644 --- a/modules/mesh-knowledge/cmd/mesh-knowledge/ledgerstore.go +++ b/modules/mesh-knowledge/cmd/mesh-knowledge/ledgerstore.go @@ -93,6 +93,10 @@ type ledgerStore struct { // drafted are the sections written for a draft and named by no version yet: a version that carries one reuses its // write-section and writes none again. drafted map[Key][]sectionRef + // index is the search index of the module's memory, nil until built. + index *searchIndex + indexAsync bool + logf func(format string, a ...any) } // newLedgerStore is the store over a pipe and the module's states. @@ -350,13 +354,13 @@ func (s *ledgerStore) Create(ctx context.Context, v Version) error { if err != nil { return err } - return s.commit(ctx, k, operationFor(nil, v, true), &entryHead{CurrentVersion: 1, Versions: 1, Current: ptr(stripped(v.Record, refs))}, v, refs) + return s.commit(ctx, k, operationFor(nil, v, true), &entryHead{CurrentVersion: 1, Versions: 1, Current: ptr(stripped(v.Record, refs))}, v, refs, true) } func ptr[T any](v T) *T { return &v } // commit appends the operation that carries the new head and the version, and holds the head it derived. -func (s *ledgerStore) commit(ctx context.Context, k Key, op string, e *entryHead, v Version, refs []sectionRef) error { +func (s *ledgerStore) commit(ctx context.Context, k Key, op string, e *entryHead, v Version, refs []sectionRef, current bool) error { body := map[string]any{"kind": k.Kind, "number": k.Number, "entry": e, "version": versionHead{N: v.N, By: v.By, At: v.At, Why: v.Why, Insight: v.Insight, Record: stripped(v.Record, refs)}, "pending-sections": map[string]any{}} @@ -366,6 +370,7 @@ func (s *ledgerStore) commit(ctx context.Context, k Key, op string, e *entryHead } s.heads[k] = &headState{Kind: k.Kind, Number: k.Number, Entry: e, Sequence: seq} delete(s.drafted, k) + s.indexed(v.Record, current) return nil } @@ -455,7 +460,7 @@ func (s *ledgerStore) Save(ctx context.Context, v Version, current, clearPending if clearPending { e.Pending, e.PendingVersion = nil, 0 } - return s.commit(ctx, k, operationFor(old, v, current), &e, v, refs) + return s.commit(ctx, k, operationFor(old, v, current), &e, v, refs, current) } func (s *ledgerStore) Versions(_ context.Context, k Key) ([]Version, error) { @@ -493,14 +498,24 @@ func (s *ledgerStore) Versions(_ context.Context, k Key) ([]Version, error) { return out, nil } -// Search ranks the served versions as the in-memory store does, over every record; the index of the module's memory -// replaces it (the search index of to-be 55 §1). +// Search ranks the served versions from the index of the module's memory; it is built on the first question when no start +// built it, and refuses with "index not built" while a start builds it. func (s *ledgerStore) Search(ctx context.Context, question string, limit int) ([]Hit, error) { - all, err := s.All(ctx) - if err != nil { - return nil, err + s.mu.Lock() + idx, async := s.index, s.indexAsync + s.mu.Unlock() + if idx == nil { + if async { + return nil, ErrIndexNotBuilt + } + if err := s.BuildIndex(ctx); err != nil { + return nil, err + } + s.mu.Lock() + idx = s.index + s.mu.Unlock() } - return searchEntries(all, question, limit), nil + return idx.search(question, limit) } func (s *ledgerStore) Inbound(_ context.Context, k Key) ([]Inbound, error) { diff --git a/modules/mesh-knowledge/go.mod b/modules/mesh-knowledge/go.mod index 7c1e9678..1046d142 100644 --- a/modules/mesh-knowledge/go.mod +++ b/modules/mesh-knowledge/go.mod @@ -10,19 +10,45 @@ require ( ) require ( + github.com/RoaringBitmap/roaring/v2 v2.14.5 // indirect github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op // indirect + github.com/bits-and-blooms/bitset v1.24.2 // indirect + github.com/blevesearch/bleve/v2 v2.6.3 // indirect + github.com/blevesearch/bleve_index_api v1.4.1 // indirect + github.com/blevesearch/geo v0.2.8 // indirect + github.com/blevesearch/go-faiss v1.1.5 // indirect + github.com/blevesearch/go-porterstemmer v1.0.3 // indirect + github.com/blevesearch/gtreap v0.1.1 // indirect + github.com/blevesearch/mmap-go v1.2.0 // indirect + github.com/blevesearch/scorch_segment_api/v2 v2.4.11 // indirect + github.com/blevesearch/segment v0.9.1 // indirect + github.com/blevesearch/snowballstem v0.9.0 // indirect + github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect + github.com/blevesearch/vellum v1.2.1 // indirect + github.com/blevesearch/zapx/v11 v11.4.3 // indirect + github.com/blevesearch/zapx/v12 v12.4.3 // indirect + github.com/blevesearch/zapx/v13 v13.4.3 // indirect + github.com/blevesearch/zapx/v14 v14.4.3 // indirect + github.com/blevesearch/zapx/v15 v15.4.3 // indirect + github.com/blevesearch/zapx/v16 v16.3.4 // indirect + github.com/blevesearch/zapx/v17 v17.2.5 // indirect + github.com/golang/snappy v1.0.0 // indirect github.com/google/go-tpm v0.9.8 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/json-iterator/go v0.0.0-20171115153421-f7279a603ede // indirect github.com/klauspost/compress v1.20.0 // indirect github.com/minio/highwayhash v1.0.4 // indirect + github.com/mschoch/smat v0.2.0 // indirect github.com/nats-io/jwt/v2 v2.8.1 // indirect github.com/nats-io/nkeys v0.4.16 // indirect github.com/nats-io/nuid v1.0.1 // indirect + go.etcd.io/bbolt v1.4.0 // indirect golang.org/x/crypto v0.57.0 // indirect golang.org/x/sync v0.23.0 // indirect golang.org/x/sys v0.48.0 // indirect golang.org/x/text v0.42.0 // indirect golang.org/x/time v0.15.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/modules/mesh-knowledge/go.sum b/modules/mesh-knowledge/go.sum index c812cb1b..6c1766ac 100644 --- a/modules/mesh-knowledge/go.sum +++ b/modules/mesh-knowledge/go.sum @@ -1,10 +1,54 @@ git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128 h1:aI1DhZAuqVBXbybSqhLNOGX5rUOrn9T0cHNCDUQF7IQ= git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261102191058-f02f142af128/go.mod h1:ouERNpZizzwZ0HLEtAypsY9FR20FyUgUYRni6J7kVCY= +github.com/RoaringBitmap/roaring/v2 v2.14.5 h1:ckd0o545JqDPeVJDgeFoaM21eBixUnlWfYgjE5VnyWw= +github.com/RoaringBitmap/roaring/v2 v2.14.5/go.mod h1:eq4wdNXxtJIS/oikeCzdX1rBzek7ANzbth041hrU8Q4= 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/bits-and-blooms/bitset v1.24.2 h1:M7/NzVbsytmtfHbumG+K2bremQPMJuqv1JD3vOaFxp0= +github.com/bits-and-blooms/bitset v1.24.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/blevesearch/bleve/v2 v2.6.3 h1:+TvSTA10Kr5c8Dj7gidTIufor8fg7pIj4rQu2Vmw9L0= +github.com/blevesearch/bleve/v2 v2.6.3/go.mod h1:cXYhNm5W1L8az+qt5j3D+zoVe268ZR34ymfFy6PDvdg= +github.com/blevesearch/bleve_index_api v1.4.1 h1:CYIyecFlI+/RYjzUm+NmDjYbSvk870Bb7f+Vl4b12q8= +github.com/blevesearch/bleve_index_api v1.4.1/go.mod h1:xvd48t5XMeeioWQ5/jZvgLrV98flT2rdvEJ3l/ki4Ko= +github.com/blevesearch/geo v0.2.8 h1:nNgtlEfLzeWH4/UJZD4k5kP+E4cI+ogfmSti0XGnWNM= +github.com/blevesearch/geo v0.2.8/go.mod h1:07qi9wrXpXWIscoMrKBykIdBdrWxnyVV4tmpq1eT8YQ= +github.com/blevesearch/go-faiss v1.1.5 h1:/IU5lkOahH9Ghfk9n3F6N0XD7PYVXZJWmNDc9TtXuco= +github.com/blevesearch/go-faiss v1.1.5/go.mod h1:w3W9AiWsFRGVaMG+/cmJi7iHEAuGyC6blsgO1EzCK/M= +github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= +github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= +github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= +github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk= +github.com/blevesearch/mmap-go v1.2.0 h1:l33nNKPFcBjJUMwem6sAYJPUzhUCABoK9FxZDGiFNBI= +github.com/blevesearch/mmap-go v1.2.0/go.mod h1:Vd6+20GBhEdwJnU1Xohgt88XCD/CTWcqbCNxkZpyBo0= +github.com/blevesearch/scorch_segment_api/v2 v2.4.11 h1:VTXi18tB7YQMWSM/K16+z7ji1hK5PwvlS7MtzRCAJus= +github.com/blevesearch/scorch_segment_api/v2 v2.4.11/go.mod h1:OHLLgtco0DySTL1uVESnmObFqn64MRX3aCKNQtXPi9M= +github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU= +github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw= +github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s= +github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= +github.com/blevesearch/upsidedown_store_api v1.0.2 h1:U53Q6YoWEARVLd1OYNc9kvhBMGZzVrdmaozG2MfoB+A= +github.com/blevesearch/upsidedown_store_api v1.0.2/go.mod h1:M01mh3Gpfy56Ps/UXHjEO/knbqyQ1Oamg8If49gRwrQ= +github.com/blevesearch/vellum v1.2.1 h1:PYryJDqBHjLM6n3YindZSQcrseaMs8QpcsrrAOpwwj8= +github.com/blevesearch/vellum v1.2.1/go.mod h1:uEcfBJz7mAOf0Kvq6qoEKQQkLODBF46SINYNkZNae4k= +github.com/blevesearch/zapx/v11 v11.4.3 h1:PTZOO5loKpHC/x/GzmPZNa9cw7GZIQxd5qRjwij9tHY= +github.com/blevesearch/zapx/v11 v11.4.3/go.mod h1:4gdeyy9oGa/lLa6D34R9daXNUvfMPZqUYjPwiLmekwc= +github.com/blevesearch/zapx/v12 v12.4.3 h1:eElXvAaAX4m04t//CGBQAtHNPA+Q6A1hHZVrN3LSFYo= +github.com/blevesearch/zapx/v12 v12.4.3/go.mod h1:TdFmr7afSz1hFh/SIBCCZvcLfzYvievIH6aEISCte58= +github.com/blevesearch/zapx/v13 v13.4.3 h1:qsdhRhaSpVnqDFlRiH9vG5+KJ+dE7KAW9WyZz/KXAiE= +github.com/blevesearch/zapx/v13 v13.4.3/go.mod h1:knK8z2NdQHlb5ot/uj8wuvOq5PhDGjNYQQy0QDnopZk= +github.com/blevesearch/zapx/v14 v14.4.3 h1:GY4Hecx0C6UTmiNC2pKdeA2rOKiLR5/rwpU9WR51dgM= +github.com/blevesearch/zapx/v14 v14.4.3/go.mod h1:rz0XNb/OZSMjNorufDGSpFpjoFKhXmppH9Hi7a877D8= +github.com/blevesearch/zapx/v15 v15.4.3 h1:iJiMJOHrz216jyO6lS0m9RTCEkprUnzvqAI2lc/0/CU= +github.com/blevesearch/zapx/v15 v15.4.3/go.mod h1:1pssev/59FsuWcgSnTa0OeEpOzmhtmr/0/11H0Z8+Nw= +github.com/blevesearch/zapx/v16 v16.3.4 h1:hDAqA8qusZTNbPEL7//w5P65UZ2de6yhSeUaTbp0Po0= +github.com/blevesearch/zapx/v16 v16.3.4/go.mod h1:zqkPPqs9GS9FzVWzCO3Wf1X044yWAV17+4zb+FTiEHg= +github.com/blevesearch/zapx/v17 v17.2.5 h1:1A3bXvT/8XkEVaUQBfD0jQBAO8kSQEiCwgrRNPKp0TE= +github.com/blevesearch/zapx/v17 v17.2.5/go.mod h1:8SHp6q+3FNVCqPyRiTFZDSRm1WA2G8Q3zCk8lRBfhT4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -15,10 +59,14 @@ github.com/jackc/pgx/v5 v5.11.0 h1:IzBBtyK9AHqf98cctWFifYSci2hgQR/cd56wB4p+ogg= github.com/jackc/pgx/v5 v5.11.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/json-iterator/go v0.0.0-20171115153421-f7279a603ede h1:YrgBGwxMRK0Vq0WSCWFaZUnTsrA/PZE/xs1QZh+/edg= +github.com/json-iterator/go v0.0.0-20171115153421-f7279a603ede/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/klauspost/compress v1.20.0 h1:a3C1ke2ohxFymNlb2HWAHjDeKCI90scRskErZkR0ezA= github.com/klauspost/compress v1.20.0/go.mod h1:LUdAzn7YLVvxLpc7y3V1m40wESHTgc1422pwwBSKYuI= github.com/minio/highwayhash v1.0.4 h1:asJizugGgchQod2ja9NJlGOWq4s7KsAWr5XUc9Clgl4= github.com/minio/highwayhash v1.0.4/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= +github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= +github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= github.com/nats-io/jwt/v2 v2.8.1 h1:V0xpGuD/N8Mi+fQNDynXohVvp7ZztevW5io8CUWlPmU= github.com/nats-io/jwt/v2 v2.8.1/go.mod h1:nWnOEEiVMiKHQpnAy4eXlizVEtSfzacZ1Q43LIRavZg= github.com/nats-io/nats-server/v2 v2.11.17 h1:GKEghcFK6A+aFx11Yf1LjgLC3txAwvyhnYzhBIQZA8I= @@ -36,6 +84,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= +go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M= golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA= golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= @@ -47,6 +97,8 @@ golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=