BLOCKS shortcuts like modifying dialyzer.ignore or .credo.exs excludes. Enforces fixing actual problems. Use when encountering ANY error, warning, or quality tool complaint.
NEVER suppress errors. ALWAYS fix the root cause.
You are NEVER allowed to:
Add to dialyzer.ignore
Modify .credo.exs to disable checks
disabled: listexcluded_paths:# credo:disable-for-this-fileSuppress compiler warnings
@compile {:no_warn_undefined, Module}# noqa style comments--warnings-as-errorsModify .gitignore to hide problems
Comment out failing tests
Skip quality checks
--no-verifyWhen Dialyzer complains:
# BAD: Adding to dialyzer.ignore
# dialyzer.ignore
lib/my_app/accounts.ex:42:pattern_can_never_match
# GOOD: Fix with proper @spec
defmodule MyApp.Accounts do
@spec get_user(integer()) :: {:ok, User.t()} | {:error, :not_found}
def get_user(id) do
case Repo.get(User, id) do
nil -> {:error, :not_found}
user -> {:ok, user}
end
end
end
Common Dialyzer fixes:
Process:
mix dialyzer again to verifyWhen Credo complains:
# BAD: Adding to .credo.exs
{Credo.Check.Refactor.CyclomaticComplexity, max_complexity: 20}
# GOOD: Refactor to reduce complexity
# Before: Complex conditional logic
def process(data, opts) do
if opts[:validate] and opts[:transform] and not opts[:skip] do
# ... 50 lines of nested logic
end
end
# After: Extract functions
def process(data, opts) do
data
|> maybe_validate(opts)
|> maybe_transform(opts)
|> finalize()
end
defp maybe_validate(data, %{validate: true}), do: validate(data)
defp maybe_validate(data, _opts), do: data
Common Credo fixes:
Process:
mix credo --strict to verifyWhen compiler warns:
# BAD: Suppressing warning
@compile {:no_warn_undefined, SomeModule}
# GOOD: Fix the actual issue
# If function doesn't exist - implement it
# If module doesn't exist - add dependency
# If typo - fix the typo
When tests fail:
# BAD: Commenting out test
# test "user can login" do
# # This is broken, will fix later
# end
# GOOD: Fix the test or the code
test "user can login" do
user = fixture(:user)
assert {:ok, session} = Accounts.authenticate(user.email, "password")
assert session.user_id == user.id
end
Before making ANY file modification, ask:
.ignore file? → STOPexcluded: or disabled: list? → STOPIf ANY answer is YES → Use this skill to fix the real problem.
If you're about to say ANY of these phrases, STOP IMMEDIATELY and use this skill:
❌ "This is a minor warning" ❌ "This will be implemented later" ❌ "It's not related to MY changes" ❌ "These warnings are safe to ignore" ❌ "I'll add a TODO and come back to it" ❌ "This is a false positive" ❌ "The code works fine, the tool is being pedantic" ❌ "Adding to ignore is just for this one case" ❌ "This function is too complex to refactor right now" ❌ "Let's just disable this check for now"
Instead: Fix the actual problem. Now. While context is fresh.
When you encounter an error:
WRONG. The tool is almost always right. If you think it's wrong, you've misunderstood either:
WRONG. "Later" never comes. Fix it now while context is fresh.
WRONG. Dialyzer found a type inconsistency. Your code might work NOW, but it's brittle and will break when circumstances change.
WRONG. If it's too complex to refactor, it's too complex to maintain. Refactor it now or suffer forever.
WRONG. Once you start ignoring, you never stop. The ignore file grows and grows. Fix. The. Code.
WRONG. Flaky tests indicate real problems (race conditions, improper setup/teardown, environmental dependencies). Fix the flakiness.
WRONG. No warning is minor. Every warning is the compiler/tool trying to tell you something important. "Minor" warnings become major bugs in production.
WRONG. This is TODO hell. Either implement it NOW or don't write the code at all. Placeholder implementations with "TODO: implement later" never get implemented - they become permanent technical debt.
WRONG. You touched the code, you own it. The warning appeared on your watch - fix it. "Not my problem" attitude leads to rotting codebases. Leave the code better than you found it.
WRONG. There is no such thing as a "safe to ignore" warning. If a warning was truly safe to ignore, the tool wouldn't emit it. Every warning has a reason - understand it and fix the code.
If you suppress instead of fix:
The 5 minutes "saved" by adding to ignore costs 5 hours in debugging later.
Before modifying ANY of these files, you MUST use this skill:
dialyzer.ignore.credo.exs (specifically disabled: or excluded_paths: sections).gitignore (when hiding problems vs. proper ignore patterns)If you find yourself typing "add to ignore", STOP and fix the real issue.
# Error: Function MyApp.Repo.get/2 is undefined or private
# BAD: Add to dialyzer.ignore
# GOOD: Add proper typing
defmodule MyApp.Accounts do
alias MyApp.Repo
alias MyApp.Accounts.User
@spec get_user(integer()) :: User.t() | nil
def get_user(id) do
Repo.get(User, id)
end
end
# Warning: Cyclomatic complexity is 15 (max is 9)
# BAD: Raise max_complexity to 20
# GOOD: Refactor into pipeline
def process_order(order, user, opts) do
order
|> validate_order()
|> check_inventory()
|> apply_discounts(user)
|> calculate_shipping(opts)
|> finalize_order()
end
# Warning: Pattern can never match
# BAD: Add to dialyzer.ignore
# GOOD: Fix the pattern
# Before:
def handle_result({:ok, data}), do: process(data)
def handle_result(:ok), do: :ok # This can never match!
# After:
def handle_result({:ok, data}), do: process(data)
def handle_result({:error, reason}), do: {:error, reason}
If a quality tool complains, it's trying to help you write better code.
Listen to it. Fix the code. Don't silence the messenger.
"Every time you add to an ignore file, a production bug gets its wings."
"Technical debt isn't free - you pay interest every single day."
"Fix the code, not the tooling."
"Minor warnings become major bugs. 'Later' means never. 'Not my changes' means rotting codebase."
"You touched it, you own it. Leave the code better than you found it."