debug

Systematic debugging workflow: reproduce, isolate, hypothesize, verify, fix. Triggers: "debug", "find bug", "fix crash", "why is this broken", "not working".

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "debug" with this command: npx skills add terryc21/xcode-workflow-skills/terryc21-xcode-workflow-skills-debug

Debug

Quick Ref: Systematic bug investigation: reproduce → isolate → hypothesize → verify → fix. Output: .agents/research/YYYY-MM-DD-debug-*.md

YOU MUST EXECUTE THIS WORKFLOW. Do not just describe it.

Required output: Every finding MUST include Urgency, Risk, ROI, and Blast Radius ratings using the Issue Rating Table format. Do not omit these ratings.


Pre-flight: Git Safety Check

git status --short

If uncommitted changes exist:

AskUserQuestion with questions:
[
  {
    "question": "You have uncommitted changes. Commit before proceeding?",
    "header": "Git",
    "options": [
      {"label": "Commit first (Recommended)", "description": "Save current work so you can revert if this skill modifies files"},
      {"label": "Continue without committing", "description": "Proceed — I accept the risk"}
    ],
    "multiSelect": false
  }
]

If "Commit first": Ask for a commit message, stage changed files, and commit. Then proceed.


Step 1: Gather Bug Report

Use AskUserQuestion if the user hasn't provided enough detail:

AskUserQuestion with questions:
[
  {
    "question": "What type of issue are you seeing?",
    "header": "Bug type",
    "options": [
      {"label": "Crash", "description": "App crashes, EXC_BAD_ACCESS, fatal error, etc."},
      {"label": "Wrong behavior", "description": "App runs but does the wrong thing"},
      {"label": "UI issue", "description": "Layout broken, animation wrong, view not updating"},
      {"label": "Performance", "description": "Slow, laggy, high memory, battery drain"}
    ],
    "multiSelect": false
  }
]

Collect these details (from user message or by asking):

  • Expected behavior — What should happen?
  • Actual behavior — What happens instead?
  • Steps to reproduce — How to trigger it
  • Error messages — Console output, crash logs, compiler errors
  • When it started — Recent change? Always broken?

Step 2: Reproduce

Goal: Confirm the bug exists and understand the trigger conditions.

2.1: Check Recent Changes

If the bug started recently, look at what changed:

# Recent commits touching Swift files
git log --oneline -10 -- '*.swift'

# Files changed in last N commits
git diff --name-only HEAD~5

# Full diff of recent changes
git diff HEAD~3 -- '*.swift'

2.2: Search for Error Messages

If the user provided an error message, find it in code:

# Search for the error string in source
Grep pattern="error message text" glob="**/*.swift"

# Search for fatalError / precondition calls
Grep pattern="fatalError|preconditionFailure|assertionFailure" glob="**/*.swift"

2.3: Document Reproduction

Record:

  • Reproducible? Always / intermittent / only under specific conditions
  • Minimum steps: Fewest actions to trigger the bug
  • Environment factors: Simulator vs device, debug vs release, iOS version

Step 3: Isolate

Goal: Narrow down to the smallest code path that causes the bug.

3.1: Trace the Code Path

Start from the user-facing symptom and trace inward:

# Find the entry point (e.g., button tap, view appear)
Grep pattern="<symptom_function_or_action>" glob="**/*.swift"

# Read the view/controller involved
Read file_path="<path_to_affected_file>"

# Trace function calls — use LSP when available for accurate resolution
LSP operation="goToDefinition" filePath="<file>" line=<N> character=<N>
LSP operation="findReferences" filePath="<file>" line=<N> character=<N>

# Fallback: Read each file along the call chain manually

3.2: Check the Blast Radius

Understand what the affected code touches:

# Find all callers of the broken function
Grep pattern="\.<brokenFunctionName>\(" glob="**/*.swift"

# Check protocol conformances if relevant
Grep pattern=":\s*<AffectedProtocol>" glob="**/*.swift"

3.3: Rule Out Environmental Factors

# Check for build configuration differences
Grep pattern="#if DEBUG|#if targetEnvironment" glob="**/*.swift"

Step 4: Gather Evidence

Goal: Collect concrete data about what the code is actually doing.

4.1: Read the Code

Read every file in the suspected code path. Don't guess — read.

