fix: reject empty stream messages at CLI, SDK, and relay ingest - #5394
Cynthia427 wants to merge 1 commit into
Conversation
An agent's channel post was published with empty content after its oversized turn output was rejected and a stdin retry delivered zero bytes — every gate accepted "" and the author believed the message was posted (silent content loss, discovered in production). Three layers, innermost out: - buzz-cli cmd_send_message: fail fast with a usage error naming the stdin-pipe case when content is empty/whitespace-only and no --files are attached - buzz-sdk build_message: SdkError::EmptyContent unless media tags are present, so every kind-9 producer inherits the guard - buzz-relay ingest: reject kind 9 with empty content and no imeta tags, covering non-CLI clients Deliberately unaffected: media-only messages (imeta, no text) stay legal, and message edits (kind 40003) are untouched — clearing an edit to empty is the deletion gesture (block#3813) and flows through a different kind. Signed-off-by: Cynthia Rohr <cynthia.r@kreativreason.co>
|
An empty variable or an empty stdin producer can publish a blank message successfully today. I prepared a complete fix that builds on the three-layer approach here and the CLI-first work in #7050. The contribution is one signed-off commit on upstream main The combined behavior is:
Validation does not trim or normalize content. Captionless attachments, Markdown/emoji, reply ancestry and edits that clear text remain supported. Stdin reads through EOF without a first-byte timeout. The payload contract also explains why partial nonempty stdout cannot prove that its producer succeeded, and gives a staged-report recipe. Local verification on that exact commit:
The new tests are wired into the unit and Relay E2E CI jobs. The same regression contract passes on our fork. These are local test results; no hosted CI, deployed behavior or upstream approval is claimed. A final relay rerun initially stopped at PostgreSQL connection setup because the disposable harness had been removed; it passed against a recreated harness without source changes. To rerun the focused contract after configuring disposable PostgreSQL, Redis and S3: cargo test -p buzz-cli -p buzz-sdk --test message_payload
cargo test -p buzz-relay --test message_payload -- --ignored --nocaptureI suggest consolidating this into the existing PR and coordinating #7050's overlapping CLI work. This supplies the broader enforcement, regression tests and protocol documentation together without opening another overlapping proposal. |
What
A production agent's channel post was published with empty content: its oversized turn output was rejected by the 64 KiB cap, the retry piped content via stdin, the pipe delivered zero bytes, and
""passed every gate — CLI validation, SDK builder, and relay ingest all accept empty content for kind 9. The author (an automated agent) believed the message was posted; the recipients saw a blank bubble. Silent content loss.Fix — three layers, innermost out
cmd_send_message: fail fast with a usage error that names the stdin-pipe case when content is empty/whitespace-only and no--filesare attached.build_message: newSdkError::EmptyContentunless media tags are present — every kind-9 producer inherits the guard.imetatags, covering non-CLI clients.Deliberately unaffected
mem set <slug> ''and other non-kind-9 empty-content uses — untouched (the guards are kind-9-scoped).Tests
Three new SDK unit tests (empty rejected, whitespace-only rejected, media-only allowed);
cargo test -p buzz-sdkgreen (187),buzz-cli+buzz-relaycompile clean.🤖 Generated with Claude Code