How AI code reviewers find bugs

Seven review tools, three historical fixes, and a shared review skill for FluentCRM, Fluent Boards and other repositories.

Review kit

Install the shared folder in your agent’s skills directory. Place the matching REVIEW.md at the root of each repository.

Download all three files ↓

Shared review skill
Download SKILL.md ↓

Resolve the target first. For a PR, compare the merge base to its exact head. For local work, inspect staged, unstaged and relevant untracked files. Identify intended behavior, supported callers and any explicitly deferred work. Treat the PR description as a statement of intent and check it against the implementation.

Read applicable project instructions and the root REVIEW.md when present. For a PR, use the base revision's review rules and review changes to those rules as part of the patch. When no context file exists, infer the contract from callers, tests and shipped interfaces. If a companion repository matters, identify the supported revision and record any unavailable evidence.

  1. Map the change. Follow each meaningful hunk from its entry point to the observable effect. Inspect direct callers, persisted data and affected consumers. For generated code or configuration, follow it into the system that executes it.
  2. Choose realistic starting states. Compare old and new behavior for inputs the system actually supports. Where relevant, trace an existing installation, missing or empty data, cancellation after selection, partial writes, retries or overlapping requests. Identify the party that owns the state at the time of use.
  3. Try to disprove each candidate. Check guards, caller normalization, transactions, version constraints and tests. Establish a reachable trigger, changed behavior and user-visible consequence. Check whether the same failure predates the patch. Keep it only if this change introduces or materially worsens it.
  4. Check the proof. Read the assertions and the path they execute. Use focused, side-effect-safe checks where available. Record whether the conclusion follows from source, a test, or a runtime observation. Name missing environment or dependency evidence when it affects the verdict.
  5. Report findings first. For each independent cause, give priority, changed file and line, trigger and consequence. State the smallest correction or test that would settle it. Rank by impact and reachability. Keep unresolved high-impact questions separate. Consolidate duplicates and skip style already enforced by project tooling.

If there are no supported findings, say so and name material coverage gaps. If the target changes, recheck affected paths against the new revision. A review request by itself authorizes analysis only.

FluentCRM context
Download REVIEW.md ↓

Apply the relevant contracts below alongside AGENTS.md. Start from the route, hook, worker or add-on that actually consumes the changed value.

Contact field updates

For Fluent Forms, trace raw form data and feed mapping through app/Services/ExternalIntegrations/FluentForm/Bootstrap.php into the contacts API. Once smartcodes are parsed, a hidden input and a submitted empty value can look identical. Use an existing contact with a populated custom field. Omission preserves it, deliberate clearing removes it, and a submitted zero survives. Cover both contact creation and update branches and nested mappings when touched. See tests/integration/fluentforms-empty-custom-field.php and fix 96e321385.

Automation step references

When editing import, copy or save, follow step IDs through app/Services/Funnel/FunnelHelper.php and the action consuming those IDs. A target must resolve inside its destination automation. Check a valid local target, a copied target requiring remapping, and a stale target from another funnel. Confirm the persisted reference after a second save. See tests/integration/automation-copy-step-targets.php and fix 49111f739.

Scheduled transitions

For recovery or bulk processing in app/Services/Funnel/FunnelProcessor.php, inspect the write predicate as well as the selection query. If a contact is cancelled or rescheduled between selection and update, the newer state must survive. Exercise a still-eligible contact in the same batch. Historical fix f1e47d9ef includes the interleaving and regression fixture. Check the worker implementation on the review target before applying this rule.

Core and FluentCampaign Pro

Treat resources/admin/shared/ exports and their import map as a public API. For a rename or removal, identify the consuming add-on version and inspect FLUENTCRM_MODULE_API in fluent-crm.php. Verify Core alone and the supported Core/Pro pairing. A Core build exercises only one side. For chunk changes, use the release asset audit described in AGENTS.md and distinguish emitted files from files actually shipped.

Checks

