This guide addresses how to get better, more accurate code reviews with fewer false positives.
Automated code review tools generate false positives when they:
- Analyze outdated commits or cached state
- Lack full execution context across files
- Use pattern matching without semantic understanding
- Don't see recent fixes or documentation
-
"Shallow copy of Definition objects" at line 469
- Claim: Uses shallow copy causing shared state
- Reality:
[k, { ...v }]uses spread operator for deep copy - Verified:
__tests__/unit/analysis/graph-incremental.test.ts:204-223
-
"Missing validation for empty definition names"
- Claim: No validation prevents empty names
- Reality: Lines 551-552 explicitly validate
!def.name - Error Message: "name must be a non-empty string"
-
"Incomplete cleanup of call edges"
- Claim: Only cleans one direction of bidirectional graph
- Reality: Lines 157-196 clean both
callsandcallersmaps - Annotations: Added BIDIRECTIONAL comments for clarity
Static analyzers respond better to explicit annotations:
// BEFORE:
this.definitions = new Map(
Array.from(other.definitions.entries()).map(([k, v]) => [k, { ...v }])
);
// AFTER:
// SECURITY: Deep copy prevents mutation aliasing between graph instances
// Each Definition object is cloned using spread operator for independence
this.definitions = new Map(
Array.from(other.definitions.entries()).map(([k, v]) => [k, { ...v }])
);Keywords that help analyzers:
SECURITY:- Security-critical codeCORRECTNESS:- Correctness invariantVALIDATION:- Input validationBIDIRECTIONAL:- Graph/relationship cleanupDEFENSIVE:- Defense in depth
Link implementations to test coverage:
/**
* Remove all data for a file from the graph
*
* @test graph-builder.test.ts:removeFile - File removal
* @test graph-incremental.test.ts:204-223 - Clone independence
*/
removeFile(file: string): void {
// ...
}Make invariants explicit:
// INVARIANT: After this loop, no edges reference symbols in symbolsToRemove
for (const symbol of symbolsToRemove) {
// ... cleanup code
}
// POSTCONDITION: calls and callers maps are consistent and bidirectionalWe just added .github/multi-provider-review-hints.md with:
- Known correct implementations and their line numbers
- Test coverage references
- Explanations of algorithms and security properties
If using configurable review tools, provide:
Custom Rules (.eslintrc.js, sonar-project.properties, etc.):
module.exports = {
rules: {
// Disable rules that don't understand our patterns
'@typescript-eslint/no-explicit-any': 'off', // We have SerializedGraph types
'security/detect-object-injection': 'off', // False positives on Map access
},
overrides: [
{
files: ['src/analysis/context/graph-builder.ts'],
rules: {
// Graph builder has legitimate complexity
'sonarjs/cognitive-complexity': ['warn', 20],
},
},
],
};Suppression Comments for known false positives:
// eslint-disable-next-line security/detect-object-injection -- Safe: field is from typed array
if (!Array.isArray(data[field])) {
throw new Error(`Invalid graph data: ${field} must be an array`);
}Configure review tools to:
- Only analyze changed files (incremental analysis)
- Compare against base branch for context
- Cache analysis results between runs
- Access full git history for blame/context
GitHub Actions Example:
- name: Code Review with Full Context
uses: some-review-action@v1
with:
base-branch: main
head-branch: ${{ github.head_ref }}
incremental: true
cache-enabled: trueDifferent tools have different strengths:
| Tool | Strengths | Weaknesses |
|---|---|---|
| ESLint | TypeScript types, custom rules | Limited semantic analysis |
| SonarQube | Security vulnerabilities | Many false positives |
| CodeQL | Deep dataflow analysis | Slow, complex queries |
| Semgrep | Custom patterns | Requires pattern authoring |
| GPT-4/Claude | Semantic understanding | Cost, rate limits |
Strategy: Run multiple tools and intersect findings (high confidence).
Train human reviewers to:
- Verify automated findings before commenting
- Check test coverage for flagged code
- Look for recent commits that may have fixed issues
- Understand context before assuming bugs
Write project-specific rules that understand your patterns:
Semgrep Example (.semgrep/rules/graph-deep-copy.yml):
rules:
- id: graph-deep-copy-verified
pattern: |
new Map(
Array.from($MAP.entries()).map(([k, v]) => [k, { ...$V }])
)
message: "Verified deep copy pattern for Map of objects"
severity: INFO
languages: [typescript]Use tools that understand TypeScript's type system:
TypeScript ESLint with type checking:
module.exports = {
parserOptions: {
project: './tsconfig.json', // Enables type-aware rules
},
rules: {
'@typescript-eslint/no-unsafe-assignment': 'error',
'@typescript-eslint/no-unsafe-member-access': 'error',
},
};Benefits:
- Knows
Map.entries()returns[K, V][] - Understands
{ ...v }creates new object - Can verify type safety across files
Add runtime assertions that prove correctness:
removeFile(file: string): void {
// ... removal logic ...
if (process.env.NODE_ENV === 'test') {
// Verify postconditions
this.assertGraphIntegrity();
}
}
private assertGraphIntegrity(): void {
// All callers in calls map must have corresponding callers entry
for (const [caller, callees] of this.calls) {
for (const callee of callees) {
const callerList = this.callers.get(callee);
assert(
callerList?.includes(caller),
`Broken bidirectional edge: ${caller} -> ${callee}`
);
}
}
}Generate random inputs to verify invariants:
import fc from 'fast-check';
test('copyFrom creates independent copies', () => {
fc.assert(
fc.property(fc.array(fc.string()), fc.array(fc.string()), (files, symbols) => {
const graph1 = new CodeGraph(files);
for (const symbol of symbols) {
graph1.addDefinition(/* ... */);
}
const graph2 = new CodeGraph([]);
graph2.copyFrom(graph1);
// Mutate graph2
graph2.removeFile(files[0]);
// Verify graph1 unchanged
expect(graph1.getFiles()).toContain(files[0]);
})
);
});✅ Add explicit security/correctness comments ✅ Reference test coverage in documentation ✅ Use assertion comments for invariants ✅ Configure review tools with project context ✅ Verify automated findings before accepting ✅ Combine multiple analysis approaches
❌ Trust automated reviews blindly ❌ Accept findings without verification ❌ Ignore test coverage information ❌ Assume static analysis understands semantics ❌ Skip human review for critical code ❌ Disable all warnings (hides real issues)
- False Positive Rate: % of flagged issues that are actually correct code
- False Negative Rate: % of real bugs missed by automated review
- Time to Verify: How long humans spend checking automated findings
- Override Rate: % of automated findings marked "won't fix"
- False Positive Rate: < 20% (currently ~50%+ based on recent reviews)
- Time to Verify: < 5 minutes per finding
- Override Rate: < 10% (overrides should be rare)
Based on our current experience with false positives:
- ✅ Added documentation tags to graph-builder.ts
- ✅ Created review hints file at
.github/multi-provider-review-hints.md - ⏭️ Configure review tool to use hints file (if supported)
- ⏭️ Train review process to verify findings before commenting
- ⏭️ Add custom ESLint rules for project-specific patterns
This tool uses multiple LLM providers. To improve accuracy:
- Increase context window: Use models with larger context (e.g., Claude 3.5 Sonnet 200K)
- Provide file context: Configure to analyze related files together
- Use batch mode: Review related changes in single batch for better context
- Enable caching: Reuse analysis across similar code patterns
- Quality Profile: Create custom profile excluding noisy rules
- Issue Lifecycle: Mark false positives as "Won't Fix" with explanation
- Exclusions: Exclude test files and generated code
- Custom Rules: Write rules that match your coding patterns
- Custom Queries: Write queries specific to your security requirements
- Path Filters: Exclude paths where findings are always false positives
- Sarif Output: Post-process SARIF to filter known issues
- Query Variants: Create project-specific variants of standard queries
Improving code review quality requires:
- Immediate: Better documentation and annotations
- Medium-term: Tool configuration and process improvements
- Long-term: Custom rules and verification infrastructure
The goal is high signal-to-noise ratio: maximize real bugs caught, minimize false positives.
Current State: ~50% false positive rate (3/6 recent findings incorrect) Target State: <20% false positive rate with faster verification
Related Documentation:
.github/multi-provider-review-hints.md- Context for automated reviewsdocs/DEVELOPMENT_PLAN_V3.md- Future enhancements (v0.3.2+)docs/TROUBLESHOOTING.md- Common review tool issues