BLOCKS shortcuts like modifying dialyzer.ignore or .credo.exs excludes. Enforces fixing actual problems. Use when encountering ANY error, warning, or quality tool complaint.
Scanned 2/12/2026
Install via CLI
openskills install majiayu000/claude-skill-registry---
name: elixir-no-shortcuts
description: BLOCKS shortcuts like modifying dialyzer.ignore or .credo.exs excludes. Enforces fixing actual problems. Use when encountering ANY error, warning, or quality tool complaint.
---
# Elixir No Shortcuts: Fix the Real Problem
## THE IRON LAW
**NEVER suppress errors. ALWAYS fix the root cause.**
## ABSOLUTE PROHIBITIONS
You are **NEVER** allowed to:
1. **Add to dialyzer.ignore**
- Not for "unknown function" errors
- Not for "pattern can never match" warnings
- Not for "no local return" issues
- Not even "temporarily"
2. **Modify .credo.exs to disable checks**
- Not adding to `disabled:` list
- Not adding to `excluded_paths:`
- Not using inline `# credo:disable-for-this-file`
- Not raising complexity limits
3. **Suppress compiler warnings**
- Not with `@compile {:no_warn_undefined, Module}`
- Not with `# noqa` style comments
- Not by removing `--warnings-as-errors`
4. **Modify .gitignore to hide problems**
- Not to hide accidentally created files
- Not to ignore build artifacts in wrong places
- Fix the process that created them
5. **Comment out failing tests**
- Not "just for now"
- Not "until we figure it out"
- Fix the test or fix the code
6. **Skip quality checks**
- Not removing from pre-commit hook
- Not skipping with `--no-verify`
- Not disabling in CI/CD
## INSTEAD: FIX THE ACTUAL PROBLEM
### Dialyzer Errors
**When Dialyzer complains:**
```elixir
# 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:**
1. **Unknown function** - Add @spec or import the module
2. **Pattern can never match** - Fix the actual pattern mismatch
3. **No local return** - Add error handling paths
4. **Invalid type specification** - Correct the @spec to match reality
**Process:**
1. Read the full Dialyzer error (don't just scan it)
2. Understand what Dialyzer is telling you
3. Add @spec that matches what the function actually does
4. If function behavior is wrong, fix the function
5. Run `mix dialyzer` again to verify
### Credo Warnings
**When Credo complains:**
```elixir
# 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:**
1. **High complexity** - Extract functions, use pipelines
2. **Long functions** - Break into smaller, focused functions
3. **Nesting too deep** - Use early returns, with statements, or guard clauses
4. **Modules too long** - Split into multiple focused modules
5. **Design anti-patterns** - Refactor following Elixir idioms
**Process:**
1. Read WHY Credo is warning
2. Understand the code smell it detected
3. Refactor to eliminate the smell
4. Run `mix credo --strict` to verify
### Compiler Warnings
**When compiler warns:**
```elixir
# 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
```
### Test Failures
**When tests fail:**
```elixir
# 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
```
## DETECTION CHECKLIST
**Before making ANY file modification, ask:**
1. **Am I about to modify a `.ignore` file?** → STOP
2. **Am I about to add to an `excluded:` or `disabled:` list?** → STOP
3. **Am I about to comment out code to make errors go away?** → STOP
4. **Am I about to skip a quality check?** → STOP
5. **Am I about to suppress a warning?** → STOP
**If ANY answer is YES → Use this skill to fix the real problem.**
## BANNED PHRASES
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.
## THE DEBUGGING PROCESS
When you encounter an error:
### Step 1: READ THE ERROR COMPLETELY
- Don't scan - read every word
- Note the file, line, and exact message
- Understand what tool is complaining and why
### Step 2: UNDERSTAND THE ROOT CAUSE
- Why is this happening?
- What is the code actually doing vs. what it should do?
- What does the tool want me to fix?
### Step 3: FIX THE CODE
- Add missing @spec annotations
- Refactor complex functions
- Fix pattern matching
- Add error handling
- Implement missing functions
### Step 4: VERIFY THE FIX
- Run the tool again
- See the error is GONE (not suppressed)
- All tests still pass
## RATIONALIZATIONS THAT ARE WRONG
### "This is a false positive from the tool"
**WRONG.** The tool is almost always right. If you think it's wrong, you've misunderstood either:
- What your code does
- What the tool is checking
- The Elixir/Erlang semantics
### "I'll fix this later, just need to move forward"
**WRONG.** "Later" never comes. Fix it now while context is fresh.
### "The code works fine, Dialyzer is just being pedantic"
**WRONG.** Dialyzer found a type inconsistency. Your code might work NOW, but it's brittle and will break when circumstances change.
### "This function is too complex to refactor right now"
**WRONG.** If it's too complex to refactor, it's too complex to maintain. Refactor it now or suffer forever.
### "Adding to ignore is just for this one case"
**WRONG.** Once you start ignoring, you never stop. The ignore file grows and grows. Fix. The. Code.
### "The test is flaky, I'll just comment it out"
**WRONG.** Flaky tests indicate real problems (race conditions, improper setup/teardown, environmental dependencies). Fix the flakiness.
### "This is minor warning"
**WRONG.** No warning is minor. Every warning is the compiler/tool trying to tell you something important. "Minor" warnings become major bugs in production.
### "This will be implemented later"
**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.
### "It's not related to MY changes"
**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.
### "These warnings are safe to ignore"
**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.
## CONSEQUENCES OF TAKING SHORTCUTS
**If you suppress instead of fix:**
1. **Technical debt accumulates** - Future you will hate past you
2. **Real bugs hide** - The error was trying to tell you something
3. **Code quality degrades** - Broken windows theory in action
4. **Team velocity slows** - Every shortcut makes next feature harder
5. **Production failures increase** - Suppressed warnings become runtime errors
**The 5 minutes "saved" by adding to ignore costs 5 hours in debugging later.**
## ENFORCEMENT
**Before modifying ANY of these files, you MUST use this skill:**
- `dialyzer.ignore`
- `.credo.exs` (specifically `disabled:` or `excluded_paths:` sections)
- Any file containing quality check configuration
- `.gitignore` (when hiding problems vs. proper ignore patterns)
- Test files (when commenting out failing tests)
**If you find yourself typing "add to ignore", STOP and fix the real issue.**
## EXAMPLES OF PROPER FIXES
### Example 1: Dialyzer Unknown Function
```elixir
# 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
```
### Example 2: Credo Complexity Warning
```elixir
# 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
```
### Example 3: Pattern Match Warning
```elixir
# 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}
```
## THE RULE
**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.**
## REMEMBER
> "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."
No comments yet. Be the first to comment!