Topology refactor simulation: mutate the supervision structure, re-run the real analysis on the hypothetical, and diff the synchronous cross-tree crossings — so you can answer "does this move actually fix the coupling, or just relocate it?" before touching code.
The mutation is applied to the parsed modules and fed back through
Firebreak.analyze_modules/1, so the result uses the same forest/coupling/check
logic as a normal run — nothing is re-implemented or approximated. The diff is
computed over the model IR's synchronous crossings.
a = Firebreak.analyze("my_app")
Firebreak.WhatIf.move(a, MyApp.Cache, MyApp.Worker.Supervisor)
#=> %{resolved: [{MyApp.Worker, MyApp.Cache}], introduced: [], before: 1, after: 0}move/3 relocates a child to a new supervisor (the common fix for a
cross_tree_coupling finding — colocate the caller and target). set_strategy/3
changes a supervisor's restart strategy; it's expected to leave the crossing set
unchanged (strategy doesn't fix coupling), which is itself a useful thing to
confirm.
Summary
Functions
Simulate relocating child to be a child of new_parent; diff the crossings.
Simulate changing sup's restart strategy; diff the crossings.
Types
@type diff() :: %{ resolved: [{module(), module()}], introduced: [{module(), module()}], before: non_neg_integer(), after: non_neg_integer() }
Functions
@spec move(Firebreak.Analysis.t(), module(), module()) :: diff()
Simulate relocating child to be a child of new_parent; diff the crossings.
@spec set_strategy(Firebreak.Analysis.t(), module(), atom()) :: diff()
Simulate changing sup's restart strategy; diff the crossings.