All notable changes to this project are documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased

0.2.1 - 2026-10-03

Changed

  • Requires Mutare 0.5 ({:mutare, "~> 0.5.0"}) and mutare_phoenix 0.3.1.

0.2.0 - 2026-09-26

Changed

  • Breaking: requires Mutare 0.4.1 and mutare_phoenix 0.3 ({:mutare, "~> 0.4.1"}, {:mutare_phoenix, "~> 0.3"}). Mutare 0.4.0 offers a pipe stage to a mutator as the direct call it is sugar for, and removed the pipe-mode API these families were built on; every family now produces through mutate/1, reading the socket at argument 0 whichever way the call was written.
  • A removed pipe stage collapses to the socket piped into it. s |> push_event("a", %{}) and s |> attach_hook(:log, :handle_event, &h/3) are diffed against s; a stage removed in the middle of a chain takes everything upstream of it along (s |> push_event("a", %{}) |> assign(:x, 1) shows s |> push_event("a", %{}) → s). Through 0.1.0 such a stage read push_event("a", %{}) → Elixir.Function.identity(). The :lv_nav, :lv_stream and :lv_reply diffs are unchanged: a mutant that keeps the piped socket is still reported at the stage alone.
  • The :lv_send_update immediate replacement is parenthesized where it stands in for a do: value ((send_update(Cart, id: 1)\n:erlang.make_ref())), so the patched source is the program the mutant ran.

Added

  • :lv_send_update mutates a piped send_update/send_update_after (pid |> send_update(Cart, id: 1) → :ok). Such a call was left alone through 0.1.0, when its :ok/ref stand-in could not be delivered as a pipe stage; it is the same call as the direct spelling and now gets the same remove and immediate mutants, diffed over the whole pipe.

0.1.0 - 2026-09-07

Initial release.

Added

  • Mutare.Phoenix.LiveView.Navigation (:lv_nav) — swaps push_navigate ↔ push_patch at the arity-2 form both share.
  • Mutare.Phoenix.LiveView.Reply (:lv_reply) — drops a callback's optional trailing tuple element ({:reply, payload, socket} → {:noreply, socket}, {:ok, socket, opts} → {:ok, socket}), gated on the enclosing module's Phoenix.LiveView / Phoenix.LiveComponent behaviour.
  • Mutare.Phoenix.LiveView.Stream (:lv_stream) — swaps stream_insert ↔ stream_delete at the arity-3 form both share (swap); swaps at: 0 ↔ at: -1 on stream_insert/4 (at — prepend vs append; the covering rewrite supersedes core's integer leaves there via overlap pruning); drops the limit: entry of stream/4 / stream_insert/4 (limit). Dropping reset: true is omitted because it is equivalent to core's boolean flip.
  • Mutare.Phoenix.LiveView.Event (:lv_event) — removes push_event/3,4, collapsing to the socket (or Function.identity() when piped, through 0.1.0).
  • Mutare.Phoenix.LiveView.SendUpdate (:lv_send_update) — removes send_update/2,3 / send_update_after/3,4, collapsing to a faithful stand-in (:ok / a fresh make_ref() for _after's timer ref) (remove); and turns send_update_after/3,4 into an immediate send_update that still yields a ref (immediate — deletes the delay). The delay argument is a marked :timeout position, so core's literal families skip it.
  • Mutare.Phoenix.LiveView.Hook (:lv_hook) — removes attach_hook/4 (attach — the hook never runs) and detach_hook/3 (detach — the hook keeps running), collapsing to the socket. Hook name and stage atoms are routed :raw, so no core family mutates them.
  • Registers the LiveView compile-time DSL (live/live_session, on_mount, attr/slot/embed_templates) as :skip through Mutare.CallRouting, so declarations that run once as mutant 0 are left unmutated.
  • Mutare.Phoenix.LiveView.all/0 for splicing the six families into a :mutators list, composing with Mutare.Phoenix.all/0.