Files
buzz/crates/buzz-cli/src
Blake McAnally 745d2a86e0 fix(cli): treat a retried sidebar write the relay already stored as success (#9202)
Follow-up to #9191. It addresses the review findings that came in as
that PR merged.

## Summary

**A retried write was reported as a conflict.** This was found by the
Codex security review on #9191 (LOW).

- `BuzzClient::submit_event` can resend the same signed event after an
ambiguous attempt, for example a timeout after the relay stored it.
- The relay answers that resend `accepted: true, message: "duplicate:"`.
`publish` turned any `duplicate:` into exit 5 with "a newer update won;
run the command again".
- If you ran `buzz sidebar sections create` again, you got a second
section.

On a `duplicate:` reply, `publish` now re-reads the head from the writer
(`consistency: strong`). It reports success only when the head is the
event it signed. The check is safe because `replace_parameterized_event`
returns `was_inserted = false` for both an exact-id duplicate and a
stale (dominated) write. Only a stored event can be the head with our
id, so a dominated write still exits 5.

**Unknown keys are dropped on decode.** This was raised by joahg on
#9191. The module docs now state the limitation and why it is safe:
- Buzz Desktop (`block/buzz-app`, `validate_sidebar_payload`) refuses to
sign a document with unknown keys, so a new field needs a new `meta.v`.
- `decode` refuses an unknown `meta.v`. The commands then neither read
nor overwrite that head.

## Not changed

joahg also noted the lost-update window between the head read and the
submit. That window is documented in `crates/buzz-cli/README.md` (from
#9191). A kind:30078 replaceable event has no compare-and-set on the
relay, so the CLI cannot detect the case. A test would only check the
fake relay's replace rules.

## Testing

- `cargo test -p buzz-cli`: 665 pass. `cargo clippy -p buzz-cli
--all-targets -D warnings` and `cargo fmt --check` are clean.
- New test: `a_retry_of_a_stored_write_is_success`. The fake relay
stores the event and answers `duplicate:`. The test fails without the
fix (`Conflict("a newer sidebar sections update won; run the command
again")`).
- `a_dominated_write_is_a_conflict` now seeds a newer head under the
caller's own key. Before, every conflict test had an empty own head, so
a looser check (`Some(_)`) still passed. The test now fails under that
change.
- An agent review ran. It found that gap in the dominated-write test,
which is now fixed. Its remaining notes are optional.

### Manual test steps

The retry path needs a lost relay response, so you cannot easily trigger
it by hand. These steps check that normal writes did not change:

1. Run `cargo build -p buzz-cli`. Then set `BUZZ_RELAY_URL` and either
pair with Buzz Desktop (`buzz auth desktop pair`) or set
`BUZZ_PRIVATE_KEY`.
2. Run `buzz sidebar sections list` and save the output.
3. Run `buzz sidebar sections create --name "Retry test"`. Expected:
`"accepted": true`, a non-null `event_id`, and a `section_id`.
4. Run `buzz sidebar sections delete --section "Retry test"`. Then run
`list` again. Expected: the same output as step 2.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Signed-off-by: Blake McAnally <bmcanally@squareup.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 12:31:49 -08:00
..