From b47668421fbb3297b841865e7d12e59e661b8795 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 3 Nov 2026 14:02:01 +0100 Subject: [PATCH] =?UTF-8?q?The=20witness=20judges=20the=20tool=20runner's?= =?UTF-8?q?=20process=20by=20its=20id,=20.runtime,=20which?= =?UTF-8?q?=20the=20composition=20gives=20only=20the=20module=20whose=20ma?= =?UTF-8?q?nifest=20says=20it=20is=20the=20tool=20runner,=20never=20by=20a?= =?UTF-8?q?=20name=20(ADR=200601=20=C2=A74;=20review=20round=201,=20findin?= =?UTF-8?q?g=204)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/apply/process.go | 2 +- internal/witness/contract.go | 17 ++++++++--------- internal/witness/contract_test.go | 11 +++++++---- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/internal/apply/process.go b/internal/apply/process.go index 80c386e..121b683 100644 --- a/internal/apply/process.go +++ b/internal/apply/process.go @@ -536,7 +536,7 @@ func witnessOf(r *declaration.Process) string { if r.Witness != "" { return r.Witness } - return witness.Default(r.Name) + return witness.Default(r.ID, r.Name) } // digestWritten is the bundle digest a process's record says was placed: the first half of what it diff --git a/internal/witness/contract.go b/internal/witness/contract.go index 35e8b0b..9c1c6e6 100644 --- a/internal/witness/contract.go +++ b/internal/witness/contract.go @@ -9,6 +9,7 @@ package witness import ( "time" + "github.com/novox/mesh-host/internal/compose/resolution" "github.com/novox/mesh-host/internal/link" ) @@ -33,15 +34,13 @@ const ( GiveUp = 30 * time.Minute ) -// NodeToolsService is the runtime's name on the services protocol, and its instance is this -// machine's node name: what `$SRV.PING..` asks, so only this machine's runtime can -// answer (mesh-tools node-tools internal/runtime, announce.Service{Name: module, ID: node}). -const NodeToolsService = "node-tools" - -// Default is the witness a process is judged by when it names none: the core process the mesh composes on every -// machine, by the name it composes it under, and nothing else. -func Default(process string) string { - if process == NodeToolsService { +// Default is the witness a process is judged by when it names none: the tool runner's process, the core process the mesh +// composes on every machine for the module whose manifest says it is the tool runner (catalogue.IsToolRunner), with the id +// `.runtime` and named as its module (resolution's runtime process), and nothing else. It is pinged by that +// name on this machine's instance, `$SRV.PING..`, so only this machine's runtime answers; never known here by +// a module's name (ADR 0601 §4). +func Default(id, process string) string { + if process != "" && id == process+"."+resolution.RuntimeProcessID() { return ByPing } return ByNone diff --git a/internal/witness/contract_test.go b/internal/witness/contract_test.go index 2ea5c5c..6677fe9 100644 --- a/internal/witness/contract_test.go +++ b/internal/witness/contract_test.go @@ -13,7 +13,7 @@ import ( // The runtime is asked by its own name and this machine's: only this machine's runtime can answer. func TestTheRuntimeIsAskedByItsNameAndThisMachines(t *testing.T) { - if got := link.PingSubject(NodeToolsService, "anchor"); got != "$SRV.PING.node-tools.anchor" { + if got := link.PingSubject("runner-x", "anchor"); got != "$SRV.PING.runner-x.anchor" { t.Fatalf("the host asks %s; the runtime answers $SRV.PING.node-tools.", got) } } @@ -21,9 +21,12 @@ func TestTheRuntimeIsAskedByItsNameAndThisMachines(t *testing.T) { // What is judged by default is the mesh's core process on every machine, by the name it is composed under, and // nothing else: the controller ended (issue 1126), so its name is judged as any other. func TestOnlyTheCoreProcessIsJudgedByDefault(t *testing.T) { - for name, want := range map[string]string{"mesh-controller": ByNone, "node-tools": ByPing, "greeter": ByNone} { - if got := Default(name); got != want { - t.Errorf("%s is judged by %q, want %q", name, got, want) + // The tool runner's process by its id and name, whatever its module is called (ADR 0601 §4); a process named so by + // another id, or another process, is not. + for id, want := range map[string]string{"runner-x.runtime": ByPing, "node-tools.runtime": ByNone, "runner-x.server": ByNone, + "mesh-controller.runtime": ByNone} { + if got := Default(id, "runner-x"); got != want { + t.Errorf("%s is judged by %q, want %q", id, got, want) } } if NodeToolsWithin != 60*time.Second || PingWithin != 5*time.Second {