Serve a key's kept values so the issue tracker can carry them into its log (ADR 0307, issue 502)
mesh/delivery-group group adr-0307-state-history delivered: every member is delivered
mesh/delivery delivered
mesh/merge-gate pass: builds mesh-tools, node-tools → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of …
mesh/repo-check pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the change's judges the pull requests after it merges; it…

mesh/state.history answers every value a bucket still keeps for a key,
oldest first, to whoever may get it, by the same watch the runtime already
uses, so no new grant is needed.
This commit is contained in:
jochen
2026-10-12 10:18:34 +02:00
parent 4348b42844
commit 3f0c1a6cec
6 changed files with 219 additions and 5 deletions
+44
View File
@@ -129,6 +129,50 @@ func (c *Conn) StateGet(module, name, key string) (*StateEntry, error) {
return &StateEntry{Key: e.Key(), Value: valueOf(e.Value()), Revision: e.Revision()}, nil
}
// StateKept is one value a bucket still keeps for a key: a put, or a delete (a purge reads as one).
type StateKept struct {
Key string `json:"key"`
Value json.RawMessage `json:"value,omitempty"`
Revision uint64 `json:"revision"`
Op string `json:"op"`
At time.Time `json:"at"`
}
// StateHistory is every value the bucket still keeps for one key, oldest first, or none (novox/hq ADR
// 0307). It is a read like StateGet: served to the owner and to every reader, and writes nothing.
func (c *Conn) StateHistory(module, name, key string) ([]StateKept, error) {
s, err := c.issuedState(module, name)
if err != nil {
return nil, err
}
if err := checkKey(key); err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), StateTimeout)
defer cancel()
kv, err := c.bucket(ctx, s)
if err != nil {
return nil, err
}
entries, err := kv.History(ctx, key)
kept := []StateKept{}
if errors.Is(err, jetstream.ErrKeyNotFound) {
return kept, nil
}
if err != nil {
return nil, err
}
for _, e := range entries {
k := StateKept{Key: e.Key(), Revision: e.Revision(), Op: "delete", At: e.Created().UTC()}
if e.Operation() == jetstream.KeyValuePut {
k.Op = "put"
k.Value = valueOf(e.Value())
}
kept = append(kept, k)
}
return kept, nil
}
// StatePut writes one key, as the module, where the module keeps the state. It answers the revision.
func (c *Conn) StatePut(module, name, key string, value json.RawMessage) (uint64, error) {
s, err := c.writable(module, name)