diff --git a/CLAUDE.md b/CLAUDE.md index 4d1f235..a8b8f35 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -20,6 +20,7 @@ cargo run -- --help # CLI usage - `migrations/` — PostgreSQL migrations (sqlx) - `eval/` — Evaluation and benchmarking - `examples/` — Usage examples +- `docs/` — Mutation testing, **ROADMAP.md** (enhancement backlog + gh CLI workflow) ## Development - Run `bash scripts/install-hooks.sh` once to install pre-commit and pre-push hooks (merge conflict check, trailing newline, conditional Rust/web checks, shellcheck; pre-push adds version sync, cargo audit, full web build+test). Mutation testing runs in CI only; see `docs/mutation-testing.md`. diff --git a/README.md b/README.md index fcfc276..b9ace2c 100644 --- a/README.md +++ b/README.md @@ -1000,7 +1000,7 @@ The summary includes: ## Contributing -Contributions are welcome! Please open an issue first to discuss what you would like to change. +Contributions are welcome! Please open an issue first to discuss what you would like to change. Enhancement backlog and triage: see [docs/ROADMAP.md](docs/ROADMAP.md) and `gh issue list --label "priority: high"`. **PR workflow:** Open a PR → ensure CI is green (version, lint, security, test, mutation, review) → merge when ready. Use a short test plan in the PR description. Small, focused PRs are preferred. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 0000000..8f94b35 --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,85 @@ +# DiffScope roadmap + +Enhancement backlog derived from open GitHub issues. Use **gh CLI** for triage and filtering. + +## gh CLI workflow + +```bash +# List open issues (default: 30) +gh issue list + +# Filter by label +gh issue list --label "priority: high" +gh issue list --label "area: review-pipeline" + +# Search (advanced filters) +gh issue list --search "no:assignee sort:created-asc" +gh issue list --search "verification OR RAG" + +# View one issue +gh issue view 32 + +# Add/remove labels (labels must exist: gh label create "name" --color "hex" --description "desc") +gh issue edit 32 --add-label "priority: medium,area: plugins" +gh issue edit 32 --remove-label "help wanted" + +# Add to project (requires project scope) +gh issue edit 32 --add-project "Roadmap" +``` + +Create labels once: `priority: high`, `priority: medium`, `priority: low`, `area: review-pipeline`, `area: plugins`, `area: platform`. + +--- + +## Priority: High / Critical + +| # | Title | Area | Notes | +|---|--------|------|--------| +| [27](https://github.com/evalops/diffscope/issues/27) | Embedding-based false positive filtering from developer feedback | review | Greptile-style: block if similar to 3+ downvoted; pass if 3+ upvoted. Per-team. | +| [23](https://github.com/evalops/diffscope/issues/23) | Verification pass to catch hallucinations | review | Second LLM pass validates findings vs actual code; drop below score. **Partially done** (verification in config/pipeline). | +| [22](https://github.com/evalops/diffscope/issues/22) | Embedding-based RAG pipeline with function-level chunking | review | NL summaries + pgvector; highest leverage for catch rate. | +| [24](https://github.com/evalops/diffscope/issues/24) | Agentic review loop with tool use | review | Tools: search_code, read_file, search_symbols, git_log, git_blame. | +| [21](https://github.com/evalops/diffscope/issues/21) | Multi-agent architecture: review + fix + test agents | platform | Fix Agent, Test Agent, Triage Agent; orchestration. | +| [10](https://github.com/evalops/diffscope/issues/10) | Deep codebase graph context in review prompts | review | Pre-index repo; inject callers/callees/contracts into prompt. | + +## Priority: Medium + +| # | Title | Area | Notes | +|---|--------|------|--------| +| [32](https://github.com/evalops/diffscope/issues/32) | In-sandbox linter/analyzer execution | plugins | ToolSandbox + AnalysisTool trait; Clippy, Ruff, Gitleaks, ShellCheck, actionlint. | +| [31](https://github.com/evalops/diffscope/issues/31) | AST-based structural pattern matching (ast-grep) | plugins | Pre-analyzer plugin; coderabbitai/ast-grep-essentials rules. | +| [30](https://github.com/evalops/diffscope/issues/30) | Adaptive patch compression for large PRs | review | Full → Compressed → Clipped → MultiCall; token budget. | +| [29](https://github.com/evalops/diffscope/issues/29) | File triage: classify before expensive review | review | NeedsReview vs Cosmetic/ConfigChange/TestOnly; heuristic + cheap model. | +| [28](https://github.com/evalops/diffscope/issues/28) | Robust LLM output parsing with fallback strategies | review | **In progress:** code-block extraction, trailing commas, diff-prefix strip. More fallbacks in parsing/llm_response.rs. | +| [25](https://github.com/evalops/diffscope/issues/25) | Dynamic context: enclosing function/class boundary | review | Search upward for boundary; reuse symbol_index patterns. | + +## Priority: Low / Tier 2–3 + +| # | Title | Area | Notes | +|---|--------|------|--------| +| [20](https://github.com/evalops/diffscope/issues/20) | Built-in secrets detection scanner | plugins | **Done:** `secret_scanner.rs` with AWS, GitHub, Slack, JWT, PEM, etc. | +| [19](https://github.com/evalops/diffscope/issues/19) | Compliance review command | platform | `diffscope compliance` — security, secrets, rules, ticket, licenses, duplication. | +| [18](https://github.com/evalops/diffscope/issues/18) | Authentication layer for web UI (SSO/SAML) | platform | Basic → OAuth/OIDC → SAML, RBAC. | +| [17](https://github.com/evalops/diffscope/issues/17) | GitLab, Azure DevOps, Bitbucket support | platform | GitPlatform trait; GitLab first. | +| [15](https://github.com/evalops/diffscope/issues/15) | Auto-generate Mermaid sequence diagrams in PRs | review | Symbol graph → sequence diagram in PR comment. | +| [14](https://github.com/evalops/diffscope/issues/14) | VS Code / IDE extension | platform | Staged/unstaged review, inline diagnostics, Quick Fix. | +| [13](https://github.com/evalops/diffscope/issues/13) | Ticket validation (Jira/Linear/GitHub Issues) | platform | Fetch ticket, validate acceptance criteria. | +| [12](https://github.com/evalops/diffscope/issues/12) | Natural language custom review rules | review | Prose rules in YAML or `.diffscope-rules`. | +| [11](https://github.com/evalops/diffscope/issues/11) | PR analytics and review metrics dashboard | platform | Persist to PG, aggregation, dashboard. | +| [9](https://github.com/evalops/diffscope/issues/9) | Structured PR description auto-generation | platform | `pr describe` — walkthrough, labels, breaking, testing notes. | + +--- + +## Shipped (recent) + +- **LLM parsing (#28):** Repair candidate for diff-style line prefixes (`+` on each line) in `repair_json_candidates`; test `parse_json_with_diff_prefix_artifact`. +- **Secrets (#20):** Built-in secret scanner in `plugins/builtin/secret_scanner.rs`. +- **Verification (#23):** Verification pass and config (verification.*) in pipeline. + +--- + +## References + +- [GitHub CLI manual](https://cli.github.com/manual/) +- [Advanced issue search](https://docs.github.com/en/search-github/searching-on-github/searching-issues-and-pull-requests) +- [gh issue edit](https://cli.github.com/manual/gh_issue_edit) — labels, assignees, projects, milestones diff --git a/src/parsing/llm_response.rs b/src/parsing/llm_response.rs index d22f093..85695a5 100644 --- a/src/parsing/llm_response.rs +++ b/src/parsing/llm_response.rs @@ -347,13 +347,27 @@ fn find_balanced_json(content: &str, open: char, close: char) -> Option fn repair_json_candidates(candidate: &str) -> Vec { static TRAILING_COMMAS: Lazy = Lazy::new(|| Regex::new(r",\s*([}\]])").unwrap()); - let mut candidates = vec![candidate.trim().to_string()]; - let without_trailing_commas = TRAILING_COMMAS - .replace_all(candidate.trim(), "$1") - .to_string(); - if without_trailing_commas != candidate.trim() { + let trimmed = candidate.trim(); + let mut candidates = vec![trimmed.to_string()]; + + let without_trailing_commas = TRAILING_COMMAS.replace_all(trimmed, "$1").to_string(); + if without_trailing_commas != trimmed { candidates.push(without_trailing_commas); } + + // When LLM echoes JSON with diff-style line prefixes (leading "+"), strip them (issue #28). + let without_diff_prefix: String = trimmed + .lines() + .map(|line| line.strip_prefix('+').map(str::trim).unwrap_or(line)) + .collect::>() + .join("\n"); + let without_diff_prefix = without_diff_prefix.trim(); + if without_diff_prefix != trimmed + && (without_diff_prefix.starts_with('[') || without_diff_prefix.starts_with('{')) + { + candidates.push(without_diff_prefix.to_string()); + } + candidates } @@ -1218,6 +1232,17 @@ let data = &input; assert_eq!(comments[0].line_number, 5); } + #[test] + fn parse_json_with_diff_prefix_artifact() { + // LLM sometimes echoes JSON in a code block with leading "+" on each line (diff artifact); repair strips (issue #28). + let input = "```json\n+[{\"line\": 7, \"issue\": \"Missing check\"}]\n+\n```"; + let file_path = PathBuf::from("src/lib.rs"); + let comments = parse_llm_response(input, &file_path).unwrap(); + assert_eq!(comments.len(), 1); + assert_eq!(comments[0].line_number, 7); + assert!(comments[0].content.contains("Missing check")); + } + // ── Bug: find_json_array uses mismatched brackets ────────────────── // // `find_json_array` uses `find('[')` (first) + `rfind(']')` (last).