Feature 57 (config and provisioning): release mesh-tools (the provider's StateBus, the SDK pin, templates), reviewed
mesh/merge-gate head 33d136e70227 merged into trunk 6b3e15042fee — pass, with a note: builds mesh-tools, node-tools (+40 dependent(s)) → ace, g14, novox, s…
mesh/repo-check head 33d136e70227 merged into trunk 6b3e15042fee — pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the ch…
mesh/delivery delivered

This commit is contained in:
2026-10-16 09:41:17 +00:00
parent 6b3e15042f
commit 33d136e702
14 changed files with 963 additions and 8 deletions
@@ -0,0 +1,107 @@
package launch
import (
"encoding/json"
"os"
"path/filepath"
"slices"
"strings"
"sync"
"testing"
"time"
)
// A bundle that asks for one of its values and watches it, and writes each change it is handed to $OUT.
const provisionBundle = `#!/bin/sh
while IFS= read -r line; do
id=$(printf '%s' "$line" | sed -n 's/.*"id":\([0-9]*\)[,}].*/\1/p')
case "$line" in
*'"method":"initialize"'*) printf '{"jsonrpc":"2.0","id":%s,"result":{}}\n' "$id" ;;
*'"method":"tools/list"'*)
printf '{"jsonrpc":"2.0","id":%s,"result":{"tools":[]}}\n' "$id"
printf '{"jsonrpc":"2.0","id":"g1","method":"mesh/provision.get","params":{"kind":"config","key":"role"}}\n'
printf '{"jsonrpc":"2.0","id":"w1","method":"mesh/provision.watch","params":{"kind":"config","key":"role"}}\n' ;;
*'"method":"mesh/provision"'*)
printf '%s\n' "$line" >> "$OUT"
printf '{"jsonrpc":"2.0","id":%s,"result":{}}\n' "$id" ;;
*'"id":"g1"'*) printf '%s\n' "$line" >> "$OUT" ;;
esac
done
`
type provisioning struct {
subscribing
mu sync.Mutex
asked []string
}
func (b *provisioning) Provision(verb string, params json.RawMessage) (json.RawMessage, error) {
b.mu.Lock()
defer b.mu.Unlock()
b.asked = append(b.asked, verb+" "+string(params))
return json.RawMessage(`"the build machine"`), nil
}
func (b *provisioning) ProvisionWatch(params json.RawMessage, deliver func(json.RawMessage) error) (func(), error) {
b.mu.Lock()
b.asked = append(b.asked, "watch "+string(params))
b.mu.Unlock()
return func() {}, deliver(json.RawMessage(`{"kind":"config","key":"role","value":"the build machine"}`))
}
// novox/hq ADR 0349 §14, ADR 0370 §4: a bundle's ask for its values reaches the runtime's bus from its own channel,
// answered there, and a watch's change is handed to it naming the watch it asked.
func TestABundleAsksForItsValuesAndIsHandedItsWatchsChanges(t *testing.T) {
entry := filepath.Join(t.TempDir(), "bundle")
if err := os.WriteFile(entry, []byte(provisionBundle), 0o755); err != nil {
t.Fatal(err)
}
out := filepath.Join(t.TempDir(), "out")
b := &provisioning{}
l, err := Start("claude-code", entry, append(os.Environ(), "OUT="+out), b, t.Logf)
if err != nil {
t.Fatal(err)
}
t.Cleanup(l.Stop)
deadline := time.Now().Add(10 * time.Second)
for {
said, _ := os.ReadFile(out)
if strings.Count(string(said), "\n") >= 2 {
// Each line as the bundle read it, by what it is: the get's answer, and the watch's change.
got := map[string]string{}
for _, line := range strings.Split(strings.TrimSpace(string(said)), "\n") {
var m struct {
ID any `json:"id"`
Method string `json:"method"`
Result json.RawMessage `json:"result"`
Params json.RawMessage `json:"params"`
}
if err := json.Unmarshal([]byte(line), &m); err != nil {
t.Fatalf("the bundle read %s", line)
}
if m.Method != "" {
got[m.Method] = string(m.Params)
} else {
got["answer"] = string(m.Result)
}
}
if got["answer"] != `"the build machine"` {
t.Errorf("the get was answered %s", got["answer"])
}
if got["mesh/provision"] != `{"change":{"kind":"config","key":"role","value":"the build machine"},"watch":"w1"}` {
t.Errorf("the watch was handed %s", got["mesh/provision"])
}
break
}
if time.Now().After(deadline) {
t.Fatalf("the bundle was handed %q", said)
}
time.Sleep(20 * time.Millisecond)
}
b.mu.Lock()
defer b.mu.Unlock()
slices.Sort(b.asked)
if len(b.asked) != 2 || b.asked[0] != `get {"kind":"config","key":"role"}` || b.asked[1] != `watch {"kind":"config","key":"role"}` {
t.Errorf("the runtime's bus was asked %q", b.asked)
}
}