feat(review): add structured category and severity fields to findings#311
Conversation
Add two structured fields, category and severity, to every review finding so CI integrations can sort, group, filter, or gate builds without re-parsing natural-language comment text. - Tool schema (tools.json): add category/severity as enum-constrained, required properties of code_comment. severity is limited to critical/high/medium/low (info dropped, since LLMs struggle to distinguish low from info). - System prompt (task_template.json) is intentionally left untouched to avoid the review-quality regression observed on the benchmark suite; the tool schema alone drives field population. - JSON output: category/severity are flat siblings of content/start_line, omitted entirely when empty (backward compatible). - CLI output: render an inline [category - severity] badge before the comment, colored by severity. - Sync docs across all five README locales.
| func severityColor(severity string) string { | ||
| switch severity { |
There was a problem hiding this comment.
The severityColor function performs case-sensitive matching against lowercase severity values ("critical", "high", etc.), but the severity value comes directly from LLM output without any normalization (see internal/tool/code_comment.go). If the LLM returns "Critical", "HIGH", or "Medium", the color will silently fall back to dim (\033[2m) while the badge still displays the original casing.
Consider normalizing the severity to lowercase before matching, e.g.:
switch strings.ToLower(severity) {This makes the color assignment resilient to LLM casing variations.
Suggestion:
| func severityColor(severity string) string { | |
| switch severity { | |
| func severityColor(severity string) string { | |
| switch strings.ToLower(severity) { |
|
as #16 mentioned, want a filter flag. is it needed? last time i impled one. |
|
and want a rank function for output. first severity then category. |
There was a problem hiding this comment.
Pull request overview
Note
Copilot couldn't run its full agentic review because no GitHub Actions runner was available. Make sure your repository has a runner available to run Copilot's review, or add a copilot-setup-steps.yml file specifying one with the runs-on attribute. See the docs for more details.
Adds structured category and severity metadata to review findings so CI systems can reliably sort/filter/gate results without parsing free-form text.
Changes:
- Extends the finding model + parsing logic to carry
Category/Severity, and adds JSONomitemptybehavior. - Updates the tool schema (
tools.json) with enum constraints and required fields forcategory/severity. - Enhances CLI rendering to show a colorized inline
[category · severity]badge and adds unit tests + docs updates across locales.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/tool/code_comment.go | Parses category/severity from LLM tool output into the comment model. |
| internal/model/review.go | Adds Category/Severity fields with JSON serialization behavior. |
| internal/config/toolsconfig/tools.json | Enforces enum values and marks the new fields as required in the tool schema. |
| cmd/opencodereview/output.go | Renders a severity-colored badge inline before comment text. |
| cmd/opencodereview/output_test.go | Adds tests for badge building, severity colors, and inline rendering. |
| internal/tool/code_comment_test.go | Adds tests for parsing and JSON serialization of the new fields. |
| README*.md | Documents the new structured fields and their allowed values. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "required": [ | ||
| "content", | ||
| "existing_code" | ||
| "existing_code", | ||
| "category", | ||
| "severity" | ||
| ] |
| if category, ok := obj["category"].(string); ok { | ||
| cm.Category = category | ||
| } | ||
| if severity, ok := obj["severity"].(string); ok { | ||
| cm.Severity = severity | ||
| } |
| lines := wrapByRunes(content, 100) | ||
| for i, ln := range lines { | ||
| if i == 0 && badge != "" && strings.HasPrefix(ln, badge) { | ||
| color := severityColor(comment.Severity) | ||
| ln = color + badge + "\033[0m" + ln[len(badge):] | ||
| } | ||
| fmt.Printf("%s\n", ln) | ||
| } |


Summary
Adds two structured fields,
categoryandseverity, to every review finding so CI integrations (GitHub Actions, GitLab CI, etc.) can sort, group, filter, or gate builds without re-parsing natural-language comment text.This reworks #29 based on maintainer feedback in that thread.
Allowed values:
category:bug,security,performance,maintainability,test,style,documentation,otherseverity:critical,high,medium,lowWhat changed
tools.json):categoryandseverityare added asenum-constrained,requiredproperties ofcode_comment. Relying on the schema (rather than prompt guidance) is sufficient to drive reliable population.severitydropsinfo: limited tocritical/high/medium/low, since LLMs consistently struggle to distinguishlowfrominfo— fewer options yield more decisive, reliable output.task_template.jsonis intentionally left unchanged to avoid the review-quality regression observed on the benchmark suite. The tool schema alone drives field population.category/severityare flat siblings ofcontent,start_line, etc., and are omitted entirely when empty (omitempty), so existing consumers are unaffected.[category · severity]badge before the comment text, colored by severity (critical=bold red, high=red, medium=yellow, low=blue).Testing
make check— passesmake test— all packages passbuildBadge,severityColor, and inline badge rendering inrenderComment.Fixes #16