Skip to content

fix(buzz-agent): make reply guard result-based - #8084

Draft
knehighprinter wants to merge 1 commit into
block:mainfrom
knehighprinter:ted/layer1-reply-guard
Draft

knehighprinter wants to merge 1 commit into
block:mainfrom
knehighprinter:ted/layer1-reply-guard

Conversation

@knehighprinter

Copy link
Copy Markdown

What

Make the buzz-agent reply guard result-based instead of attempt-based.

Today run() sets buzz_reply_call_seen from the shape of a tool call before
it executes (agent.rs, is_buzz_reply_call), so a send that fails, is
rejected, returns an empty body, or is never acknowledged still satisfies the
guard and can end a turn silently. The source already documents this as
deliberate ("recognizes an attempt, not a successful publish").

This change decides confirmation from the executed result:

enum ReplyOutcome { NoAttempt, AttemptFailed, AttemptUncertain, Confirmed }
struct ReplyState { attempted, send_attempted, reacted, outcome }

append_results records reply.observe(call, &result, mcp) for each executed
call. The guard then selects its reminder by outcome:

Outcome Reminder
Confirmed none
NoAttempt original reminder
AttemptFailed corrective — fix and publish once
AttemptUncertain no blind resend; record the uncertainty

Classifier evidence priority:

  1. explicit relay ack accepted:true + valid 64-hex event_id
  2. explicit accepted:false
  3. verified pre-submission/local failure
  4. timeout / connection loss / missing ack / ambiguous state
  5. generic exit status — diagnostic only, never proof of failure

A non-zero shell exit alone is not treated as failure (the submission may
have reached the relay). Dynamic --content ($VAR, backticks, globs, stdin)
is never treated as proving a non-empty published body; reactions count as an
attempt but never as a final textual reply. MAX_REPLY_NAGS and the shared
stop_max_rejections budget are unchanged.

Tests

  • Unit: classifier (ack wins over exit, non-zero exit ≠ failed, rejection,
    pre-submission, timeout, missing ack, empty static content, dynamic content,
    stdin), content extraction, event-id shape, publish-kind split, merge
    priority, reaction-only, and nag selection per outcome.
  • Integration (tests/regressions.rs, reply-guard suite): confirmed ⇒ no nag;
    accepted:false ⇒ corrective nag (not the no-resend nag); timeout/no-ack ⇒
    no-resend nag (not corrective); no attempt ⇒ original nag.
  • Test-only FAKE_MCP_RESULT_TEXT / FAKE_MCP_RESULT_IS_ERROR in
    tests/bin/fake_mcp.rs; the existing
    reply_guard_satisfied_by_registered_shell_send now returns a real ack.

cargo test -p buzz-agent → 0 failures across the package (568 lib incl. 22 new
unit cases; 57 regressions incl. 13 reply-guard). cargo clippy -p buzz-agent --all-targets -- -D warnings clean; cargo fmt applied.

Scope

crates/buzz-agent only. No Fizz/agent configuration, no threading changes, no
fallback publication, no retries, no nonce/idempotency.

Confirm a Buzz reply from the executed `messages send` result instead of
the call shape, so a failed, empty, or unacknowledged send cannot end a
turn silently. `ReplyState`/`ReplyOutcome` track no-attempt / failed /
uncertain / confirmed separately and select the matching reminder
(corrective repost vs do-not-duplicate). Reactions count as an attempt
but never a confirmation. A non-zero shell exit alone no longer implies
failure, and dynamic `--content` is never treated as proving a non-empty
published body.

Tests: unit cases for the classifier, content state, event-id shape and
nag selection; integration cases for confirmed / failed / uncertain /
no-attempt in the reply-guard suite.

Signed-off-by: Ted <6d09db46fe019f2c52219114b5db6b85519f7a1b6f1d2d869e029e6cbb20b252@gurusurfer.communities.buzz.xyz>
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is 5f2d801b8f1d7be0c06839bded3f0391cbb46f92...6a89df6a491a23a96ac4640a149f8e13fbde9027.
A new review must complete for this exact range. When manual authorization
is required, a user with write access must comment exactly
@buzz-security-review 6a89df6a491a23a96ac4640a149f8e13fbde9027 to authorize a new review.
Any previous review applies only to its recorded range.

This branch has not been deployed

No deployments
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