For PHP changes follow tests/README.md and the gate in AGENTS.md. For a finding, name the entry point, affected persisted value or downstream consumer, and an assertion that reaches it. Record any add-on, delivery provider or packaged-asset behavior still unverified.

Fluent Boards context
Download REVIEW.md ↓

Trace changed REST behavior from app/Http/Routes/api.php through its policy, controller and service. Use AGENTS.md for repository conventions.

Derived task views

A stored mention or notification can outlive board membership. When changing task visibility, follow both the result query and the category count in app/Services/TaskService.php. Use current board access for each. Check an accessible board and a formerly accessible board in the same view, including an empty incoming task-ID list. See tests/php/task-medium-access-boundaries-test.php and fix b3346062.

Task cover lifecycle

Follow upload, replacement, removal and the generic settings update through app/Http/Controllers/TaskController.php and TaskService. Cleanup must identify the image's owning task and object type. Existing settings can reference an image that no longer belongs to the task. Confirm the correct image is removed and unrelated images survive. The focused task boundary fixture above covers this ownership contract.

Notification delivery

In app/Services/TelegramService.php, follow recipient selection through enqueue and eventual delivery. Board access and global or per-board pauses can change while a job waits. Inspect the shared NotificationService checks at both stages, including retries. Exercise a still-eligible recipient alongside a paused one. Inspect tests/php/telegram-rich-delivery-test.php and tests/php/notification-current-access-test.php for the precise assertions available. Fix f9c73bd2 records the missed pause. A queued job alone does not demonstrate provider delivery.

Core and Pro handoff

For shared Telegram settings or hook ownership, trace registration, stored settings and the sibling plugin consumer. Check Core alone and mixed supported versions for duplicate dispatch or lost configuration. Start with tests/php/telegram-owner-handoff-test.php and tests/php/telegram-shared-contract-test.php. Record which combinations the fixtures model and whether a live provider was exercised.

Bulk and frontend state

For archive bulk operations in resources/admin/Components/Board/Menu/ArchiveTasks.vue, inspect selection after partial success. Succeeded rows should leave the selection and failures should remain available for retry. Follow response handling into the task list and its refreshed order. See b1cbeb24. Use the focused fixtures available on the target revision and identify any interaction that still needs a browser.

A reviewer can read every changed line and still miss the bug. In FluentCRM, a mapped field can arrive empty for two different reasons, and only one should clear a contact’s saved value. The decisive evidence lives on opposite sides of the integration. A useful repository review file tells the reviewer where to find both sides and which behavior the customer relies on.

Recommendation. Keep one shared review method and a short root REVIEW.md per repository. Use the shared method to establish what changed, seek contrary evidence, and decide what deserves a comment. Use the repository file for facts an incoming engineer could easily miss. Start with FluentCRM and Fluent Boards. Use a Go service as a transfer test before standardizing the method.

How seven review tools look for bugs

OpenCodeReview — prepared evidence. BridgLabs’ system assembles a revision-bound snapshot with changed code, related files, conventions and PR intent. Its universal skill asks for a sweep of changed behavior, followed by a pass that tries to disprove each candidate. The runtime prompt goes further than the skill alone. It requires an anchored finding, an evidence reference, a counter-evidence reference, and explicit missing evidence. It routes weak tests and stale documentation to suggestions. This is the closest published design to the proposed split. Its limit is retrieval completeness. A valid line citation can prove a guard exists while saying little about whether that guard protects the path under review. Universal skill · Runtime review contract

OpenCode — investigation from a local command. Its review template resolves working changes, commits, branches or PRs. It asks the agent to read whole changed files, inspect conventions and look up analogous implementations. It checks guards, error handling, behavior changes, obvious performance problems and structural fit. The publication test is concrete and qualitative. Identify the inputs and environment that make the issue real. This is a lightweight starting point for local review. Callers in a separately installed plugin still need an explicit pointer. OpenCode review command

