From 55696fc098bd8ef1e5bca3421c9c873e6e21b4b4 Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Tue, 28 Jul 2026 10:29:59 +1000 Subject: [PATCH] docs(buzz-agent): pin the one mesh behaviour that is NOT parity I claimed the restored relay-mesh policy was identical to the old loop. Checked it properly: constants, catalog parsing, hysteresis and the gate all match, but contraction detection does not, and the difference is forced. The old loop read the raw HTTP body and accepted two shapes: a 503 whose error.message is the MoA-unavailable string, or any 5xx whose error.type is "moa_failure". A provider-level wrapper only sees what goose leaves behind, and extract_message (goose-providers/src/http_status.rs:186-197) reduces the payload to error.message when that field exists. So "moa_failure" *alongside* a message is invisible to us and fails the turn instead of retrying on auto. Verified by probe, not assumed. The message shape -- which is what mesh-llm's under-provisioned path actually sends -- still works, as does moa_failure with no message. Documented on is_mesh_contraction and pinned with a test that fails loudly if goose ever stops stripping the body, so the caveat cannot silently rot. Signed-off-by: Michael Neale --- crates/buzz-agent/src/mesh.rs | 46 +++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/crates/buzz-agent/src/mesh.rs b/crates/buzz-agent/src/mesh.rs index 56d276bdeb..dc045d5cc5 100644 --- a/crates/buzz-agent/src/mesh.rs +++ b/crates/buzz-agent/src/mesh.rs @@ -110,10 +110,29 @@ fn catalog_supports_collective(catalog: &Value) -> Option { /// Did this error mean "the mesh shrank", as opposed to a generic failure? /// -/// Two shapes, both from the old implementation (`llm.rs:1362-1388`): a 503 -/// whose `error.message` is exactly [`MOA_UNAVAILABLE_MESSAGE`], or any server -/// error whose `error.type` is `moa_failure`. Anything else is a real error and -/// must surface — silently retrying every 5xx as `auto` would mask outages. +/// The old loop inspected the raw HTTP body (`llm.rs:1362-1388`) and accepted +/// two shapes: a 503 whose `error.message` is exactly +/// [`MOA_UNAVAILABLE_MESSAGE`], or any 5xx whose `error.type` is +/// `moa_failure`. +/// +/// **We only see what goose leaves us.** `extract_message` +/// (`goose-providers/src/http_status.rs:186-197`) reduces the payload to +/// `error.message` when that field exists, and only falls back to the whole +/// JSON when it does not. So: +/// +/// * message shape — always detected (the message survives verbatim); +/// * `moa_failure` with no `message` — detected (whole JSON survives); +/// * `moa_failure` *alongside* a `message` — **not** detected, because the +/// type is discarded before it reaches us. Such a request fails the turn +/// instead of retrying on `auto`. +/// +/// That last case is the one behaviour the provider-level wrapper cannot +/// reproduce; recovering it needs an HTTP-level seam goose does not expose. +/// mesh-llm's under-provisioned path sends the message shape, which is why the +/// common case is covered. +/// +/// Anything else is a real error and must surface — silently retrying every +/// 5xx as `auto` would mask outages. fn is_mesh_contraction(err: &ProviderError) -> bool { let text = err.to_string(); if text.contains(MOA_UNAVAILABLE_MESSAGE) { @@ -458,12 +477,29 @@ mod tests { } #[test] - fn recognises_moa_failure_type() { + fn recognises_moa_failure_type_when_no_message_field() { + // Reachable only because goose falls back to the whole payload when + // `error.message` is absent (http_status.rs:196). let err = ProviderError::ServerError("500: {\"error\":{\"type\":\"moa_failure\"}}".to_string()); assert!(is_mesh_contraction(&err)); } + #[test] + fn moa_failure_alongside_a_message_is_a_known_blind_spot() { + // goose keeps only `error.message`, so `type` never reaches us. This + // pins the gap rather than pretending parity: if goose ever preserves + // the body, this test flips and we can delete the caveat in the docs. + let err = ProviderError::ServerError( + "Server error (500) at http://x: upstream exploded".to_string(), + ); + assert!( + !is_mesh_contraction(&err), + "if this now passes, goose stopped stripping the body -- update the \ + doc comment on is_mesh_contraction" + ); + } + #[test] fn ordinary_server_errors_are_not_contractions() { // Critical: treating every 5xx as a contraction would silently mask