Files

22 KiB
Raw Permalink Blame History

Extracted from implement/SKILL.md (Mode: bugfix) — moved verbatim 2026-08-25, ticket [org-internal #3381].

Mode: bugfix

Reproduce, isolate, and fix a bug with a regression test to prevent recurrence. For small, localized bugs, use standalone mode — the existing system behavior is the specification. For large, complex bugs, route through the full quality pipeline.

Process Overview

Every diamond below is a gate Developers rationalize skipping — especially under "the bug is obvious" pressure.

digraph bugfix {
    rankdir=TB;
    node [shape=box, fontname="Helvetica"];

    repro   [shape=diamond, label="Bug reproduces?"];
    norepro [label="STOP: report cannot-reproduce\n(do not guess-patch)"];
    rc      [shape=diamond, label="Root cause found\n(not just symptom)?"];
    symptom [label="Go deeper — do NOT\npatch the symptom"];
    route   [shape=diamond, label="Routing:\nstandalone vs pipeline?"];
    escalate [label="Uncertain → escalate\nto pipeline mode"];
    rtest   [shape=diamond, label="Regression test\nFAILS before fix?"];
    notest  [label="Test does not cover\nthe bug — rewrite it"];
    fix     [label="Phase 4: Fix\n(one change, root cause only)"];
    green   [shape=diamond, label="Regression test PASS\n+ full suite green?"];
    done    [shape=doublecircle, label="Phase 5/6:\nSelf-Check + Report"];

    repro  -> norepro   [label="no"];
    repro  -> rc        [label="yes"];
    rc     -> symptom   [label="no"];
    rc     -> route     [label="yes"];
    route  -> escalate  [label="uncertain"];
    route  -> rtest     [label="standalone"];
    rtest  -> notest    [label="passes already"];
    rtest  -> fix       [label="fails (confirmed)"];
    fix    -> green;
    green  -> fix       [label="no: fix + re-run"];
    green  -> done      [label="yes"];
}

Execution Modes

Mode Entry Point Scope Source Review Gate Verify Gate
Standalone User says "fix this bug" Bug report + code Optional (>20 lines or ≥3 files) None
Pipeline User requests full-process bugfix, or auto-escalation Bug report → requirements → design → plan → implement Mandatory Mandatory

Routing override (ticket-seeded): the Optional/None gate declarations above apply to user-initiated standalone mode. When the ticket carries a Kind/* route whose keep_gates includes review-code / verify (e.g. Kind/Bug, Kind/Testing — see <instance-root>/workflow-routing.yaml), those gates are MANDATORY regardless of size. Per core/rules/workflow-routing.md, a gate is mandatory if EITHER the route OR the skill requires it; skipping is valid only when BOTH agree it is skippable.

In pipeline mode, the bug report becomes a bugfix work item that flows through the full requirements → design → plan → implement → review-code → verify pipeline.

Role & Responsibilities

The bugfix is owned and executed by the Developer (Worker). The Developer owns both implementation and bugfix — same role, same skill set.

The Developer is responsible for:

  • Reproducing the bug from the description.
  • Identifying the root cause (not just patching the symptom).
  • Writing a regression test that fails before the fix and passes after.
  • Applying the minimal surgical fix — one change, one purpose.
  • Running the full test suite to confirm no regressions.

The Builder's role is to present the bugfix report and route it to code review if the change is non-trivial (> 20 lines or touches ≥ 3 files).

Tester focus for bugfix

The Tester role in bugfix writes regression tests and, uniquely, intervenes BEFORE the fix (a regression test must fail before the fix to prove the bug exists):

  • Failing regression test — read repro-notes.md (the Developer's reproduction + root-cause analysis from Phases 12), write a test that exercises the exact bug path and FAILS with the bug's symptom. This MUST happen before Phase 4 (Fix), not after — it is Phase 3.
  • Passing confirmation — after the Developer's fix, the same test MUST pass (the Developer's green run in Phase 4 verifies this).
  • Boundary regression tests — inputs adjacent to the bug trigger, similar conditions that must NOT trigger the fix (guards against over-fixing), and error paths near the root cause.

Bugfix-specific orchestration (overrides the standard role-split flow):

Because a regression test must fail BEFORE the fix, the bugfix role split inverts the standard orchestration — the Tester dispatches between Phase 2 and Phase 4, not after the fix:

[Worker: developer] Phase 1 reproduce + Phase 2 root cause
    → write repro-notes (reproduction steps, root cause, bug path,
      expected behavior)
    ↓ persist: wiki page `{slug}/repro-notes` (`POST .../wiki/new`, body `content_base64`)
[Worker: tester] read repro-notes → Phase 3 write failing regression test
    (confirms FAIL before fix)
    ↓ persist: wiki page `{slug}/test-report` (`POST .../wiki/new`, body `content_base64`, failing test confirmed)
[Worker: developer] Phase 4 fix → run test:changed to green
    → write impl-notes (post-fix behavior contract)
    ↓ persist: wiki page `{slug}/impl-notes` (`POST .../wiki/new`, body `content_base64`, post-fix behavior contract)
[Worker: tester] supplement boundary regression tests → run test:changed
    ↓ persist: update wiki page `{slug}/test-report` (`PATCH .../wiki/page/{mangled-name}`, omit `title`, body `content_base64` — final)
    — consumed by the human stakeholder / next iteration planning for DoD regression-test evidence

For small, single-file bugfixes with an obvious fix, a single Developer Worker may write the failing test, fix, and confirm green in one invocation — the split is optional for trivial fixes (Phase 3 + Phase 4 in one session). Force the split when the fix touches ≥ 2 files or the root cause spans ≥ 2 levels of indirection.

Pipeline-mode bugfixes route through the implement pipeline (see ### Mode: implement (default)), with the bugfix-specific Tester focus above layered on top of the standard role-split orchestration.


Preconditions (standalone)

Before starting the bugfix, confirm:

  • Bug description exists (user's message, issue tracker link, or error log).
  • Existing codebase is accessible.
  • core/checklists/bugfix.md is accessible.

If the user describes a symptom without specifics, ask for:

To fix this bug, I need:
1. What is the expected behavior? (what should happen)
2. What is the actual behavior? (what happens instead)
3. Steps to reproduce.
4. Any error messages, logs, or stack traces.

Routing Decision

After Phase 1 (reproduce) and Phase 2 (root cause), the Developer evaluates whether the fix qualifies for standalone or pipeline mode:

Escalate to pipeline mode when ANY of:

Condition Reason
Fix touches ≥ 5 files Cross-file changes need design review and integration tests
Fix spans ≥ 2 modules / components Multi-module fixes need architectural validation
Root cause is in a design-level decision (protocol, schema, architecture) Design change needs requirements + design review
Fix requires data migration or schema change Schema changes need data design review and migration plan
Fix changes a public API or interface contract API changes need interface design review and compatibility check
Fix introduces a new dependency or changes an existing one Dependency changes need review (DGN dimension, code review)
Estimated lines changed > 50 Large change carries high regression risk
User explicitly requests full-process bugfix User wants quality gates

Stay in standalone mode when ALL of:

Condition
Fix is ≤ 4 files
Fix is ≤ 1 module / component
Fix is a logic error, not a design error
No data migration or schema change
No API or interface contract change
No dependency change
Estimated lines changed ≤ 50

If the Developer is uncertain, escalate. A false pipeline escalation costs a few extra review rounds. A false standalone decision risks missing a quality gate on a complex change.

Big-bug relabel rule ([org-internal #3061]) — before the generic escalation below, split the triggers by kind:

  • Design-level triggers (root cause is a design decision — protocol / schema / architecture; shared-contract or public-API change; data migration): do NOT push through bugfix and do NOT run the legacy pipeline escalation — relabel the ticket Kind/Feature and reroute via Step 0 (DAG route; a 13 node small DAG is the expected shape for a single design-level fix). The fix work already done (repro notes, root cause) becomes node input, not wasted work.
  • Mechanical size triggers only (many files / many lines, same design): stay in bugfix — batch the change into iterations and keep the review-code + verify gates. Scale alone never justifies a relabel.

When escalating, the Developer pauses after Phase 2, reports the routing decision, and asks the user to confirm pipeline escalation:

This bugfix qualifies for pipeline mode:
- {N} files across {M} modules
- Root cause: {design-level issue}
- Estimated lines: {N}

→ Route through requirements → design → plan → implement → review → verify?
  (yes / no — proceed with standalone)

Phase 1 — Understand & Reproduce

  1. Read relevant code — find the module/component likely responsible for the bug. Use grep for error messages, glob for related files.

  2. Check existing tests — do existing tests cover this code path? If a test exists but passes, the bug is in the test or in an uncovered branch.

  3. Reproduce — run the relevant test(s) or manually trigger the bug. Confirm the actual behavior matches the bug report. Document the reproduction:

    ## Reproduction
    
    **Steps**:
    
    1. {step}
    2. {step}
       **Expected**: {what should happen}
       **Actual**: {what happens}
    
  4. If the bug CANNOT be reproduced, stop and report:

    Cannot reproduce the bug. Here's what I tried:
    - {step 1}
    - {step 2}
    
    → Is the environment different? Are there missing steps? Does a specific
      data state trigger it?
    

Phase 2 — Isolate Root Cause

Trace from the symptom to the root cause:

  1. Symptom: surface-level error (e.g. "500 on login").
  2. Proximate cause: the code that throws or returns wrong (e.g. "password hash comparison returns false for valid password").
  3. Root cause: the underlying defect (e.g. "password hashing config changed in commit abc123 but the stored hashes were not re-hashed").
## Root Cause Analysis

**Symptom**: {error message or wrong behavior}
**Proximate cause**: {file}:{line} — {what the code does wrong}
**Root cause**: {underlying defect — config, data, logic, or assumption}

**Introduced in**: {commit hash or version if known}

Rules:

  • If you're fixing a symptom (e.g. adding a null check where the real bug is that null should never reach that line), stop and go deeper.
  • If you can't find the root cause after examining 3 levels of indirection, pause and report findings. Do NOT apply a surface-level patch.
  • After Phase 2, evaluate the routing decision (see Routing Decision table above). If the fix qualifies for pipeline mode, pause and present the escalation prompt before proceeding to Phase 3.

Phase 3 — Write a Regression Test

Before fixing, write a test that proves the bug exists:

  1. Write a test that exercises the bug path with the failing inputs.
  2. Run the test — it MUST fail with the bug's symptom.
  3. The test must be specific: test the exact condition that was broken, not a general "endpoint returns 200" test.
## Regression Test

- **File**: {path to test file}
- **Test name**: {test function name}
- **What it verifies**: {the expected behavior that was broken}
- **Fails before fix**: ✅ (confirmed)

Rules:

  • If you cannot write a test that fails (bug is non-deterministic, environment- specific), write the most targeted test you can and mark it [flaky].
  • The test must fail NOW, before you apply the fix. If it passes already, the test does not cover the bug.

Phase 4 — Fix

Apply the minimum change that resolves the root cause:

  1. One conceptual change per fix — do not bundle a bugfix with refactoring, style changes, or "while I'm here" improvements.
  2. Fix the root cause, not the symptom. If the root cause is in a different file than the symptom, fix it there.
  3. Update only what's necessary — if fixing a null-safety bug requires adding a null check in one place, add one null check, not a comprehensive null-safety overhaul of the entire module.
  4. Run the regression test — it MUST pass.
  5. Run the relevant unit tests — all existing tests must still pass.

Phase 5 — Self-Check & Report

Self-Check
  1. Typecheck: bun typecheck — zero errors.
  2. Lint: bun oxlint --deny-warnings — zero errors.
  3. Full test suite: bun run test:parallel — all tests pass (new + existing).
  4. Checklist: verify every item in core/checklists/bugfix.md.
  5. Publish bugfix report: write the bugfix report as a wiki page via wiki 读写 API(见 TERMINOLOGY with page_name {slug}/bugfix-report (_shared/gitea-write-patterns.md Pattern 1).
Report
## Bugfix Report

**Bug**: {one-line description}
**Root cause**: {file}:{line} — {explanation}
**Fix**: {file} — {single-sentence description of change}
**Lines changed**: {N}
**Regression test**: {test file}:{test name}

### Verification

- Regression test: {PASS | FAIL}
- Full test suite: {N} passed, 0 failed
- Typecheck: ✅
- Lint: ✅

### Files Changed

| File                | Lines  | Purpose                                                |
| ------------------- | ------ | ------------------------------------------------------ |
| `src/auth/login.ts` | +3, -1 | Fix password hash comparison when salt version changes |

---

**Handoff**: {if changes > 20 lines or ≥ 3 files → run `core/skills/review-code/SKILL.md`
| otherwise → fix complete, no review needed}

> **Routing override**: when the ticket carries a `Kind/*` route whose
> `keep_gates` includes `review-code` / `verify` (e.g. `Kind/Bug`,
> `Kind/Testing`), those gates are MANDATORY even for small fixes — the
> "no review needed" branch above does not apply (see the Execution Modes
> routing-override note above).

Phase 5.5 — Issue Checklist Sync (standalone bugfix)

In standalone-bugfix mode there are no skill-exit boundaries between commit, PR, review, and CI — without explicit sync points the issue goes stale. Per the issue-checklist-sync L1 rule, sync at each externally visible transition (skip any step if no source issue exists):

When Sync action
After the fix commit Check off fix-delivered ACs with _(commit {sha}: file)_
After PR creation Ensure the ## 当前状态 section exists (the PR row is auto-written by the status-sync poller — see issue-checklist-sync.md § Automated sync)
After review convergence Review-related ACs get _(reviewed: round N PASS)_ (done by review-code Phase E 2.7)
On CI state transitions Update process-AC progress (e.g. "N consecutive green") with run number
At verify PASS / close Final sweep per verify Phase 5.6

Bugfix mode delegates the "after commit" step to the same mechanics as Phase 4.6 above (fetch issue body → map - [ ] items → 工单 API(见 TERMINOLOGYupdate), and the PR-creation step to Phase 4.7.


Phase 6 — Approval

Present the report:

Bug fixed: {one-line description}
- Root cause: {file}:{line}
- {N} lines changed in {M} files
- Regression test added: {test name}
- Full test suite: ✅

→ {if review needed: "Run code review?" | else: "Fix complete. Approve?"}

Common Rationalizations (bugfix)

Bugfixes fail from pressure and false confidence far more than from ignorance — "the bug is obvious" is the thought that precedes a symptom patch, a bundled diff, or a regression that surfaces weeks later. These are the excuses that precede every reopened bug. If you catch yourself thinking any row's "Excuse", stop: the "Reality" column is the exact rule you are about to break.

Excuse Reality (the rule being broken)
"Just add a null check where it crashes" Symptom-patching. Phase 2: if you are fixing a symptom, stop and go deeper — the real defect is whatever let null reach that line.
"Can't reproduce, but I'm sure it's X" Phase 1: if the bug cannot be reproduced, stop and report. Guess-patching a non-reproduced bug fixes nothing verifiable.
"3 levels deep, can't find it, patch the symptom" Phase 2: after 3 levels of indirection with no root cause, pause and report — do NOT apply a surface patch.
"Bug's obvious, I'll fix then add the test" Phase 3: the regression test MUST fail before the fix. Fix-first means you test your fix, not the bug.
"Test passed immediately, ship it" Phase 3 Rules: a test that passes before the fix does not cover the bug — rewrite it until it fails.
"While I'm in this file, also clean up…" Phase 4 rule 1: one conceptual change per fix. Bundling refactors/style/other-fixes pollutes the regression signal.
"Make the whole module null-safe while I'm here" Phase 4 rule 3: update only what is necessary. Over-fixing turns a 3-line surgical fix into a high-risk diff.
"Fix is isolated, skip the full suite" Phase 4 rule 5 + Phase 5: the full suite catches regressions your isolated view cannot.
"4 files but one module, standalone's fine" Routing Decision: escalate when uncertain. A false-standalone call skips quality gates on a complex change.
Incident Triage Carve-Out

When the bugfix occurs under active production incident pressure (user-facing outage, on-call escalation), the Phase 2→3 ordering can be temporarily relaxed — but never skipped:

  1. A stop-gap (symptom patch) MAY ship first to restore service.
  2. BUT the full root-cause trace + failing regression test + proper root-cause fix MUST land in the same incident window — never deferred to "tomorrow" or "a follow-up ticket".
  3. If you defer, you have not fixed the bug — you have shipped a symptom patch with a promise. Promises are not regression tests.

This carve-out exists because the rationalization table above cannot resolve a legitimate priority conflict (service down vs process discipline). It resolves it by permitting triage but forbidding deferral.


Pipeline Mode (bugfix)

Legacy path retired ([org-internal #3072] phase 3, 2026-08-21): the full requirements-elicitation → design → review-artifact(design-space) → plan-iterations → review-artifact(plan) front-end was archived (<instance-root>/archive/skills/). A big bug that needs a design-level decision now relabels Kind/Feature and enters the DAG route (see the big-bug relabel rule above) — repro + root-cause notes carry over as node input. The abort criteria below still apply to any multi-stage bug run before code is written.

When a bugfix escalates beyond standalone scope, the bug report becomes a pipeline input; the original bugfix phases (reproduce, root cause, regression test, fix) are embedded within the implement stage, and review-code + verify remain mandatory gates.

Pipeline Abort Criteria

Before any code is written in pipeline mode, abort the pipeline if ANY of:

# Condition Action
1 Bug no longer reproduces after environment change (strace re-isolation returns 0 reproductions, user confirms symptom resolved) Write ABORT to wiki page {slug}/ABORT (wiki 读写 API(见 TERMINOLOGY), preserve all completed artifacts, run retrospective
2 Root cause hypothesis is falsified during re-isolation (e.g., strace shows suspected git spawn is NOT hanging) Write ABORT.md, escalate to Architect for design revision OR abort pipeline
3 Bug is resolved by external change (new binary build, dependency update, OS/kernel patch) Write ABORT.md with resolution evidence, close without code changes
4 Reproduction confidence < 3/5 after re-isolation attempt Write ABORT.md if confidence cannot be improved within 1 re-isolation iteration

Abort procedure:

  1. Write ABORT to wiki page {slug}/ABORT (wiki 读写 API(见 TERMINOLOGY) documenting the reason, evidence, and which artifacts are preserved.
  2. Do NOT commit or merge the bugfix branch (no code was written).
  3. Run retrospective to extract process improvements.
  4. Archive artifacts to wiki page _archive/{slug}/ (wiki 读写 API(见 TERMINOLOGY) after retrospective.

Scope: these criteria apply before the implement stage. Once code is written, the pipeline proceeds through review-code → verify — abort is no longer valid.

Stage: Implement → Code Review → Verify

On the DAG route a bug-fix node's spec (ACs tracing to the repro + root cause) lives in {epic-slug}/dag; the Developer follows the bugfix Phases 16 (from standalone mode above) as the implementation method, then produces the standard implementation report (see ### Mode: implement (default), Phase 5). Code review runs all 10 dimensions against the bugfix changes. Verify runs the full DoD matrix including regression tests, integration tests, and NFR validation. Output pages: code review → {slug}/reviews/code/final/report; verification → {slug}/05-verify-iteration-1.