Claude Code — independent search and validation. The public code-review plugin launches four discovery agents. Two check applicable project rules, one looks for obvious defects in the diff, and one examines introduced code. Bug candidates receive a validation pass. The prompt filters aggressively, including discouraging issues that depend on specific state. That tradeoff matters for upgrades and existing contacts. Anthropic’s managed service has a different documented scope. It reads surrounding code, looks for broken edge cases, verifies and deduplicates findings, then ranks them by severity. Its review reads code without executing it. Public plugin command · Managed review design

Codex CLI — a contract for what deserves a finding. The rubric requires an introduced, discrete, actionable defect that matters to the author. If the reviewer claims a change breaks another part of the system, it must identify the affected code. Findings carry a short diff location, priority and confidence. The patch receives a separate correctness verdict and confidence. Borrow the affected-caller requirement. A shared PHP method changing shape is actionable when the reviewer can identify a supported caller and the value it will now receive. Codex CLI rubric

PR-Agent — bounded, structured triage. Its templated reviewer focuses on introduced changes in supplied hunks. It explicitly accounts for truncated context. Output fields and limits vary by configuration, including key issues, review effort, relevant tests and a PR quality score. It allows an uncertain high-impact concern when the uncertainty is explicit. A capped list makes reviews easier to consume but can hide independent issues on large changes. A reviewer looking at hunks also needs a way to request the missing caller before claiming that validation is absent. PR-Agent reviewer template

CodeRabbit — encode recurring rules where they apply. Its documentation exposes three distinct mechanisms. Guideline files supply repository knowledge, path mappings scope that knowledge, and AST-based instructions identify structural patterns. Tool integrations can supply deterministic evidence. For example, its PMD integration documents configuration discovery and when a duplicate CI run is skipped. For Fluent products, the transferable idea is to scope a field-mapping rule to the integration that owns it. The public documentation establishes configuration behavior without exposing an internal confidence formula. Guideline discovery and scope · AST-based instructions · PMD integration

Greptile — retrieve across repository boundaries. Greptile describes an index of code relationships and repo clusters that make sibling repositories available as review context. This addresses a real Fluent Core/Pro problem. The caller can be absent from the PR repository. A cluster makes the other repository discoverable. The reviewer still needs the supported release pair, especially when both development branches have moved ahead of customers. Greptile displays per-comment priorities and a separate PR readiness score. The documented inputs include issue severity and count, change complexity and alignment with codebase patterns. Graph-based context · Repo clusters · Review scoring

What the scores actually measure

System Unit and scale Meaning for a maintainer
OpenCodeReview Finding severity, high / medium / low Orders confirmed findings. The skill ranks by impact, confidence and ease of fix, and suppresses numeric confidence in output.
OpenCode Qualitative severity The trigger and impact explain urgency. The reviewed command specifies no numerical threshold.
Claude Depends on workflow The public command uses validation. A separate feature-development reviewer uses a 0–100 judgment and reports at 80 or above. The managed service ranks verified findings by severity.
Codex CLI P0–P3 priority and 0–1 confidence Priority expresses urgency. Finding confidence and overall verdict confidence are distinct outputs.
PR-Agent Optional 0–100 PR quality and 1–5 review effort An expensive review can still cover a good patch. The figures answer different questions.
CodeRabbit Configurable checks and review rules A matched structural rule has a verifiable trigger. The reviewed docs give no basis for converting a match to a probability of failure.
Greptile P0–P2 inline priority and 0–5 PR readiness Readiness summarizes the whole patch. A 3/5 does not establish the probability that one particular comment is correct.

The frequently repeated Claude “80” threshold belongs to a specific reviewer definition. Applying it to every Claude workflow would misdescribe both the public command and the hosted product. None of these scales establishes calibration on Fluent projects. For the pilot, record impact, evidence and unverified behavior separately. A rare but demonstrated data-loss case can be high impact even when few users encounter it. Claude feature-development reviewer