# Read the primary file
Read file_path="<path_to_suspected_file>"

# Read related files along the call chain
Read file_path="<path_to_related_file>"

4.2: Check Git History

# When was the broken code last modified?
git log --oneline -5 -- "path/to/file.swift"

# What exactly changed?
git log -p -1 -- "path/to/file.swift"

# Find when a specific pattern was introduced or removed
git log -p -S "suspiciousCode" -- '*.swift'

4.3: Search for Related Patterns

# Find similar patterns that might also be affected
Grep pattern="<same_pattern_as_bug>" glob="**/*.swift"

# Find TODO/FIXME comments near the affected code
Grep pattern="TODO|FIXME|HACK|WORKAROUND" path="<affected_directory>"

Step 5: Hypothesize

Goal: Form ranked hypotheses based on evidence.

List possible causes ranked by likelihood:

#HypothesisLikelihoodEvidenceHow to Verify
1[Most likely cause]High[What evidence supports this][Specific check to confirm/deny]
2[Second possibility]Medium[Evidence][Check]
3[Third possibility]Low[Evidence][Check]

Common iOS Bug Patterns

State & Data:

  • Optional unwrapped when nil (check for as! and force unwraps)
  • Array index out of bounds (check for subscript access without bounds checking)
  • State mutation on wrong thread (check for @MainActor missing on UI updates)
  • Stale data after model change (check if view re-renders on data change)

Concurrency:

  • Data race (multiple tasks writing same property without synchronization)
  • Deadlock (two actors waiting on each other)
  • Missing await (forgetting to await an async call, getting old value)
  • Task cancelled but not checked (long operation ignoring Task.isCancelled)

Memory:

  • Retain cycle in closure (check for missing [weak self] in escaping closures in classes)
  • Delegate not declared weak (strong reference cycle)
  • Timer not invalidated (keeps firing after view dismissed)
  • Observation leak (NotificationCenter observer not removed)

UI:

  • View not updating (missing @Published, wrong property wrapper)
  • Layout constraint conflict (ambiguous Auto Layout)
  • Off-main-thread UI update (background queue modifying UI)
  • Animation state stuck (completion handler not called)

Step 6: Verify Hypotheses

Goal: Test each hypothesis starting with the most likely.

For each hypothesis, design a specific check that will definitively confirm or deny it:

# Example: Hypothesis is "nil optional crash"
# Test: Search for force unwraps in the affected file
Grep pattern="as!" path="<affected_file>"

# Example: Hypothesis is "missing weak self"
# Test: Find closures in the affected class (only relevant for classes, not structs)
Grep pattern="\.sink|\.receive|completion.*=" path="<affected_file>"

# Example: Hypothesis is "race condition"
# Test: Find shared mutable state
Grep pattern="var\s+\w+.*=" path="<affected_file>"

Record results for each hypothesis:

Hypothesis 1: [description]
  Test: [what I checked]
  Result: CONFIRMED / DENIED / INCONCLUSIVE
  Evidence: [what I found]

Continue until root cause is identified.


Step 7: Root Cause Analysis

Goal: Document the confirmed root cause clearly.

## Root Cause

**What:** [One-sentence description of the bug]
**Why:** [Underlying reason — why did this code get written this way?]
**Where:** [File:line where the bug lives]
**When introduced:** [Commit hash/date if identifiable]

Step 8: Fix

Goal: Implement the minimal correct fix.

8.1: Plan the Fix

Before editing, document:

FileChange RequiredRisk
File.swift:45[what to change]Low/Med/High

Blast radius: How many files are affected? Regression risk: Low / Medium / High Test coverage: Do existing tests cover this? New tests needed?

8.2: Implement the Fix

Use Edit tool to make targeted changes. Keep the fix minimal — don't refactor unrelated code.

8.3: Check for Similar Bugs

After fixing, search for the same pattern elsewhere:

# If the bug was a force cast, find other force casts
# INTENTIONAL: as! after guard let/is check is already validated
Grep pattern="as!" glob="**/*.swift"

# If the bug was a missing weak self, find other closures in classes
# INTENTIONAL: SwiftUI struct views don't need [weak self]
Grep pattern="\.sink\s*\{[^}]*self\." glob="**/*ViewModel*.swift"
Grep pattern="\.sink\s*\{[^}]*self\." glob="**/*Manager*.swift"

