BMAD-METHOD/src/bmm-skills/4-implementation/bmad-code-review/steps/step-03-triage.md

4.9 KiB

Step 3: Triage

RULES

  • YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config {communication_language}
  • Be precise. When uncertain between categories, prefer the more conservative classification.

INSTRUCTIONS

  1. Normalize findings into a common format. Expected input formats:

    • Adversarial (Blind Hunter): markdown list of descriptions
    • Edge Case Hunter: JSON array with location, trigger_condition, guard_snippet, potential_consequence fields
    • Acceptance Auditor: markdown list with title, AC/constraint reference, and evidence

    If a layer's output does not match its expected format, attempt best-effort parsing. Note any parsing issues for the user.

    Convert all to a unified list where each finding has:

    • id -- sequential integer
    • source -- blind, edge, auditor, static (auto-mode prefilter), or merged sources (e.g., blind+edge)
    • title -- one-line summary
    • detail -- full description
    • location -- file and line reference (if available)
  2. Deduplicate. If two or more findings describe the same issue, merge them into one:

    • Use the most specific finding as the base (prefer edge-case JSON with location over adversarial prose).
    • Append any unique detail, reasoning, or location references from the other finding(s) into the surviving detail field.
    • Set source to the merged sources (e.g., blind+edge).

    Prior-cycle ledger check ({auto_mode} only): if {spec_file} contains #### Review Ledger entries from earlier review cycles, treat them as already adjudicated. A new finding matching a previously dismissed entry (same location, same substance) is dismiss with reason "previously dismissed — see ledger" unless it brings genuinely new evidence. A finding matching a previously patched entry must be checked against the current code before re-raising — the patch may already cover it.

  3. Verify against the code ({auto_mode} only). For each surviving finding (except static ones — those are tool output), check it against the actual code before classifying. You have project access; the hunters that produced these findings mostly did not. A finding contradicted by the surrounding code — the case is already guarded, the function behaves differently than the finding assumes, the "missing" handling exists elsewhere — becomes dismiss with the contradiction recorded as its reason. Do not classify a finding you have not verified.

  4. Classify each finding into exactly one bucket:

    • decision_needed -- There is an ambiguous choice that requires human input. The code cannot be correctly patched without knowing the user's intent. Only possible if {review_mode} = "full".
    • patch -- Code issue that is fixable without human input. The correct fix is unambiguous.
    • defer -- Pre-existing issue not caused by the current change. Real but not actionable now.
    • dismiss -- Noise, false positive, or handled elsewhere.

    If {review_mode} = "no-spec" and a finding would otherwise be decision_needed, reclassify it as patch (if the fix is unambiguous) or defer (if not).

    If {auto_mode} and a finding would otherwise be decision_needed: reclassify as patch only when the fix is genuinely unambiguous; otherwise reclassify as defer with reason "auto-mode: needs human decision" AND record it in the result escalations — severity CRITICAL if it concerns correctness or security of the new code, else PREFERENCE (see ../automation-mode.md rule 5).

    If {auto_mode} and a finding's root cause is a defect in the spec itself (the code faithfully implements something the spec got wrong), handle it per ../automation-mode.md rule 6: if the root cause is inside the spec's <frozen-after-approval> block, classify as defer and record a CRITICAL (type: spec-defect) escalation — never patch around frozen, human-owned intent; if the root cause is outside the frozen block, classify as patch (correct the code to the evidently right behavior), mark it for the step-04 ## Spec Change Log append, and record a PREFERENCE escalation.

  5. Drop all dismiss findings. Record the dismiss count for the summary. ({auto_mode}: do NOT drop — set each dismissed finding aside, keeping its title, location, and one-line dismissal reason; step-04 writes them to the Review Ledger so later cycles do not re-litigate them.)

  6. If {failed_layers} is non-empty, report which layers failed before announcing results. If zero findings remain after dropping dismissed AND {failed_layers} is non-empty, warn the user that the review may be incomplete rather than announcing a clean review.

  7. If zero findings remain after triage (all rejected or none raised): state " Clean review — all layers passed." (Step 3 already warned if any review layers failed via {failed_layers}.)

NEXT

Read fully and follow ./step-04-present.md