Which words recur in public review instructions

Five pinned files above form the corpus. The table counts exact lowercased ASCII word tokens, split on every nonletter, across the entire files including examples, identifiers and template branches. Singular and plural are separate. Hosted documentation is excluded. There are 11,135 tokens. The three most frequent unrestricted words are “the” (510), “a” (318) and “or” (220). The table ranks selected review terms so their distribution is visible.

Term OpenCodeReview PR-Agent Codex Claude plugin OpenCode Total
code 26 32 14 15 10 97
review 33 37 5 9 9 93
issue 9 23 11 18 3 64
file 22 16 7 7 2 54
issues 3 17 4 23 2 49
changed 36 4 2 1 1 44
finding 26 4 9 0 0 39
diff 15 11 2 3 7 38
evidence 35 3 0 0 0 38
context 6 21 0 4 4 35

“Diff” appears in all five. “Evidence” is concentrated in OpenCodeReview, the longest file at 4,966 tokens. Codex never uses that exact word in its rubric yet requires a provably affected code path. PR-Agent’s examples and conditional branches repeat terminology. Copy the underlying instruction into your skill as a verifiable action, such as “name the affected caller and show the guard you checked.” Word counts alone cannot tell which prompt finds more bugs.

Three historical changes that expose different review blind spots

FluentCRM and the meaning of an empty field

In the Fluent Forms integration, parsed smartcodes can yield an empty value for both a hidden input omitted from a submission and a visible input deliberately cleared. The fix consults the original mapping and submitted form data, preserves explicit empties for custom fields, and changes how the contact API is called. A reviewer inspecting only the normalized value has already lost the evidence needed to tell the two cases apart. FluentCRM fix and integration test

Put in FluentCRM’s review context: For a mapped-field change, start with an existing contact with a saved custom value. Trace the original mapping, raw submission, formatted payload and both create-or-update call paths. Check omission, explicit empty, and a legitimate zero value separately. Name the stored value expected after each operation. A new-contact-only test cannot demonstrate preservation of existing data.

Fluent Boards and current board membership

A historical fix scopes both mentioned-task results and their count to the user’s currently accessible boards. A historical notification can outlive membership. The same commit also ties cover cleanup to the owning task and object type. These are distinct contracts with distinct evidence. A reviewer can correctly validate the list query and still miss the count, or inspect the cover update and miss cleanup through the generic settings path. Fluent Boards change and focused test

Put in Fluent Boards’ review context: For derived task views, enumerate list and count consumers and identify the current permission source. Include membership that changed after the activity was recorded. For attachment lifecycle changes, trace replacement, removal and generic settings updates through the ownership check. When Core moves a shared helper, record the Pro consumer and its supported version alongside the Core path.

Vantuly and the boundary between Go and first boot

Vantuly’s Go service generates a cloud-init shell script. A historical change introduced bounded installer retries because a newly provisioned machine can temporarily lack DNS or hold a package lock. The added Go test checks the generated text for the loop, pipeline behavior and logging. Those assertions can detect accidental template edits. They cannot establish that an installer recovers after a partial attempt or that the machine reaches the ready state. Vantuly service and test change

Put in the Go repository’s review context: When generated setup changes, name the process that actually executes it and the signal the UI treats as ready. Test a transient failure followed by success, exhaustion of retries and the resulting exit status. A local fake installer can exercise the generated shell cheaply. Actual first-boot behavior still requires a disposable machine. This example shows why “run Go tests” is too broad to describe the verification boundary.

