--- description: >- You MUST use this skill before writing any fix or editing any code to address a bug. Use when the code should do X but currently does Y — restoring correct behavior in existing code. Stronger signals: error messages, stack traces, "not working", "broken", "failing", "regression", "it used to work". Use sextant:debug instead when you have a symptom but cannot yet point to a specific file or line. Use sextant:modify-feature instead when the requirement itself is changing, not just broken behavior. --- !../principles/SKILL_BODY.md !../tool-gitnexus/SKILL_BODY.md --- # Bug Fix Workflow ## Disambiguating fix-bug vs modify-feature > **Use this skill when:** the code *should* do X but does Y — you want to restore correct behavior. > **Use modify-feature when:** the code does X correctly — you want it to do Z instead (desired behavior changed). > > Quick test: *"Did this ever work correctly, or was it always intended to work differently?"* > → **Yes, it used to work / should work** → fix-bug (continue here). > → **No, the requirement itself is changing** → **stop**. Tell the user: "This looks like a behavior change rather than a bug fix — the modify-feature workflow is a better fit. You can say something like 'refactor/change how X works' to trigger the right workflow, or tell me to proceed anyway and I'll apply baseline rules only." Do not proceed unless the user explicitly says to proceed. > > Edge case: A feature never implemented but expected is a bug only if it was promised in an interface contract; otherwise **stop** and direct the user to `sextant:add-feature`. ## Core Principle When fixing bugs, **make surgical modifications to the existing solution** — do not start over with a rewrite. --- ## Complete Execution Workflow > **Progress tracking:** At the start of each step, output an updated progress block so the user always knows where you are. Use this format: > > ``` > Bug Fix Progress > ✓ Step 1: Reproduce & Locate — > ✓ Step 2: Impact Assessment — Risk: > → Step 3: Minimal-Change Fix — in progress > ○ Step 4: Boundary Validation > ``` > > Replace `○` with `→` for the current step, and `✓` once complete. --- ### Step 1: Reproduce and Locate the Root Cause Before making any changes, confirm: - What is the **specific manifestation** of the bug? (Error message, abnormal behavior, data anomaly) - What are the **trigger conditions**? (Specific input, timing, environment) - Where is the **root cause**? (Don't fix the symptom — find the source) **Localization techniques:** - Starting from the error manifestation, trace the call chain **upward** to the earliest point of failure - Distinguish between "where the bug is exposed" and "where the bug originates" — they are often not the same place - Check whether **implicit state assumptions** have been violated (e.g., a variable expected to be non-null is actually null) - Pay attention to **boundary conditions**: null values, zero values, overflow, concurrency races, type mismatches 🔗 When GitNexus is available, use `context` / `trace` MCP tools for enhanced root-cause tracing. ### Step 2: Impact Assessment After locating the root cause, assess the potential impact of the fix: - Which **callers** does this function/method have? Will their behavior change after the fix? - Does the bug location involve a **public interface**? Will the fix change the interface contract? - Is there other code that **depends on the bug's behavior**? (Sometimes bugs have existed so long that other code has adapted to the erroneous behavior) 🔗 When GitNexus is available, use `impact` MCP tool to enumerate callers automatically. ``` ─── Bug Impact Assessment ─────────────────────────── Bug location: Root cause: Number of callers: Involves public interface: Yes / No Possible code depending on buggy behavior: Yes (explanation) / No Fix impact scope: Internal only / Affects callers / Cross-module Risk level: Low / Medium / High ───────────────────────────────────────────────────── ``` **When risk level is "High" (involves public interface or cross-module), you MUST inform the user of the impact scope and confirm before fixing.** --- ### Confirmation Gate (between Step 2 and Step 3) After completing the Impact Assessment, **before writing any code**, use the confirmation gate with: - **question**: A concise Proposed Fix Plan (see format below) - **options**: - `"Yes, apply the fix"` - `"No — let's discuss a different approach"` **Proposed Fix Plan format:** ``` Root cause : What changes : Callers affected : Risk : ``` **Decision rules by risk level:** | Risk | Behavior | |------|----------| | **High** | Always use the confirmation gate. Do not touch any file until user selects "Yes". | | **Medium** | Always use the confirmation gate. Do not touch any file until user selects "Yes". | | **Low** | Use the confirmation gate with an additional option `"Yes, and skip confirmations for low-risk fixes in this session"`. If the user selected that option earlier in the **current conversation**, proceed directly without using the confirmation gate for subsequent low-risk fixes — this preference is session-scoped only. | **If user selects "No":** ask *"What direction would you prefer?"*, incorporate their feedback, update the Proposed Fix Plan, and use the confirmation gate again before proceeding. --- ### Step 3: Minimal-Change Fix **Execution discipline:** - **Only change the part of code that causes the bug** — do not expand the scope of changes - **Maintain style consistency**: The fix code is fully consistent with surrounding code style (naming, indentation, comment language) - **Annotate changes**: Comments explaining the fix reason, format: `# fix: ` - **No hitchhiking**: Don't "optimize" unrelated code while fixing a bug — this introduces new regression risk **✅ Correct fix approach:** ```python def calculate_discount(price, rate): # fix: rate = 0 causes division by zero; added boundary check if rate <= 0: return price return price / rate ``` **❌ Incorrect fix approach:** ```python # Rewrote the entire function — introduces unnecessary change risk def calculate_discount(price, rate): if not isinstance(price, (int, float)): # Added type checking (not part of this bug) raise TypeError("...") validated_rate = max(rate, 0.01) # Changed boundary strategy (not the original behavior) return round(price / validated_rate, 2) # Added rounding (not part of this bug) ``` ### Step 4: Boundary Validation After completing the fix, check: ``` ─── Fix Verification Checklist ────────────────────── [ ] Is the original bug fixed? (Verify with original trigger conditions) [ ] Is the normal path still correct? (Regression validation) [ ] Are related boundary conditions handled correctly? (Null, zero, extreme values) [ ] Does the fix introduce new boundary issues? [ ] Does caller behavior still match expectations? [ ] Do related unit tests pass? If new tests are needed, use the sextant:write-tests skill with bug-fix context: root cause (Step 1) + impact scope (Step 2) already resolved. [ ] Is the style consistent with surrounding code? ───────────────────────────────────────────────────── ``` Report to the user: **Fix complete ✅** or **Additional issues found ⚠️ (with description)**. --- ## Forbidden Actions - Delete the old function and write a new "better" replacement (unless the user explicitly requests refactoring) - "Optimize" unrelated code while fixing a bug (introduces new variables, increases regression risk) - Use a temporary patch to work around the problem without fixing the root cause (e.g., adding `try/except` to swallow the exception) - "Mask" the bug with defensive code without understanding the root cause --- ## Exceptions (Require Explicit User Authorization) The following situations can break the "minimal change" principle, but **must be initiated by the user**: - User says "this approach has fundamental flaws, try a different approach" - User says "redesign this module/component" - User says "refactor this part of the code while you're at it" Even when the user authorizes expanding the scope, **fix the bug first, then refactor** — do it in separate steps, don't mix them together. --- ## Common Bug Pattern Quick Reference | Bug Pattern | Typical Manifestation | Investigation Direction | |-------------|----------------------|------------------------| | Null/None reference | `NoneType has no attribute` | Check if data source can be null/None | | Out-of-bounds access | `IndexError` / `KeyError` | Check collection length / key existence | | Concurrency race | Intermittent errors, data inconsistency | Check if shared state reads/writes are locked | | Type mismatch | `TypeError` / implicit conversion error | Check type consistency across layers | | State leak | Previous call's state affects the next | Check for unreset global/class-level variables | | Missing boundary | Abnormal behavior for specific inputs | Check null, zero, negative, very large values | | Async timing | Callback/Promise order doesn't match expectation | Check missing await, event order | | Configuration error | Only occurs in specific environments | Check env vars, config file differences | --- ## Sprint State Integration If `.sextant/state.json` exists in the project root and the current task matches a sprint task: - **On start:** offer to update the task's `status` from `pending` → `in_progress`. Ask: *"Update sprint state to mark Task N as in_progress?"* - **On completion** (acceptance condition met): offer to update `status` to `done`. Ask: *"Update sprint state to mark Task N as done?"* - **On blocker** (test failure, missing dependency, unresolvable ambiguity that halts progress): surface the issue, then ask: *"Mark Task N as blocked and record the reason in flags?"* If confirmed, set `status: "blocked"` and append `{"task": N, "reason": ""}` to the top-level `flags` array. Do not proceed to the next task while a task is blocked. Do not write the file without explicit user confirmation. If the user declines, continue without state updates. --- ## Reply Format **Lightweight task** (single function, < 50 lines changed): one sentence only. ``` ✅ Fixed ``: (:). ``` or if something needs attention: ``` ⚠️ Fixed ``: . Note: . ``` **Medium/large task** (cross-file, public interface, or high-risk): full block. Fix Summary: | # | Item | Detail | |---|------|--------| | [1] | Conclusion | | | [2] | Changes | | | [3] | Risks / Assumptions | | | [4] | Verification | | | [5] | Needs your input | |