A newest hold's key is <node>.<module>=newest, which the bus holds, and the test store refuses what the bus refuses (issue 1966)
mesh/delivery merged: source.main moved to novox/mesh-catalog@89cd8a2e8ed2
mesh/check checking 4658e1cb1c6c on 6a24e4d0c77e

Review round 2: '@' is outside the bus's key rule, so every newest hold failed to write
on the live bus while the in-memory store took it.

Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
2026-11-09 09:06:39 +01:00
parent 6e6b325cf1
commit 4658e1cb1c
4 changed files with 15 additions and 6 deletions
@@ -220,7 +220,7 @@ func TestARefusedOrMissingCompositionHoldsItsModule(t *testing.T) {
if _, err := h.ComposeNode(context.Background(), c.Node); err != nil {
t.Fatal(err)
}
if e, _ := s.Get(RefusedState, "n1.restic@newest"); e == nil || !strings.Contains(string(e.Value), row.held) {
if e, _ := s.Get(RefusedState, "n1.restic=newest"); e == nil || !strings.Contains(string(e.Value), row.held) {
t.Errorf("%s: refused holds %s", row.name, valueOf(e))
}
h.Compose = FromCompositions(s)
@@ -232,7 +232,7 @@ func TestARefusedOrMissingCompositionHoldsItsModule(t *testing.T) {
if _, err := h.ComposeNode(context.Background(), c.Node); err != nil {
t.Fatal(err)
}
if e, _ := s.Get(RefusedState, "n1.restic@newest"); e != nil {
if e, _ := s.Get(RefusedState, "n1.restic=newest"); e != nil {
t.Errorf("the newest hold stays once the composition is read: %s", valueOf(e))
}
}
@@ -64,7 +64,7 @@ type Refusal struct {
Module string `json:"module"`
Why string `json:"why"`
Since time.Time `json:"since"`
// Scope is "newest" for a module held at its newest build (its composition there unread: key `<node>.<module>@newest`),
// Scope is "newest" for a module held at its newest build (its composition there unread: key `<node>.<module>=newest`),
// "" for one held at its wanted build.
Scope string `json:"scope,omitempty"`
}
@@ -364,7 +364,7 @@ func (h *Holder) ComposeNodeWith(ctx context.Context, node string, retireMany bo
// of the state is the event a watcher hears.
func (h *Holder) writeRefused(node string, held, heldNewest map[string]string) error {
var problems []error
// Each hold has a key: `<node>.<module>` at the wanted build, `<node>.<module>@newest` at the newest.
// Each hold has a key: `<node>.<module>` at the wanted build, `<node>.<module>=newest` at the newest.
type hold struct {
key string
r Refusal
@@ -381,7 +381,7 @@ func (h *Holder) writeRefused(node string, held, heldNewest map[string]string) e
continue
}
if scope.name != "" {
key += "@" + scope.name
key += "=" + scope.name
}
holds = append(holds, hold{key, Refusal{Node: node, Module: module, Why: scope.by[module], Since: h.Now().UTC(), Scope: scope.name}})
}
@@ -731,7 +731,7 @@ func TestARetirementIsJudgedOnlyFromAWholePicture(t *testing.T) {
t.Errorf("the pass does not say the key is kept: %v", c.Changed)
}
// The hold is on the bus, in `refused` beside the wanted build's, so a restart or another instance sees it.
if e, _ := m.s.Get(RefusedState, "novox.de-spiegel@newest"); e == nil || !strings.Contains(string(e.Value), `"scope":"newest"`) ||
if e, _ := m.s.Get(RefusedState, "novox.de-spiegel=newest"); e == nil || !strings.Contains(string(e.Value), `"scope":"newest"`) ||
!strings.Contains(string(e.Value), "not published") {
t.Errorf("refused holds %s", valueOf(e))
}
@@ -2,7 +2,9 @@ package main
import (
"encoding/json"
"fmt"
"os"
"regexp"
"slices"
"sort"
"strings"
@@ -32,7 +34,14 @@ func (m *memStore) Get(state, key string) (*Entry, error) {
return &Entry{Key: key, Value: append([]byte(nil), v...)}, nil
}
// busKey is the bus's key-value key rule (nats.go's validKeyRe): the store refuses what the bus refuses, so a key
// the live bus cannot hold fails here too.
var busKey = regexp.MustCompile(`^[-/_=\.a-zA-Z0-9]+$`)
func (m *memStore) Put(state, key string, value any) error {
if !busKey.MatchString(key) {
return fmt.Errorf("nats: invalid key %q", key)
}
raw, err := json.Marshal(value)
if err != nil {
return err