Summary
Cora scan found 10 performance issues, all sharing the same pattern: repeated expensive operations inside loops that should be done once.
Issues
Regex recompiled per line (#41 — src/engine/rules/matching.rs:36)
Regex::new(&rule.pattern) called for every line of every rule. Should precompile once when loading rules.
Fix: Store compiled regex alongside each rule, compile once at load time.
Per-file DB queries in nested loops (#5 — src/mcp/tools.rs:528)
handle_find_affected_tests runs SQL per file → per symbol → per test pattern. Classic N+1 query pattern.
Fix: Batch lookups, prepare statements once, deduplicate before traversal.
Affected test analysis repeated graph lookups (#13 — src/main.rs:844)
Same N+1 pattern in the Affected command — queries symbols per file, callers per symbol.
Fix: Fetch all symbols for all files in one query, resolve callers in fewer set-based queries.
Prepared statement recreated in inner loop (#14 — src/main.rs:888)
conn.prepare(...) called inside test-pattern loop for every changed file.
Fix: Prepare once before loop, reuse statement.
Secrets scanner no early cutoff (#59 — src/engine/secrets_scanner.rs:137)
Scans all files/hunks/lines even after max_findings reached. Capped only after full scan.
Fix: Check findings.len() >= max_findings during scan and break early.
Symbol cap does not stop file scanning (#70 — src/engine/context/extraction.rs:281)
break exits only inner symbol loop, not the line iteration loop.
Fix: Add labeled break or guard before line extraction.
Repeated file reads during sibling search (#67 — `src/engine/context/resolver.rs:447)
resolve_function and resolve_type read same files from disk repeatedly.
Fix: Introduce file-content cache keyed by path for duration of context build.
New Tokio runtime per MCP tool call (#3 — src/mcp/tools.rs:643)
handle_review_diff creates fresh tokio::runtime::Runtime for every request.
Fix: Create and reuse single runtime for server lifetime.
Regex recompiled per line in detect_function_entry (#22 — src/index/extract.rs:423)
Creates new Regex instances per call. Module already uses LazyLock statics.
Fix: Move to static LazyLock<Regex> values.
Per-file transaction for prune_deleted (#24 — src/index/mod.rs:249)
Starts/commits separate transaction per deleted file.
Fix: Open one transaction before loop, commit once at end.
Effort estimate: 1-2 days
Summary
Cora scan found 10 performance issues, all sharing the same pattern: repeated expensive operations inside loops that should be done once.
Issues
Regex recompiled per line (#41 —
src/engine/rules/matching.rs:36)Regex::new(&rule.pattern)called for every line of every rule. Should precompile once when loading rules.Fix: Store compiled regex alongside each rule, compile once at load time.
Per-file DB queries in nested loops (#5 —
src/mcp/tools.rs:528)handle_find_affected_testsruns SQL per file → per symbol → per test pattern. Classic N+1 query pattern.Fix: Batch lookups, prepare statements once, deduplicate before traversal.
Affected test analysis repeated graph lookups (#13 —
src/main.rs:844)Same N+1 pattern in the
Affectedcommand — queries symbols per file, callers per symbol.Fix: Fetch all symbols for all files in one query, resolve callers in fewer set-based queries.
Prepared statement recreated in inner loop (#14 —
src/main.rs:888)conn.prepare(...)called inside test-pattern loop for every changed file.Fix: Prepare once before loop, reuse statement.
Secrets scanner no early cutoff (#59 —
src/engine/secrets_scanner.rs:137)Scans all files/hunks/lines even after
max_findingsreached. Capped only after full scan.Fix: Check
findings.len() >= max_findingsduring scan and break early.Symbol cap does not stop file scanning (#70 —
src/engine/context/extraction.rs:281)breakexits only inner symbol loop, not the line iteration loop.Fix: Add labeled break or guard before line extraction.
Repeated file reads during sibling search (#67 — `src/engine/context/resolver.rs:447)
resolve_functionandresolve_typeread same files from disk repeatedly.Fix: Introduce file-content cache keyed by path for duration of context build.
New Tokio runtime per MCP tool call (#3 —
src/mcp/tools.rs:643)handle_review_diffcreates freshtokio::runtime::Runtimefor every request.Fix: Create and reuse single runtime for server lifetime.
Regex recompiled per line in detect_function_entry (#22 —
src/index/extract.rs:423)Creates new
Regexinstances per call. Module already usesLazyLockstatics.Fix: Move to
static LazyLock<Regex>values.Per-file transaction for prune_deleted (#24 —
src/index/mod.rs:249)Starts/commits separate transaction per deleted file.
Fix: Open one transaction before loop, commit once at end.
Effort estimate: 1-2 days