From 0e26fd8ed585be8e3619758908555c14dd8c3c31 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 3 Nov 2026 01:13:36 +0100 Subject: [PATCH 1/2] The checker's calls to node-engines wait the compose-answer-bound, not the SDK's 30 s (issue 1126) Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL --- .../cmd/mesh-delivery-checker/main.go | 1 + .../cmd/mesh-delivery-checker/settings.go | 10 ++++++++++ .../mesh-delivery-checker/settings_test.go | 20 +++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go index 42e99b8..ef544bc 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/main.go @@ -174,6 +174,7 @@ func run(ctx context.Context, getenv func(string) string, logOut io.Writer) erro if err != nil { return err } + holdCallsFor(answerBound) verdicts := &manifestVerdicts{} compositions := check.EngineCompositions{ Asker: engineAsks{call: caller.CallOn}, diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings.go index c65f0f7..c3c44af 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings.go @@ -9,6 +9,7 @@ import ( "time" "git.novox.be/novox/mesh-sdk/go/delivery" + "git.novox.be/novox/mesh-sdk/go/process" ) // The checker's own settings (its config, written by the node-engine into ${dir:state}/settings.json, named to the @@ -42,3 +43,12 @@ func composeAnswerBound(path string) (time.Duration, error) { } return time.Duration(*s.Bound) * time.Second, nil } + +// holdCallsFor makes a bus call wait the compose-answer-bound (novox/hq ADR 0593 §7), not the SDK's CallTimeout of 30 s: +// the request of Conn.CallOn gives up at CallTimeout, so a node-engine answering at 30.4 s was lost before the bound +// applied (issue 1126). It only ever lengthens the SDK's bound, and it is set once, before the first call. +func holdCallsFor(bound time.Duration) { + if bound > process.CallTimeout { + process.CallTimeout = bound + } +} diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings_test.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings_test.go index 37155a3..ed6e148 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings_test.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings_test.go @@ -7,6 +7,7 @@ import ( "time" "git.novox.be/novox/mesh-sdk/go/delivery" + "git.novox.be/novox/mesh-sdk/go/process" ) // ADR 0593 §7: the answer bound is the checker's setting compose-answer-bound, 60 s when the file or the value is @@ -33,3 +34,22 @@ func TestTheAnswerBoundIsTheCheckersSetting(t *testing.T) { } } } + +// Issue 1126, ADR 0593 §7: the SDK's call gives up at CallTimeout (30 s), so an engine answering at 31 s is lost under a +// 60 s answer bound unless the checker's calls wait the bound; the bound never shortens the SDK's own. +func TestCallsWaitTheComposeAnswerBound(t *testing.T) { + was := process.CallTimeout + defer func() { process.CallTimeout = was }() + for _, row := range []struct{ bound, want time.Duration }{ + {delivery.ComposeAnswerBound, delivery.ComposeAnswerBound}, {10 * time.Second, was}, {600 * time.Second, 600 * time.Second}, + } { + process.CallTimeout = was + holdCallsFor(row.bound) + if process.CallTimeout != row.want { + t.Errorf("bound %v: calls wait %v, want %v", row.bound, process.CallTimeout, row.want) + } + if row.bound > 31*time.Second && process.CallTimeout < 31*time.Second { + t.Errorf("an answer at 31 s would be lost under bound %v", row.bound) + } + } +} From bedda86a22c5f9e76172019a7da3213afe6d4e86 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 3 Nov 2026 01:26:26 +0100 Subject: [PATCH 2/2] Fold the call-bound check into the answer-bound settings test (test budget) Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL --- .../mesh-delivery-checker/settings_test.go | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings_test.go b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings_test.go index ed6e148..ad9a986 100644 --- a/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings_test.go +++ b/modules/mesh-delivery-checker/cmd/mesh-delivery-checker/settings_test.go @@ -32,24 +32,15 @@ func TestTheAnswerBoundIsTheCheckersSetting(t *testing.T) { if (err != nil) != row.err || got != row.want { t.Errorf("%q: %s, %v", row.body, got, err) } - } -} - -// Issue 1126, ADR 0593 §7: the SDK's call gives up at CallTimeout (30 s), so an engine answering at 31 s is lost under a -// 60 s answer bound unless the checker's calls wait the bound; the bound never shortens the SDK's own. -func TestCallsWaitTheComposeAnswerBound(t *testing.T) { - was := process.CallTimeout - defer func() { process.CallTimeout = was }() - for _, row := range []struct{ bound, want time.Duration }{ - {delivery.ComposeAnswerBound, delivery.ComposeAnswerBound}, {10 * time.Second, was}, {600 * time.Second, 600 * time.Second}, - } { - process.CallTimeout = was - holdCallsFor(row.bound) - if process.CallTimeout != row.want { - t.Errorf("bound %v: calls wait %v, want %v", row.bound, process.CallTimeout, row.want) - } - if row.bound > 31*time.Second && process.CallTimeout < 31*time.Second { - t.Errorf("an answer at 31 s would be lost under bound %v", row.bound) + // Issue 1126: the SDK's call gives up at CallTimeout (30 s), so the checker's calls must wait the bound read + // (an answer at 31 s is heard under 60 s), and the bound never shortens the SDK's own. + if err == nil { + was := process.CallTimeout + holdCallsFor(got) + if process.CallTimeout < got || process.CallTimeout < was { + t.Errorf("%q: calls wait %v under bound %v", row.body, process.CallTimeout, got) + } + process.CallTimeout = was } } }