Skip to content

fix(buzz-acp): clamp idle_timeout to max_turn_duration instead of hard-erroring - #4261

Open
rsnodgrass wants to merge 1 commit into
block:mainfrom
rsnodgrass:fix/clamp-idle-timeout-to-max-turn
Open

fix(buzz-acp): clamp idle_timeout to max_turn_duration instead of hard-erroring#4261
rsnodgrass wants to merge 1 commit into
block:mainfrom
rsnodgrass:fix/clamp-idle-timeout-to-max-turn

Conversation

@rsnodgrass

@rsnodgrass rsnodgrass commented Aug 2, 2026

Copy link
Copy Markdown

Problem

Config::from_args rejects any config where idle_timeout >= max_turn_duration with a hard ConfigError:

config error: idle_timeout (900s) must be less than max_turn_duration (300s)

A ConfigError takes the agent process offline. Under a restart-on-failure supervisor (Docker restart: always, systemd, k8s), that becomes a crash-loop — and it can be triggered with no config change the moment a rolling image (pull_policy: always) tightens this invariant while an existing, previously-valid config sets a low max_turn_duration and leaves idle_timeout at its 900s default.

That's exactly what bit a fleet of agents: max_turn_duration=300 (a deliberate safety cap) had been valid for days; a routine image pull added the idle < max check; every agent then rejected its config and crash-looped (exit 1), silently — until someone read a container log.

Fix

idle_timeout only matters if it fires before the absolute wall-clock cap. When idle_timeout >= max_turn_duration the cap fires first and idle_timeout is a dead letter — harmless. So instead of failing the whole config, clamp idle_timeout down to the lesser of the requested value and max_turn_duration, and warn:

let idle_timeout_secs = if idle_timeout_secs >= max_turn_duration_secs {
    tracing::warn!(
        idle_timeout_secs,
        max_turn_duration_secs,
        "idle_timeout >= max_turn_duration; clamping idle_timeout down to max_turn_duration"
    );
    max_turn_duration_secs
} else {
    idle_timeout_secs
};

A dead-letter idle_timeout is harmless; a hard config error takes the agent down. Config validation should degrade gracefully in this case rather than turning a benign, previously-valid setting into an outage.

Test

The existing idle_timeout_must_be_less_than_max_turn_duration test (which only asserted a precondition) is replaced with idle_timeout_clamped_to_max_turn_duration, exercising the real Config::from_args path: idle=900 + max=300idle_timeout_secs == 300, no error.

$ cargo test -p buzz-acp idle_timeout
test config::tests::idle_timeout_clamped_to_max_turn_duration ... ok

Co-Authored-By: SageOx ox@sageox.ai

…d-erroring

A config with idle_timeout >= max_turn_duration was rejected outright (ConfigError),
taking the agent process offline. Under a restart-on-failure supervisor (Docker
restart: always, systemd, k8s) that becomes a crash-loop the instant a rolling image
tightens the invariant while an existing, previously-valid config sets a low
max_turn_duration and leaves idle_timeout at its 900s default — which is exactly what
happened to a fleet of agents on a pull_policy: always image.

idle_timeout only matters if it fires before the absolute wall-clock cap; when it is
>= max_turn_duration the cap fires first and idle_timeout is a dead letter (harmless).
So clamp idle_timeout down to the lesser of the requested value and max_turn_duration
and warn, rather than failing the whole config. Config-handling should degrade
gracefully here, not take the agent down.

Test updated to assert clamping (idle 900 + max 300 -> idle 300, no error).

Co-Authored-By: SageOx <ox@sageox.ai>
Signed-off-by: Ryan Snodgrass <rsnodgrass@gmail.com>
@rsnodgrass
rsnodgrass force-pushed the fix/clamp-idle-timeout-to-max-turn branch from ba0f5f9 to a06acb1 Compare August 2, 2026 05:40
@rsnodgrass

Copy link
Copy Markdown
Author

@dcoapp recheck

@rsnodgrass
rsnodgrass marked this pull request as ready for review August 2, 2026 05:41
@rsnodgrass
rsnodgrass requested a review from a team as a code owner August 2, 2026 05:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant