Files
buzz/crates
Sami 9281d7b313 fix(acp): publish the setup nudge over REST so a dropped one is not silent
The setup nudge is a durable kind:9 reply, but it was published through
the WS path, which is built for ephemera. While the rate-limit gate is
armed, or while disconnected, that path drops any non-observer publish
and returns Ok: the command is queued and the caller never learns what
happened to it. The nudge was therefore lost while being logged as
"nudge published" — the user asked how to set the agent up and got
nothing back.

Dedup made the loss permanent. should_nudge_for_event recorded the event
id by insert-on-check, before the publish was attempted, so the retry on
the next delivery of the same event was suppressed by an entry written
for a message that was never sent. One dropped nudge meant no nudge ever.

Both halves are fixed by subtraction rather than new machinery:

The nudge now goes through RestClient::submit_event, joining the four
other durable publishes on the HTTP bridge. The rest_client was already
in scope at the call site. submit_event surfaces the relay's actual
response, so a refusal is an Err.

The gate stops mutating: it takes &HashSet and only checks. The caller
inserts the id in the Ok arm of the publish, so a nudge that failed to
send stays retryable.

An earlier draft of this change instead widened the WS drop guard from
kind == KIND_AGENT_OBSERVER_FRAME to is_ephemeral(kind). That is wrong,
and the comment now says why: observer frames are themselves
range-ephemeral, so testing is_ephemeral would route them into the drop
path and undo the parking directly above it. The boundary is encoded as
a debug_assert instead. Enumerating the callers shows it holds: presence
(20001), typing (20002), observer frames (24200, parked before the
assert), and HarnessRelay::publish_event, which has no in-repo callers.

That assertion immediately caught publish_during_replay_pacing_is_sent_
on_live_socket publishing a kind:1 through the publish path. It was a
fixture artifact, not a defect — the test asserts on the event id and
never on the kind, so it reached for the generic make_test_event. The
fixture now builds a typing indicator, and both helpers' docs say which
path they belong to.

Mutation results. Reverting the dedup insert back into the gate is
killed by test_failed_nudge_remains_retryable; note the pre-existing
test_same_event_id_twice_nudges_exactly_once survives it, so the new
test is the discriminator rather than decoration. Reverting the
transport to publisher.publish_event initially survived the entire
suite: the dedup tests are pure and structurally cannot see which
transport is used. That is what the three transport tests are for --
they drive publish_setup_nudge against a real socket, and they kill that
mutant 3/3. Removing the debug_assert is caught by restoring the kind:1
fixture.

Co-authored-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>
Signed-off-by: Sami <f4a42a97e594b77bdbd8ee35191c8b28a94a4cb871d96f32921558275421fb68@buzz.block.builderlab.xyz>
2026-08-05 12:17:10 -04:00
..
2026-07-27 14:18:24 -04:00