Interactive Finding Triage
Start an interactive triage session: the user classifies each finding in a browser UI, and decisions are written back to the report JSON.
Argument: $ARGUMENTS — path to the report.json produced by grumpy-review or check-pr-comments.
Workflow
Validate the report JSON against the schema:
python3 ${CLAUDE_SKILL_DIR}/../../scripts/validate_report.py "$ARGUMENTS"
Requires python3-jsonschema (apt install python3-jsonschema).
If validation fails, fix the JSON and re-validate. Do NOT start the triage server with invalid data.
The validator also prints non-blocking [consistency] warnings to stderr (label/band drift, or an un-rated axis such as relevance pinned at 1.0). These don't fail validation, but surface them to the user — severity labels are derived from likelihood/impact per claudius:severity (relevance drives merge_class/ordering only), never hand-typed, so a warning means the floats need rerating, not a label edit.
Start the triage server (default port 8741):
python3 ${CLAUDE_SKILL_DIR}/../../scripts/triage_server.py "$ARGUMENTS" [--port PORT]
The server auto-opens a browser; if that fails, it prints the URL for the user.
Wait for the user to complete triage in the browser and submit. The server writes the triage field back into the report JSON and exits.
Killing a stuck server
The server normally shuts down when the user submits with complete=true. If stuck, kill it by port — never pkill -f (risks killing servers from other sessions):
fuser -k 8741/tcp # kills whatever is bound to port 8741
Replace 8741 with the actual port if --port was used.
Read the updated report JSON and summarize the triage results:
- How many findings were triaged
- Breakdown by action (fix, accept_risk, defer, false_positive, duplicate)
- All
fix decisions with finding IDs and titles
For findings marked fix: apply the recommended fixes using the finding's location, description, and recommendation. Work through them one at a time, verifying each achieves the desired end-user or developer experience (not just code correctness) before proceeding.
For findings marked defer: add a TODO comment at the finding's location with a short descriptive slug and the finding's title — never the finding ID itself (coding-best-practices' Cross-Cutting Rules ban ephemeral review-finding IDs like SEC-004 in committed code; they're reassigned on every consolidator run and go dead after merge):
// TODO(banner-atomicity): BannerHandle is Send+Sync but read-modify-write is not atomic
Use the file's native comment syntax (//, #, <!-- -->, etc.). If traceability back to the original finding is wanted, put the ID in the PR/commit description or a coordinator-maintained ID→slug map — never in the committed comment text.
For findings marked accept_risk: add an INTENTIONAL comment at the finding's location documenting the accepted risk and rationale, again with a descriptive slug rather than the finding ID:
// INTENTIONAL(relaxed-ordering): Relaxed ordering adequate for single-threaded UI model
Use the rationale from the triage decision if provided, else summarize from the finding's description. Future reviews encountering an INTENTIONAL comment downgrade the finding to INFO severity — this match is by proximity to the flagged location, not by the slug text, so the slug is free-form.
Comment-Check Reports
For reports with metadata.report_type == "comment_check" (produced by check-pr-comments):
- Triage actions apply to unresolved PR review comments instead of code review findings
- accept_risk / false_positive: after triage, resolve the associated GitHub review thread using
${CLAUDE_SKILL_DIR}/../../scripts/gh-resolve-review-threads.sh with the finding's thread_id. Always ask user confirmation before resolving threads.
- fix: apply the fix described in
recommendation, then resolve the thread
- defer: leave the thread unresolved; add a
TODO comment as usual
- The triage decision's
resolve_thread field (boolean) indicates whether thread resolution is appropriate per decision
Output
The report JSON is updated in-place with a triage field containing all decisions — consumable by other tools or re-renderable with generate_review_report.py.
1---2name: triage-findings3description: This skill should be used when the user explicitly asks to "triage findings" through an interactive browser-based workflow. Only invoke when explicitly requested.4---56# Interactive Finding Triage78Start an interactive triage session: the user classifies each finding in a browser UI, and decisions are written back to the report JSON.910**Argument**: `$ARGUMENTS` — path to the `report.json` produced by `grumpy-review` or `check-pr-comments`.1112## Workflow13141. Validate the report JSON against the schema:15 ```bash16 python3 ${CLAUDE_SKILL_DIR}/../../scripts/validate_report.py "$ARGUMENTS"17 ```18 Requires `python3-jsonschema` (`apt install python3-jsonschema`).19 If validation fails, fix the JSON and re-validate. Do NOT start the triage server with invalid data.20 The validator also prints non-blocking `[consistency]` warnings to stderr (label/band drift, or an un-rated axis such as `relevance` pinned at `1.0`). These don't fail validation, but surface them to the user — severity labels are *derived* from `likelihood`/`impact` per `claudius:severity` (`relevance` drives `merge_class`/ordering only), never hand-typed, so a warning means the floats need rerating, not a label edit.21222. Start the triage server (default port 8741):23 ```bash24 python3 ${CLAUDE_SKILL_DIR}/../../scripts/triage_server.py "$ARGUMENTS" [--port PORT]25 ```26 The server auto-opens a browser; if that fails, it prints the URL for the user.27283. Wait for the user to complete triage in the browser and submit. The server writes the `triage` field back into the report JSON and exits.2930### Killing a stuck server3132The server normally shuts down when the user submits with `complete=true`. If stuck, kill it by port — **never `pkill -f`** (risks killing servers from other sessions):3334```bash35fuser -k 8741/tcp # kills whatever is bound to port 874136```3738Replace `8741` with the actual port if `--port` was used.39404. Read the updated report JSON and summarize the triage results:41 - How many findings were triaged42 - Breakdown by action (fix, accept_risk, defer, false_positive, duplicate)43 - All `fix` decisions with finding IDs and titles44455. For findings marked `fix`: apply the recommended fixes using the finding's `location`, `description`, and `recommendation`. Work through them one at a time, verifying each achieves the desired end-user or developer experience (not just code correctness) before proceeding.46476. For findings marked `defer`: add a `TODO` comment at the finding's location with a short descriptive slug and the finding's title — never the finding ID itself (`coding-best-practices`' Cross-Cutting Rules ban ephemeral review-finding IDs like `SEC-004` in committed code; they're reassigned on every consolidator run and go dead after merge):48 ```49 // TODO(banner-atomicity): BannerHandle is Send+Sync but read-modify-write is not atomic50 ```51 Use the file's native comment syntax (`//`, `#`, `<!-- -->`, etc.). If traceability back to the original finding is wanted, put the ID in the PR/commit description or a coordinator-maintained ID→slug map — never in the committed comment text.52537. For findings marked `accept_risk`: add an `INTENTIONAL` comment at the finding's location documenting the accepted risk and rationale, again with a descriptive slug rather than the finding ID:54 ```55 // INTENTIONAL(relaxed-ordering): Relaxed ordering adequate for single-threaded UI model56 ```57 Use the rationale from the triage decision if provided, else summarize from the finding's description. Future reviews encountering an `INTENTIONAL` comment downgrade the finding to INFO severity — this match is by proximity to the flagged location, not by the slug text, so the slug is free-form.5859## Comment-Check Reports6061For reports with `metadata.report_type == "comment_check"` (produced by `check-pr-comments`):6263- Triage actions apply to unresolved PR review comments instead of code review findings64- **accept_risk / false_positive**: after triage, resolve the associated GitHub review thread using `${CLAUDE_SKILL_DIR}/../../scripts/gh-resolve-review-threads.sh` with the finding's `thread_id`. Always ask user confirmation before resolving threads.65- **fix**: apply the fix described in `recommendation`, then resolve the thread66- **defer**: leave the thread unresolved; add a `TODO` comment as usual67- The triage decision's `resolve_thread` field (boolean) indicates whether thread resolution is appropriate per decision6869## Output7071The report JSON is updated in-place with a `triage` field containing all decisions — consumable by other tools or re-renderable with `generate_review_report.py`.