# `Mutare.Phoenix.LiveView.Stream`
[🔗](https://github.com/foxbenjaminfox/mutare_phoenix_live_view/blob/v0.2.1/lib/mutare/phoenix/live_view/stream.ex#L1)

`:lv_stream` — mutates `Phoenix.LiveView` stream operations. Three kinds, each a variant
label:

**`swap`** inverts an operation for its opposite:

    stream_insert(socket, name, item)  <->  stream_delete(socket, name, item)

Replacing a deletion with an insertion (or vice versa) leaves the wrong rows in the
`phx-update="stream"` container. A test that asserts a stream's *contents* after the event
kills it; one that only checks the event returned lets it survive. Only the 3-argument form
is swapped — `stream_insert` also exists at arity 4 but `stream_delete` does not, so a
`stream_insert/4` gets the option mutations below instead, keeping every mutant compiling.

**`at`** swaps the `at:` option between its two boundary positions on `stream_insert/4`:

    stream_insert(socket, name, item, at: 0)   <->  stream_insert(socket, name, item, at: -1)

Prepend vs append (`-1`, the default, appends). Tests overwhelmingly assert an item is
*present*, rarely *where* — a survivor means nothing pins the insertion position. Only the
two boundary literals are swapped; core's `IntegerLiteral` still applies to other `at:`
values (a computed index, `at: 2`). The swap substitutes exactly the `at:` value node, so core's
`Mutare.Transform.Overlap` recognises it as covering and prunes `IntegerLiteral`'s redundant
leaf mutants (`0 → 1`, `0 → -1`) at that node — this family's position swap is the one
informative mutant there.

**`limit`** drops the `limit:` entry from `stream/4` and `stream_insert/4`:

    stream(socket, name, items, limit: 10)     ->  stream(socket, name, items)
    stream_insert(socket, name, item, at: 0, limit: 10)
                                               ->  stream_insert(socket, name, item, at: 0)

The unbounded stream is a valid-but-wrong program: without the limit the client container
grows without pruning. A survivor means no test fills past the limit and asserts the pruned
contents. Core mutators do not remove the *entry*; `IntegerLiteral` still mutates the limit's
numeric *value* to test off-by-one errors at the boundary.

No `reset:` mutation, deliberately: dropping `reset: true` is equivalent to core
`BooleanLiteral`'s `true → false` flip on the same literal (`false` is the default), so a
drop here would report the same mutant twice. The same holds for
`stream_insert/4`'s boolean `update_only:` option.

Suppress one kind with `# mutare:ignore[lv_stream:swap]` / `[lv_stream:at]` /
`[lv_stream:limit]`, or the whole family with `# mutare:ignore[lv_stream]`. A pipe form
(`socket |> stream_insert(:songs, song)`) is the call it is sugar for, so the socket counts
toward every arity gate.

Matches direct, aliased, and bare-imported (`use`-injected) calls. This family has a high
equivalent-mutant rate in apps that don't assert stream contents — drop it from your preset
if that is noisy.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
