End every wait in flight when the tool runner stops (issue 745)
mesh/merge-gate head 21d038d3397c merged into trunk 5d70eb3e35a9 — pass, with a note: builds mesh-tools, node-tools (+39 dependent(s)) → ace, g14, novox, s…
mesh/repo-check head 21d038d3397c merged into trunk 5d70eb3e35a9 — pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the ch…
mesh/delivery delivered

Closing the console shut its server down with a context that never ends, so a stop or restart of
the tool runner waited on any mesh_wait in flight for up to ten minutes. The server's base context
is now cancelled first, ending every wait at once, with a five-second shutdown as a backstop
(second review of issue 745).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 00:47:59 +00:00
co-authored by Claude Opus 5.5
parent 5d70eb3e35
commit 21d038d339
12 changed files with 775 additions and 18 deletions
+12 -6
View File
@@ -2,8 +2,8 @@ package console
// The mesh's tools found by address, not announced whole (novox/hq ADR 0195, to-be 34 §3a).
//
// The console announces six tools — five to find and call, and mesh_runtimes to say which runtimes
// discovery heard. Everything the mesh answers is reached through them by one address per layer:
// The console announces seven tools — five to find and call, mesh_runtimes to say which runtimes
// discovery heard, and mesh_wait to wait on the bus for an event (novox/hq ADR 0367). Everything the mesh answers is reached through them by one address per layer:
//
// <seat>.<verb> a seat held once for the mesh — its holder answers
// <node>/<seat>.<verb> a seat held once per machine — that machine's holder answers
@@ -17,6 +17,7 @@ package console
// session — so a tool that arrived a minute ago is found without the client reconnecting.
import (
"context"
"encoding/json"
"fmt"
"sort"
@@ -32,7 +33,7 @@ import (
// one agent turn's search, describe and call ask once, short enough that nothing goes stale.
var IndexKept = 5 * time.Second
// The six tools the console announces. Names of the API's kind — letters, digits, `_`, `-`.
// The seven tools the console announces. Names of the API's kind — letters, digits, `_`, `-`.
const (
verbOverview = "mesh_overview"
verbMachine = "mesh_machine"
@@ -40,6 +41,7 @@ const (
verbDescribe = "mesh_describe"
verbCall = "mesh_call"
verbRuntimes = "mesh_runtimes"
verbWait = "mesh_wait"
)
// searchCap is how many matches a search answers before it says how many more there were.
@@ -50,7 +52,7 @@ const grammar = "Addresses: `<seat>.<verb>` for a seat held once for the mesh (e
"`<node>/<module>.<tool>` for a module on one machine (e.g. `novox/postgres.postgres_list_databases`); " +
"and `<module>.<tool>` also for a module whose instances are interchangeable."
// discovery is the six tools as tools/list announces them.
// discovery is the seven tools as tools/list announces them.
func discovery() []map[string]any {
str := func(desc string) map[string]any { return map[string]any{"type": "string", "description": desc} }
obj := func(props map[string]any, required ...string) map[string]any {
@@ -84,12 +86,13 @@ func discovery() []map[string]any {
"arrive, its size in bytes, how many modules and tools it announced, whether it was shortened to fit the " +
"bus, and when it was last heard — and every runtime or machine expected that was not heard. Read-only; " +
"for when an address is said to be missing or on another machine."},
waitTool(),
}
}
func isDiscovery(name string) bool {
switch name {
case verbOverview, verbMachine, verbSearch, verbDescribe, verbCall, verbRuntimes:
case verbOverview, verbMachine, verbSearch, verbDescribe, verbCall, verbRuntimes, verbWait:
return true
}
return false
@@ -815,10 +818,13 @@ func failure(text string) map[string]any {
}
// discover answers one of the discovery verbs.
func (s *Surface) discover(name string, args map[string]any) map[string]any {
func (s *Surface) discover(ctx context.Context, name string, args map[string]any) map[string]any {
if name == verbRuntimes {
return s.runtimesAnswer()
}
if name == verbWait {
return s.waitAnswer(ctx, args)
}
x, err := s.index()
if err != nil {
return failure("the mesh's discovery failed: " + err.Error())