Or use /scan-similar-bugs for a more thorough scan.


Step 9: Verify Fix

Goal: Confirm the fix works and doesn't break anything.

  • Bug no longer reproduces with the original steps
  • Build succeeds without warnings
  • Existing tests pass
  • New test added to prevent regression
  • No new issues introduced in related functionality

Step 10: Generate Report

Display the investigation summary, root cause, and fix inline, then write report to .agents/research/YYYY-MM-DD-debug-{summary}.md:

# Bug Investigation Report

**Date:** YYYY-MM-DD
**Bug:** [one-line description]
**Urgency:** 🔴 Critical / 🟡 High / 🟢 Medium / ⚪ Low
**Status:** Fixed

## Symptoms

[What the user observed]

## Root Cause

**What:** [description]
**Where:** FileName.swift:line
**Why:** [underlying reason]
**Introduced:** [commit or date if known]

## Fix Applied

| File | Change | Lines |
|------|--------|-------|
| FileName.swift | [description] | 45-48 |

## Verification

- [x] Bug no longer reproduces
- [x] Build succeeds
- [x] Tests pass
- [ ] Regression test added

## Issue Rating Table

| # | Finding | Urgency | Risk: Fix | Risk: No Fix | ROI | Blast Radius | Fix Effort |
|---|---------|---------|-----------|-------------|-----|-------------|------------|
| 1 | [Primary bug] File.swift:45 — [description] | 🔴 Critical | ⚪ Low | 🔴 Critical | 🟠 Excellent | ⚪ 1 file | Trivial |

Use the Issue Rating scale:
- **Urgency:** 🔴 CRITICAL (crash/data loss) · 🟡 HIGH (incorrect behavior) · 🟢 MEDIUM (degraded UX) · ⚪ LOW (cosmetic/minor)
- **Risk: Fix:** Risk of the fix introducing regressions (⚪ Low for isolated changes, 🟡 High for shared code paths)
- **Risk: No Fix:** User-facing consequence if left unfixed
- **ROI:** 🟠 Excellent · 🟢 Good · 🟡 Marginal · 🔴 Poor
- **Blast Radius:** How many callers/files are exposed to this bug
- **Fix Effort:** Trivial / Small / Medium / Large

## Similar Patterns Found

[List any other instances of the same bug pattern, or "None found"]
Include each similar pattern as a row in the Issue Rating Table above.

## Prevention

[What could prevent this class of bug in the future]

Worked Example

User: "My app crashes when I tap an item in the list"

Step 1 — Gather: Crash on tap, EXC_BAD_ACCESS, started after last commit
Step 2 — Reproduce: git log shows ItemDetailView.swift changed yesterday
Step 3 — Isolate: Trace: List tap → NavigationLink → ItemDetailView.init → viewModel.loadItem()
Step 4 — Evidence: Read ItemDetailViewModel.swift, find `item.category!` on line 34
Step 5 — Hypothesize:
  #1: Force unwrap of nil optional (HIGH) — category is Optional, forced
  #2: Array index out of bounds (LOW) — no array access nearby
Step 6 — Verify: Check data — category is nil for items imported from CSV
Step 7 — Root cause: Force unwrap of item.category which is nil for CSV imports
Step 8 — Fix: Replace `item.category!` with `item.category ?? "Uncategorized"`
Step 9 — Verify: Build passes, tap works, added test for nil category
Step 10 — Report: Written to .agents/research/2026-02-24-debug-item-detail-crash.md

Troubleshooting

ProblemSolution
Can't reproduce the bugAsk for exact steps, device/simulator, iOS version, data state
Multiple hypotheses seem equally likelyTest the cheapest-to-verify one first
Fix breaks something elseRevert, widen the blast radius analysis, find the shared dependency
Bug is intermittentLikely a race condition — focus on concurrency patterns
No error message, just wrong behaviorAdd strategic print/breakpoint to narrow the code path
Bug only happens in release buildsCheck #if DEBUG blocks, compiler optimizations, stripped symbols

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

tech-talk-reportcard

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

implementation-plan

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

explain

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

enhanced-commands

No summary provided by upstream source.

Repository SourceNeeds Review