mesh-issues and mesh-knowledge: pin mesh-sdk at its merge of CallerOf; mesh-knowledge reads the caller from the runtime (hq issue 365)
mesh/merge-gate pass: builds mesh-issues, mesh-knowledge → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery covered: a later merge that contains it was delivered: novox/mesh-catalog@a3f4387e2630 (merged as 300406e0 into main, walk plan-17917125412…

Both pin mesh-sdk/go at 4cf45b5 (mesh-sdk#20 merged). mesh-knowledge's one
reading of the caller, callerOf, now answers stdio.CallerOf, so a call on the
caller-named subject is recorded as its caller's bus user and any other as
unproven, never from the arguments.
This commit is contained in:
2026-10-11 11:26:45 +02:00
parent 66068febb0
commit f134ed5910
8 changed files with 87 additions and 21 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-issues
go 1.25.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011031108-d9e24e95a242
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011091942-4cf45b5ca0cf
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.51.0
)
+2 -4
View File
@@ -1,7 +1,5 @@
git.novox.be/novox/mesh-sdk/go v0.1.12 h1:QvmLlT88F+OYt8MOytMGM5ZEOo0fKmNZvNVeJe6gnTk=
git.novox.be/novox/mesh-sdk/go v0.1.12/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011031108-d9e24e95a242 h1:vpYUOltncgA+GCh/KI8e6azffB1K7768Ka+VuvqXjiE=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011031108-d9e24e95a242/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011091942-4cf45b5ca0cf h1:ED/+RszKwm86U7H/NZRbS4b5LzQ8n7rubqKmeFqFtvM=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011091942-4cf45b5ca0cf/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
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/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo=
+7 -5
View File
@@ -29,10 +29,11 @@ accepted only on the operator's Approve, given on a channel that proves who answ
`ask`, `get`, `holds` and `history` stay within `bound` bytes (4096 unless asked for, at most 65536) and say what they cut
and how to read the rest. The module's own tool `knowledge_health` answers its health (below).
**Who acted** is the caller as the runtime proves it, never an argument: no verb takes one. Today the runtime
does not hand a module its caller. The SDK's tool call carries only a name and arguments, so proving the caller
needs an SDK change first (hq issue 365). Until then every change is recorded as by `unproven`. In this module
the caller is read in one place, `callerOf` in `main.go`, so the SDK change touches that one function.
**Who acted** is the caller as the runtime proves it, never an argument: no verb takes one. The tool runner takes
the caller's bus user from the caller-named subject a call arrived on and hands it through the SDK
(`stdio.CallerOf`, hq issue 365). A call on the subject that names no caller (served beside it for one release, hq
issue 464), or through a runtime from before issue 365, is recorded as by `unproven`. In this module the caller is
read in one place, `callerOf` in `main.go`.
The rules about callers:
@@ -147,7 +148,8 @@ the consolidated schema for a fresh database is `schema.sql`. A test holds the t
- assignment to the control-node, and a postgres provider for its `postgres-database` provision;
- the issue tracker serving `issue-tracker.reserve` (hq issue 424, merged as mesh-catalog#204) on the mesh;
- the SDK and the runtime proving the caller (hq issue 365) before any review is taken;
- the runtime proving the caller (hq issue 365: mesh-tools#27 and mesh-controller#224 delivered) before any review
is taken;
- the import run once, then checked against hq record by record (hq issue 426).
## Tests
@@ -0,0 +1,65 @@
package main
import (
"bufio"
"encoding/json"
"io"
"testing"
"time"
stdio "git.novox.be/novox/mesh-sdk/go"
)
// whoCalled serves one tool that answers callerOf of its arguments, over the SDK's stdio loop as the runtime
// launches a bundle, and sends it one call with params.
func whoCalled(t *testing.T, params map[string]any) string {
t.Helper()
inR, inW := io.Pipe()
outR, outW := io.Pipe()
go func() {
_ = stdio.ServeOn("mesh-knowledge", []stdio.Tool{{Name: "who", Run: func(args map[string]any) (any, error) {
return callerOf(args), nil
}}}, inR, outW)
}()
defer inW.Close()
b, _ := json.Marshal(map[string]any{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": params})
_, _ = inW.Write(append(b, '\n'))
got := make(chan string, 1)
go func() {
lines := bufio.NewScanner(outR)
if lines.Scan() {
var m struct {
Result struct {
Content []struct {
Text string `json:"text"`
} `json:"content"`
} `json:"result"`
}
_ = json.Unmarshal(lines.Bytes(), &m)
var who string
if len(m.Result.Content) > 0 {
_ = json.Unmarshal([]byte(m.Result.Content[0].Text), &who)
}
got <- who
}
}()
select {
case who := <-got:
return who
case <-time.After(3 * time.Second):
t.Fatal("the call was not answered")
return ""
}
}
// **Who called is the caller the runtime proved** (hq issue 365): read from the call's runtime-written `_meta`,
// never from its arguments; Unproven where the runtime named none.
func TestTheCallerIsTheOneTheRuntimeProved(t *testing.T) {
if got := whoCalled(t, map[string]any{"name": "who", "arguments": map[string]any{"caller": "novox.node-tools"},
"_meta": map[string]any{stdio.MetaCaller: "shanks.node-tools"}}); got != "shanks.node-tools" {
t.Errorf("callerOf answered %q, want the runtime's caller", got)
}
if got := whoCalled(t, map[string]any{"name": "who", "arguments": map[string]any{"caller": "novox.node-tools"}}); got != Unproven {
t.Errorf("a call the runtime named no caller for answered %q, want %s", got, Unproven)
}
}
@@ -15,11 +15,13 @@ import (
"strings"
"sync"
"time"
stdio "git.novox.be/novox/mesh-sdk/go"
)
// Unproven is who acted, as recorded, while the runtime does not tell a module who called it (hq issue 365). The
// caller is never taken from an argument.
const Unproven = "unproven"
// Unproven is who acted, as recorded, where the runtime proves no caller (hq issue 365): the SDK's word. The caller
// is never taken from an argument.
const Unproven = stdio.Unproven
// proven says whether a caller is one the runtime proved.
func proven(caller string) bool { return caller != "" && caller != Unproven }
@@ -103,11 +103,10 @@ func serve(k *KB, status string) {
}
}
// callerOf is who called, as the runtime proves it: the one place the caller is read, so the change that brings it
// is this one function. The runtime does not hand a module its caller yet (hq issue 365): the SDK's tool call carries
// a name and arguments only, so the SDK must first pass the runtime's proven caller to a tool. Until it does, every
// caller is Unproven. It is never read from the call's arguments, so no caller can name another.
func callerOf(map[string]any) string { return Unproven }
// callerOf is who called, as the runtime proves it: the one place the caller is read. The tool runner takes the
// caller's bus user from the subject the call arrived on and hands it through the SDK (hq issue 365); Unproven where
// it proves none. It is never read from the call's arguments, so no caller can name another.
func callerOf(args map[string]any) string { return stdio.CallerOf(args) }
// hear subscribes to the router's word on this module's asks, asked again until the runtime takes it.
func hear(k *KB) {
+1 -1
View File
@@ -3,7 +3,7 @@ module mesh-knowledge
go 1.25.0
require (
git.novox.be/novox/mesh-sdk/go v0.1.12
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011091942-4cf45b5ca0cf
github.com/jackc/pgx/v5 v5.11.0
github.com/nats-io/nats-server/v2 v2.11.17
github.com/nats-io/nats.go v1.51.0
+2 -2
View File
@@ -1,5 +1,5 @@
git.novox.be/novox/mesh-sdk/go v0.1.12 h1:QvmLlT88F+OYt8MOytMGM5ZEOo0fKmNZvNVeJe6gnTk=
git.novox.be/novox/mesh-sdk/go v0.1.12/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011091942-4cf45b5ca0cf h1:ED/+RszKwm86U7H/NZRbS4b5LzQ8n7rubqKmeFqFtvM=
git.novox.be/novox/mesh-sdk/go v0.1.14-0.20261011091942-4cf45b5ca0cf/go.mod h1:GFuZUElBZ9A++mxgIKo97aXXo+kV0uJ/UkbhQPPIbrY=
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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=