Call this when the user asks what they can SELL, remove, downsize, or trim — "what can I sell?", "which modules are redundant?", "what's doing double duty?", "I have too many modules, what can go?", "what's not pulling its weight?". The inverse of reachable_techniques: where that adds, this prunes.
Given the user's COMPLETE rack, it runs a leave-one-out over the same technique matcher reachable_techniques uses — for each module, does removing it cost any currently-reachable technique? Returns three buckets plus the overlap map:
- load_bearing: removing the module drops ≥1 reachable technique → KEEP. `sole_filler_for` names the techniques it props up.
- sell_candidates: removing it drops nothing AND another rack module covers the same function → the first place to look. `overlaps` names the shared function and `also_provided_by` the other providers.
- utility_or_uncovered: removing it drops nothing and nothing else does its job — it fills no catalogued technique role (usually a mixer / VCA / I/O / mult) OR serves an idiom the corpus is thin on. Judge by hand; this is NOT "sellable".
- overlap_map: every function ≥2 of the rack's modules provide (the "you have three reverbs" view) — the evidence behind sell_candidates.
IMPORTANT — this is decision-support, not a verdict, and the limits bite here:
- cardinality is NOT counted: a 2nd VCA / envelope / mult reads "redundant" though real patches use both at once. Overrule the tool on utilities.
- only the curated catalog is seen: a module serving an under-covered genre looks redundant when it isn't.
- two modules covering the same role are BOTH flagged — you can usually drop only one.
- it cannot weigh sonic character, ergonomics, or sentiment.
Trust it most for specialized overlap (e.g. several reverbs); present results as candidates to weigh, never "sell these". Pass the COMPLETE rack — the server is stateless and a partial rack distorts the analysis.
Args:
- rack (string[], required): module ids, e.g. ["make-noise/maths", "intellijel/quad-vca"]. Max 64. Unknown ids are returned in `unresolved` (with did-you-mean), not silently dropped.