---
name: assert-on-the-stream-the-emitter-actually-writes-to
description: "2026-09-08: my new precondition asserted the send reported SENT: and got an EMPTY STRING — SENT:/QUEUED: are emitted on STDERR via emit_line_err, and I read only stdout. The sister helper in the same crate had concatenated both streams all along."
metadata:
  node_type: memory
  type: feedback
---

Lane 4 (#272 relay window) added an assertion that `spt send` reported `SENT:` rather than
`QUEUED:` — the product's own words for live-vs-spooled, replacing a precondition that took
`Output::status.success()` and was therefore satisfied by a spooled send too. First run died with

    PRECONDITION: the live message went LIVE, not to the spool (…): ""

an EMPTY string. Not `QUEUED:`, not a wrong body — nothing. `spt`'s CLI reports through
`spt_proto::emit_line_err!`, i.e. **stderr**; I captured `out.stdout`. `quickstart_e2e::send()` in
the same crate concatenates stdout and stderr for exactly this reason and always had.

**Why:** an absent needle and a needle you are not looking at render identically — the same rule as
every filter/guard face, applied to STREAMS. Worse here, because the assertion was NEW: a green
would have proved nothing and the red pointed at my own reader while looking like a product claim.

**How to apply:** before asserting on a program's output, read the EMITTER to learn which stream it
writes to (`grep` the `emit_line_err!` / `eprintln!` / `println!` at the source of the token), and
prefer the idiom already used by a sibling helper in the same crate over inventing a reader.
Diagnostics and status lines in this codebase go to stderr far more often than stdout.
Sibling, and worth reading together: [[dont-infer-a-mechanism-from-wording-open-the-emitter]]
says a string tells you which BRANCH of the emitter ran; this one says check which PIPE it
travels on. Both are 'open the emitter', at different depths.
Related: [[never-send-a-claim-composed-before-its-check-ran]].