A review method that transfers between repositories

  1. Fix the review target. Record the merge base and head, intended behavior and supported callers. For a working tree, include staged, unstaged and untracked changes. An older review belongs to its original revision.
  2. Identify the contract that changed. Start at the public entry point, follow the changed value to the effect a user or downstream caller observes, and read the nearest relevant test. Expand to a sibling repository only when the contract crosses it.
  3. Vary the starting state. Select the cases the change makes meaningful. Examples include an existing record, a revoked permission, old persisted settings, a repeated job or a partially completed external action. Record why the state is reachable.
  4. Try to disprove each candidate. Inspect the nearest guard, upstream normalizer, transaction, retry policy or consumer. Compare behavior at base and head. If the same failure occurs at both, establish how the patch changes reachability or impact before attributing it to the PR.
  5. Publish one actionable observation per root cause. Anchor the changed line, name the trigger and consequence, and cite the relevant consumer or contract. Record missing evidence as a specific open question. Keep coverage gaps visible even when no finding survives.

Example finding for the historical CRM behavior: “Preserve the saved field when the mapped input is absent. An existing contact can submit the form with this conditional input hidden. The parser produces the same empty string as an intentional clear. Check presence in the raw submission before building the custom-field update.” This gives the author a failing scenario and a legitimate behavior the fix must preserve.

What belongs in each repository

Use root REVIEW.md for repository-specific review knowledge. OpenCodeReview tests that base-revision conventions are supplied. Anthropic’s managed service documents base/default-branch review guidance. CodeRabbit can explicitly register a custom guideline filename through knowledge_base.code_guidelines.filePatterns. For a generic runner, make reading the file an explicit review step and verify that a known rule reaches the reviewer. An arbitrary filename such as code-review-context.md works when the adapter actually loads it. OpenCodeReview guideline tests · Claude managed review · CodeRabbit file mapping

A minimal entry should answer four questions. When does the rule apply? Where is the authoritative behavior? Which starting state exposes the mistake? What proves it? Give each file an owner. Remove rules already enforced completely by CI. Add a rule after a recurring miss only if it helps recognize a broader class of changes. Keep the existing independent final-diff review before commits and PR creation. The repository file supplies the facts that review needs.

How to measure whether the context file helps

Start with a paired pilot of 30 frozen changes, ten per project, including clean controls and separate examples of data preservation, authorization, upgrades, retries and API compatibility. This is a proposed pilot size. The three worked examples are teaching cases and should stay out of the held-out evaluation. Use the original defect-introducing or pre-fix PR snapshot for positive cases. Reviewing the repair diff would reveal the answer or reverse the task.

Compare three configurations on identical changes. A uses the shared skill alone. B adds repository context. C adds an independent validation pass to B. Keep the model version, tools, accessible repositories and budget fixed for A/B. Record the extra cost of C. Freeze the context before choosing held-out changes and hide later fixes, issue titles that disclose the defect, and previous bot comments. Repeat a subset to estimate run-to-run variability.

Judge root causes blind. Two maintainers independently match each comment to a reachable defect and record disagreements. Allow a newly discovered valid issue into the adjudicated set for all systems. Count duplicate comments separately as noise. Record a baseline with existing CI and human review so the team can see which defects the bot adds. ReviewBench provides a published precedent for distinguishing matches against a fixed reference set from additional findings. ReviewBench methodology

Measure Calculation or observation Decision it informs
Precision Confirmed unique findings / adjudicated unique findings emitted How often an engineer receives a useful comment
Known-defect recall Known root causes found / held-out known root causes Which failure classes the reviewer misses
Clean-PR noise Clean controls with a false finding / clean controls Cost of enabling automatic comments
Incremental yield Confirmed defects found by B but missed by A, and vice versa Whether repo context helped or displaced useful attention
Review cost Median elapsed time, model cost and maintainer triage minutes per PR Whether separate validation pays for itself
Incomplete reviews Count runs with missing sibling code, truncated scope or tool failure Whether the reviewer had enough evidence to finish

Report counts and denominators by project. Mark undefined rates when the denominator is zero. Inspect every newly missed high-impact case before rollout. Adopt the context file where it recovers repeatable defects at acceptable triage cost. Enable additional review passes only on the change classes where they earn their cost. A head-to-head tool run on these repositories remains necessary to rank products by actual bug yield.