| name | rb:triage |
| description | Use when triaging review findings interactively. Use after /rb:review to decide what to fix now, skip, or defer in a Ruby/Rails project. Prioritizes BLOCKER findings (Iron Law violations, security risks, migration safety) and routes selected items into a fix plan for /rb:work. |
| when_to_use | Triggers: "triage", "which to fix", "prioritize findings", "after review". |
| argument-hint | [path to review file] |
| effort | low |
Triage Review Findings
Batch-select findings from the review before creating follow-up work.
Iron Laws
- Auto-include all Iron Law violations - these are never optional
- Separate safety fixes from style preferences - prioritize data integrity
- Group related findings - fix together what belongs together
- Defer performance optimizations without profiling data
- Use structured multi-select, not freeform chat prompts โ when asking the user which findings to keep, use a checkbox-style selection UI
Workflow
Review File
โ
Parse Findings (BLOCKER / WARNING / SUGGESTION)
โ
โโโโโโโโโโโโโโโโโโโ
โ Auto-Categorize โ
โโโโโโโโโโโโโโโโโโโค
โ โข BLOCKER โ โ always include (auto, never optional)
โ โข WARNING โ โ recommend (default selected; user may defer)
โ โข SUGGESTION โ โ defer (default unselected; user may include)
โโโโโโโโโโโโโโโโโโโ
โ
Present Grouped Findings
โ
User Selects Items
โ
Write Triage Output
โ
Next Action
Severity Classification
Map review buckets (BLOCKER | WARNING | SUGGESTION) to triage
priorities. Within each bucket, order security findings only by
evidence_mode (defined in
${CLAUDE_PLUGIN_ROOT}/skills/security/SKILL.md ยง "Evidence Mode" and
${CLAUDE_PLUGIN_ROOT}/agents/security-analyzer.md ยง "Evidence Mode (mandatory)"):
runtime-confirmed โ act first
configuration-risk
static-signal
requires-human-validation โ surface to user for decision
Non-security findings carry no evidence_mode. Retain agent-emitted
order within the bucket.
BLOCKER โ Always Include
- Iron Law violations: transaction safety, after_commit discipline, JSON-safe args
- Security issues: SQL injection, XSS, mass assignment, hardcoded secrets
- Data integrity: missing constraints, race conditions, incorrect null handling
- N+1 queries: database performance killers
- Transaction safety: operations outside transactions that should be inside
WARNING โ Recommend Include
- Error handling (non-Iron-Law): missing error handling on external API calls (bare
rescue / rescue Exception is Iron Law 18 โ BLOCKER, not WARNING)
- Test coverage: missing tests for critical paths
- API contract: breaking changes to public APIs
- Documentation: missing docs for public methods
- Refactoring opportunities: complex methods, Law of Demeter violations
- Naming: unclear variable/method names
SUGGESTION โ Defer by Default
- Code style: inconsistent formatting (if not auto-fixable)
- Performance: without profiling evidence
- Micro-optimizations: minor efficiency gains
- Subjective preferences: personal style differences
- Future-proofing: speculative abstractions
- Comments: missing or misleading comments
Triage Process
Follow these 5 steps. Each reads from the review artifact, classifies
via review bucket, writes selected items to a fix plan.
Step 1: Load Review File
Argument resolution FIRST. Triage operates ONLY on a consolidated
review artifact (no plain description / no feature input):
$ARGUMENTS shape | Action |
|---|
| empty / absent | Resolve newest consolidated review: glob .claude/reviews/*-*.md, EXCLUDE .provenance.md sidecars (suffix -{datesuffix}.provenance.md) โ accept only files whose basename ends in -{datesuffix}.md with no .provenance segment. Direct children of reviews/ only (no per-reviewer subdirectory). Pick the file with the most recent mtime. If none found, STOP. Print: No consolidated review artifact found under .claude/reviews/. Run /rb:review first. |
.claude/reviews/{review-slug}-{datesuffix}.md (direct child of reviews/) | proceed |
.claude/reviews/{agent-slug}/{review-slug}-{datesuffix}.md (per-reviewer artifact under subdirectory) | STOP. Print: Path is a per-reviewer artifact, not the consolidated review. Run with the consolidated path: .claude/reviews/{review-slug}-{datesuffix}.md |
.claude/reviews/{review-slug}/RUN-CURRENT.json (manifest) | STOP. Print: Path is the manifest, not the consolidated review. |
| anything else (plain text, non-review path) | STOP. Print: /rb:triage operates on a consolidated review artifact. Run /rb:plan {description} for feature planning, or /rb:review first to produce a review artifact. |
After argument resolution passes, read the consolidated review markdown.
| Source section | Extract |
|---|
| Preamble | **Date**:, **Complexity**:, **Files Changed**:, **Reviewers**: (metadata) |
## Reviewer Coverage | Per-reviewer recovery state + finding counts |
## Reviewer Verdicts | Per-reviewer raw + canonical verdicts |
## Summary (then **Verdict**: line immediately AFTER the Summary table per ${CLAUDE_PLUGIN_ROOT}/skills/review/references/review-playbook.md ยง "Consolidated Review Format") | Severity counts + consolidated verdict |
## At-a-Glance Finding Table | Per-finding row: # / Finding / Severity / Confidence / Reviewer / File / New? |
## Blockers ({n}) / ## Warnings ({n}) / ## Suggestions ({n}) | Detailed finding bodies: **File**:, **Reviewer**: ... | **Confidence**:, **Issue**:, **Why it matters**: (Blockers only), **Current**: + **Suggested**: (Blockers code blocks), **Recommendation**: (Warnings) or **Suggestion**: (Suggestions) |
## Pre-existing Issues (unchanged code) | Findings to surface in plan's ## Pre-existing Issues (informational) only |
## Test Coverage Gaps ({n}) (REQUIRES CHANGES verdict only) | One row per uncovered NEW public surface; columns # / Surface / File / Why uncovered / Suggested test. Step 2b + Step 5 auto-include each row as a Phase 1 [test] task. |
For NEW At-a-Glance rows (New? = Yes), match each row to its
detailed finding by the Finding column text โ the At-a-Glance
Finding cell MUST equal the ### N. {Title} heading under the
appropriate ## Blockers / ## Warnings / ## Suggestions
section verbatim. Use (File, Reviewer, Severity) as a
corroboration tuple. Title text disambiguates the case where one
reviewer reports two findings of the same bucket against the same
path; the tuple alone is ambiguous in that case. The Iron Law
label for THIS NEW row's plan task line comes from the issue text
combined with the iron-laws.yml registry (e.g., "Multi-step
operations without transaction wrap" โ Iron Law 5).
Pre-existing At-a-Glance rows (New? = Pre-existing) have NO
backing ### N. {Title} heading โ ## Pre-existing Issues (unchanged code) lists them as bullets, not headings. The
Finding cell carries a concise description of the unchanged-code
issue. Surface them in the plan's ## Pre-existing Issues (informational) section unchanged; do NOT attempt the
title-verbatim match. Pre-existing findings NEVER produce a plan
task line, so NO Iron Law label / [annotation] / [Pn-Tm] is
derived for them โ Step 5 emits them as bullets, not as - [ ]
checkboxes (per Step 2 + Step 5 contract).
The plan's [annotation] value MUST be one of the canonical Set A
entries per ${CLAUDE_PLUGIN_ROOT}/skills/plan/references/planning-workflow.md
ยง "Plan Generation":
| Annotation | Use for |
|---|
[direct] | most common โ generic Ruby work, refactors, glue |
[active record] | models, migrations, ORM-touching findings |
[hotwire] | Turbo Streams, Frames, Stimulus, broadcasts |
[sidekiq] | jobs, queues, Sidekiq-specific findings |
[concurrency] | threads, fibers, async, race conditions |
[security] | auth, SQL injection, XSS, secrets, authorization |
[test] | spec / test additions or fixes |
Do NOT emit [ruby], [testing], [grape], [ar], [sequel],
[perf], or [general-purpose] โ those are descriptive narrative
labels (or subagent type names), not plan-task annotations, per
planning-workflow.md ยง "Plan-Task Annotations Cross-Reference".
Do NOT use the underscore form from iron-laws.yml category:
field. /rb:work parser routes on the canonical Set A only.
Step 2: Auto-Categorize via Review Bucket
Read each finding's bucket (BLOCKER | WARNING | SUGGESTION) AND
its New? column. Apply this filter FIRST:
New? = Pre-existing โ informational only; never auto-include,
never offer in selection UI. List under a separate "Pre-existing
Issues" section in the fix plan for context.
New? = Yes โ proceed to bucket-based categorization below.
For NEW findings:
- BLOCKER โ always include (auto-selected, never optional)
- WARNING โ recommend (default selected; user may defer)
- SUGGESTION โ defer (default unselected; user may include)
Step 2b: Verdict gate + Phase 1 auto-include source
Consolidated **Verdict**: | Phase 1 source (auto-include) |
|---|
BLOCKED | every NEW BLOCKER row from At-a-Glance + matched ## Blockers detail |
REQUIRES CHANGES | every row from ## Test Coverage Gaps ({n}) |
PASS WITH WARNINGS / PASS | none โ Phase 1 heading omitted entirely |
BLOCKED + REQUIRES CHANGES are mutually exclusive per playbook
STEP 4 (BLOCKED requires blockers > 0; REQUIRES CHANGES requires
blockers == 0). One source populates Phase 1, never both.
Gap row โ Phase 1 task line shape (REQUIRES CHANGES only):
- [ ] [P1-T{n}][test] Add spec for {Surface} โ test-coverage gap
(REQUIRES CHANGES); source {review-path}
/rb:plan {review-path} is the gaps-only entrypoint (no selection
UI). /rb:triage is the default; covers all mixed cases.
Step 3: Group Findings
Group NEW findings by [file, bucket] so batch-fixable items appear
together in the selection UI. The review artifact does NOT carry a
stable rule_id; do not invent one.
Step 4: Present Multi-Select UI
Use AskUserQuestion with multiSelect: true. Auto-include rules
per Step 2b verdict gate:
| Verdict | Auto-include (no UI) | Present in selection UI |
|---|
BLOCKED | every NEW BLOCKER (B<n>) | NEW WARNINGs (W<n>), NEW SUGGESTIONs (S<n>) |
REQUIRES CHANGES | every Test Coverage Gap row (G<n>) | NEW WARNINGs (W<n>), NEW SUGGESTIONs (S<n>) |
PASS WITH WARNINGS / PASS | none | NEW WARNINGs (W<n>), NEW SUGGESTIONs (S<n>) |
Never surface pre-existing findings in the selection UI. Drive
selection entirely through AskUserQuestion options; never accept
freeform-typed commands. Present this option set in the multi-select
prompt, bucket shortcuts first then individual items:
| Option label | Effect |
|---|
All WARNING | Select every NEW WARNING. Leave SUGGESTION selections untouched. |
All SUGGESTION | Select every NEW SUGGESTION. Leave WARNING selections untouched. |
Skip all WARNING | Defer every NEW WARNING. Leave SUGGESTION selections untouched. |
Skip all SUGGESTION | Defer every NEW SUGGESTION. Leave WARNING selections untouched. |
Group by file | Re-render the option list grouped by file. Do NOT change selection state. |
W<n> / S<n> (one row per finding) | Select the individual NEW WARNING / SUGGESTION. Description: file, line, one-line reason. |
Accept combinations of shortcuts and individual picks in one
response (e.g., All WARNING + S2 + S5). Resolve combinations
in selection order: cancel an earlier All WARNING when a later
Skip all WARNING follows; let individual W<n> / S<n> picks
override their bucket-level skip. Split into multiple screens when
6 selectable items.
Summarize state back, e.g.:
auto-included: B1 B2 B3 | selected: W1 | deferred: W2 S1 S2
or for REQUIRES CHANGES:
auto-included: G1 G2 | selected: W1 | deferred: W2 S1.
Step 5: Write Triage Output
Save the plan to .claude/plans/{slug}/plan.md using the canonical
template at
${CLAUDE_SKILL_DIR}/references/triage-plan-template.md. Emit the
template's full surface in this order:
# Plan: {slug} heading.
**Status**: IN_PROGRESS / **Created** / **Last Updated**
preamble (per ${CLAUDE_PLUGIN_ROOT}/skills/work/references/file-formats.md
so /rb:work parses + resumes correctly).
## Metadata (Source Review, Generated By, Triaged By).
## Summary table (Bucket / Total / Selected / Deferred / Excluded).
- Phase 1 (auto-include; heading per Step 2b verdict gate):
## Phase 1: Blockers [PENDING] (BLOCKED verdict) โ task lines - [ ] [P1-Tn][annotation] ... per NEW BLOCKER.
## Phase 1: Test Coverage Gaps [PENDING] (REQUIRES CHANGES verdict) โ task lines - [ ] [P1-Tn][test] ... per gap row.
- Phase 1 heading OMITTED entirely for PASS / PASS WITH WARNINGS verdicts (no auto-include source).
## Phase 2: Warnings (selected) [PENDING] โ task lines - [ ] [P2-Tn][annotation] ... (only NEW WARNINGs the user selected at Step 4). Omit the heading when zero warnings selected.
## Phase 3: Suggestions (selected) [PENDING] โ task lines
- [ ] [P3-Tn][annotation] ... (only NEW SUGGESTIONs the user
selected via S<n> at Step 4). Omit the entire phase heading
when zero suggestions selected.
## Deferred Findings (NEW Warnings + Suggestions the user did NOT select; excluded entirely from any Phase).
## Pre-existing Issues (informational) โ every New? = Pre-existing
finding from Step 1, file + line + reviewer + one-line note. NEVER
emit as - [ ] task lines.
## Next Steps โ /rb:work invocation, time estimate, deferred-review note.
Decision Tree
Read the review's existing bucket per finding. Override only when
the bucket is missing or ambiguous:
Review bucket = BLOCKER?
โโโ YES โ always include
โ โโโ never optional
โ
โโโ NO โ bucket = WARNING?
โโโ YES โ recommend (default selected; user can defer)
โ
โโโ NO โ bucket = SUGGESTION?
โโโ YES โ defer (default unselected; user can include)
โ
โโโ NO โ bucket missing / ambiguous โ ask user
Batch Operations
Select All in Bucket
BLOCKERs are auto-included by Step 4; do NOT surface a "Select All
BLOCKER" shortcut in the selection UI. Offer only WARNING /
SUGGESTION + cross-cutting filters:
[Select All WARNING]
[Select All SUGGESTION]
[Select All in File: app/models/user.rb]
[Select All of Type: N+1]
Smart Grouping
Bucketize findings via reasoning, not by running code. Step 3
already pins the primary key: group NEW findings by
(file, bucket). Review artifacts carry no stable identifier
beyond that tuple โ do NOT invent one.
| Grouping rule | Effect on selection UI |
|---|
Same (file, bucket) with โฅ 2 occurrences | Surface together; recommend fix_together |
Findings touching the same domain layer (e.g., 2+ in app/models/*) | Optional cross-cutting shortcut (e.g., "Select All in app/models/"); recommend fix_sequentially |
| Different buckets in same file | Keep separate โ auto-include / recommend / defer follows the bucket, not the file |
Integration with Workflow
From Review
# After review completes
/rb:review app/models/user.rb
# โ Creates `.claude/reviews/{review-slug}-{datesuffix}.md`
# Then triage
/rb:triage .claude/reviews/fix-user-model-20260505-123000.md
# โ Creates .claude/plans/fix-user-model/plan.md
# Then work on selected items
/rb:work .claude/plans/fix-user-model/plan.md
Direct to Work
If triage generated a plan with selected BLOCKER items:
/rb:work .claude/plans/fix-user-model/plan.md
# โ Works on the selected findings as normal plan tasks
Edge Cases
Empty Selection
If user selects nothing:
No findings selected. Options:
[Review All Findings Again]
[Create Note: "Reviewed, no action needed"]
[Cancel]
All BLOCKER
If all findings are BLOCKER:
All 5 findings are BLOCKERs and must be addressed.
Estimated time: 2 hours
[Start Work]
[Start Work] invokes /rb:work against the generated plan.
Contradictory Findings
If findings conflict:
โ ๏ธ Warning: Contradictory findings detected
Finding A: "Extract method to reduce complexity"
Finding B: "Inline method for clarity"
These may conflict. Review together?
[Review Both] [Skip Both]
Output Format
Sole output: .claude/plans/{slug}/plan.md. Tasks MUST use the
canonical - [ ] [Pn-Tm][annotation] ... format from
${CLAUDE_PLUGIN_ROOT}/skills/work/references/file-formats.md +
canonical Set A annotations from
${CLAUDE_PLUGIN_ROOT}/skills/plan/references/planning-workflow.md
ยง "Plan Generation". /rb:work parser routes on this format and
resumes via --from Pn-Tm.
Example for BLOCKED verdict (Phase 1 = Blockers):
# Creates `.claude/plans/{slug}/plan.md` with selected findings as tasks
## Phase 1: Blockers [PENDING]
- [ ] [P1-T1][active record] Fix transaction wrap in `User.create_with_profile` โ Iron Law 5
- [ ] [P1-T2][sidekiq] Fix JSON-safe args in `EmailJob#perform` โ Iron Law 9
- [ ] [P1-T3][active record] Fix N+1 in `OrdersController#index` โ Iron Law 3
## Phase 2: Warnings (selected) [PENDING]
- [ ] [P2-T1][test] Add edge-case spec for `PaymentService` refund branch
## Phase 3: Suggestions (selected) [PENDING]
- [ ] [P3-T1][direct] Extract `RETRY_LIMIT` constant in `SyncService`
Example for REQUIRES CHANGES verdict (Phase 1 = Test Coverage Gaps):
# Creates `.claude/plans/{slug}/plan.md` with selected findings as tasks
## Phase 1: Test Coverage Gaps [PENDING]
- [ ] [P1-T1][test] Add spec for `PasswordsController#create` โ test-coverage gap (REQUIRES CHANGES); source .claude/reviews/...md
- [ ] [P1-T2][test] Add spec for `PasswordsController#create` 429 throttle branch โ test-coverage gap (REQUIRES CHANGES); source .claude/reviews/...md
Phase 1 heading is OMITTED entirely for PASS / PASS WITH WARNINGS
verdicts. Phase 2 + Phase 3 headings are OMITTED when zero items
selected at Step 4.
Best Practices
- Always explain why a finding is BLOCKER
- Show estimated effort for each item
- Group by location when possible for efficient fixing
- Preserve excluded items for future reference
- Link to documentation for Iron Law violations
- Suggest alternatives for deferred items (e.g., "Use RuboCop auto-fix")
Commands
| Command | Description |
|---|
/rb:triage | Triage most recent consolidated review |
/rb:triage <file> | Triage specific review file |
For in-UI bucket shortcuts (All WARNING, Skip all WARNING,
Group by file, โฆ), surface them as AskUserQuestion option labels
per ยง "Step 4: Present Multi-Select UI"; never prompt the user to
type them as commands.
References
| Need | Reference |
|---|
| auto-approve / usually-fix / often-skip rules + severity reclassification | ${CLAUDE_SKILL_DIR}/references/triage-patterns.md |
| canonical fix-plan output template (Step 5 destination format) | ${CLAUDE_SKILL_DIR}/references/triage-plan-template.md |
Trust States
When triaging a review with a provenance sidecar, read the sidecar's
trust_state (see
${CLAUDE_PLUGIN_ROOT}/references/output-verification/trust-states.md):
conflicted: surface findings in a dedicated section labeled
"Conflicted evidence โ resolve before triage".
missing: tag each finding [unverified]; treat as hint, not
decision.
weak: include findings but sort after runtime-confirmed
evidence.
clean: proceed with normal triage.