Skip to content
CAI
Software that uses CAICheck a score

flyerhzm/bullet

72.7

Strong · 26 September 2026

3.2k

lines of production code

Ruby

primary language

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is the Bullet gem, a development tool designed to detect N+1 query and unused eager loading performance issues in Ruby on Rails and Mongoid applications. It provides thread-safe detection capabilities with modular architecture, supporting a wide range of ActiveRecord and Mongoid versions while offering fine-grained control over notifications and logging. The system integrates directly into the application lifecycle to identify association inefficiencies and alert developers with contextual information to facilitate optimization.

How it got here

2009 — Thread-safe architecture and Rails 8.1 support

8 changes.

The project underwent a major refactoring to replace class variables with thread-local storage, ensuring thread safety for concurrent request handling. This architectural shift was accompanied by expanded support for Rails 7.0–8.1 and Mongoid 4–9 through version-specific adapters, alongside the introduction of fine-grained control APIs for enabling, pausing, and skipping detection.

2010–2017 — Architecture refactoring and test expansion

16 changes.

The codebase underwent a major structural refactoring, replacing monolithic classes and global monkey-patches with dedicated namespaces, thread-local state, and Ruby refinements to improve memory efficiency and compatibility. This architectural overhaul was accompanied by the addition of an installation generator and a comprehensive expansion of the test suite, including new fixtures and integration tests for both ActiveRecord and Mongoid.

Features

Add install generator for Bullet configuration

A new \Bullet::Generators::InstallGenerator\ has been added to the library. Running this generator automatically configures Bullet for the development and test environments by injecting the necessary settings (such as enabling N+1 query detection, logging, and alerts) into the respective \config/environments/\ files, streamlining the initial setup process for new applications.

lib/generators · high confidence

Added task to clear Bullet log file

A new Rake task, \rake bullet:log:clear\, has been added to the application. This task truncates the \log/bullet.log\ file to zero bytes, allowing users to easily clear out Bullet performance analysis logs without manually deleting the file.

tasks · high confidence

Support for Rails 7.0–8.1 and MongoDB 4–9 via version-specific adapters

Bullet now detects the installed ActiveRecord and Mongoid versions and loads dedicated adapter files (e.g., active\_record70.rb through active\_record81.rb and mongoid4x through mongoid9x) to hook into the correct internal APIs. This ensures N+1 and unused-eager-loading detection works across Rails 7.0–8.1 and Mongoid 4–9, while dropping support for ActiveRecord older than 7.x. The change also adds ActiveJob profiling via a new ActiveJob module and introduces a dependency-detection module to validate supported versions at runtime.

lib/bullet · high confidence

Behavioural changes

Bullet gem v8.2.0 release with thread-safe control APIs and Rails 8.1 support

This release introduces thread-safe \Bullet.pause\, \Bullet.resume\, \Bullet.paused?\, and \Bullet.skip\ APIs, allowing developers to control detection in multi-threaded environments without modifying global flags. It adds support for Rails 8.1 and drops support for ActiveRecord versions older than 7 and Mongoid versions older than 8. The changelog also notes fixes for unused eager loading false positives (including conditional \has\_many :through\ and disabled detection scenarios) and Ruby 4.0 compatibility. Configuration options now include configurable footer positioning and the ability to skip HTML injection or HTTP headers for API requests.

(repo-wide) · high confidence

Initialize Bullet middleware in Rails

The Rails application now explicitly requires the 'bullet' library during initialization. This change ensures that the Bullet middleware is available for use, likely to detect N+1 queries and other performance issues in development, although the specific conditional loading mentioned in commit messages is not visible in this diff excerpt.

rails · medium confidence

Major refactoring of Bullet core with thread-safe detection and modular architecture

The Bullet library has been significantly restructured to improve reliability and maintainability. The core detection logic now uses thread-local variables instead of class variables, ensuring thread safety for concurrent requests. The architecture is now modular, with autoloaded namespaces for ActiveRecord, Mongoid, Rack, ActiveJob, and various detectors (NPlusOneQuery, UnusedEagerLoading, CounterCache). Configuration options have been expanded to allow fine-grained control, including enabling/disabling specific detectors (n\_plus\_one\_query, unused\_eager\_loading, counter\_cache), customizing stacktrace filtering, and skipping HTML/HTTP header injection for API-only applications. The middleware insertion logic has been updated to respect Content Security Policy (CSP) settings and API-only modes. Additionally, the library now supports a wider range of notifiers via UniformNotifier and provides methods to manage safelists for associations.

lib · high confidence

Refactored key generation to support composite primary keys and avoid global namespace pollution

The library now uses Ruby refinements to add \bullet\_key\ and \bullet\_primary\_key\_value\ methods to \Object\ and \bullet\_class\_name\ to \String\, avoiding the previous approach of monkey-patching global classes. This change improves compatibility with composite primary keys (including the \composite\_primary\_keys\ gem and Rails 7.1) by correctly handling multiple key columns, and ensures that unpersisted records are handled safely without raising errors.

lib/bullet/ext · high confidence

Refactored registry and notification collection logic

The Bullet gem now uses a dedicated NotificationCollector class to manage detected issues and a Registry::Base class to handle association tracking, replacing previous implementations that relied on Array\#unique. This change improves performance by using Set-based storage to avoid redundant checks and reduces memory overhead during N+1 query detection. A new benchmark script is also included to measure these performance gains against previous versions.

bullet · high confidence

Refactored registry internals to improve memory usage and detection accuracy

The Bullet gem has restructured its internal registry system by moving registry classes into a dedicated namespace (Bullet::Registry) and introducing specialized registries for associations, call stacks, and objects. This change enhances N+1 query detection by including the caller stack in association calls, allowing for more precise identification of eager loading violations. Additionally, the refactoring includes performance optimizations, such as memoizing the call stack registry to significantly reduce memory allocation during analysis, and fixes a bug where a nil return value from flatten caused downstream errors. The changes also avoid polluting global classes like String and Object by using module extensions.

lib/bullet/registry · high confidence

Restructured detector logic into dedicated classes with thread-local state

The detection logic for N+1 queries, unused eager loading, and counter cache issues has been refactored from a monolithic structure into separate classes (NPlusOneQuery, UnusedEagerLoading, CounterCache) inheriting from a common Base. This change moves internal state storage from class variables to thread-local variables to prevent data leakage across concurrent requests. It also introduces specific safeguards to skip detection for polymorphic belongs\_to associations with nil types and excludes HABTM associations from N+1 detection to reduce false positives.

lib/bullet/detector · high confidence

Restructured notification classes and added user/URL context

The notification system has been refactored to use a new class hierarchy under the \Bullet::Notification\ namespace (e.g., \Base\, \NPlusOneQuery\, \UnusedEagerLoading\, \CounterCache\), replacing the previous \Notice\ structure. This change introduces user and URL information into all notifications, allowing users to identify which developer triggered the alert and which page or action caused it. The \whoami\ method now safely retrieves the current user, and the \notification\_data\ hash explicitly includes \user\ and \url\ fields, enhancing the context provided in alerts without changing the core detection logic.

lib/bullet/notification · high confidence

Test coverage

Added Mongoid model stubs for testing; Added integration tests for ActiveRecord association and polymorphic N+1 detection; Added integration tests for CounterCache detection; Added integration tests for Mongoid association detection; Added test coverage for Bullet detector components; Added test coverage for Bullet's core components; Added test model fixtures for association testing; Added test suite for Bullet enable/disable and thread-safe pause/resume/skip APIs; Added test support infrastructure for Mongoid and ActiveRecord; Added tests for Bullet extension methods; Added unit tests for Bullet notification classes; Removed Bullet N+1 query detection test suite.

Dependencies

Initial gemspec and Gemfile setup for Bullet

The project introduces its primary dependency manifests: \bullet.gemspec\ and \Gemfile\. The gemspec defines the Bullet gem (version derived from \Bullet::VERSION\), sets a minimum Ruby version of 2.7.0, and declares runtime dependencies on \activesupport\ (\>= 3.0.0) and \uniform\_notifier\ (\~\> 1.11). The Gemfile configures the gem source, includes the gemspec itself, and lists development dependencies including \rails\, \sqlite3\, \rspec\, \guard\, and \coveralls\.

(dependencies) · high confidence

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

This is the PUBLIC form of this artifact. Findings are listed in full, but the details of SECURITY findings — which rule fired, in which file, on which line, and how to fix it — are deliberately withheld, and any secret-scanner results are excluded entirely. Where detail is absent here it was REMOVED FOR PUBLICATION; it is not missing from the analysis. The complete artifact is available from the repository owner.

Score

  • CAI 49 → 73 (+23.2)
  • Rubric changed (rubric-2026.08.15 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 98 → 96 (-2.4)
  • Architecture 96 → 99 (+3.1)
  • Maturity 61 → 60 (-0.6)
  • Readiness 30 → 72 (+41.4)
  • Security 56 → 91 (+35.0)
  • Domain Modelling 100 (new)

Resolved (17)

  • Coverage not measured — test suite did not build
  • Dimension evaluation failed
  • Duplicated block (14 lines × 2) (lib/bullet/active_record4.rb)
  • Duplicated block (22 lines × 2) (lib/bullet/active_record4.rb)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • No exposed public API
  • No tests found
  • Test reliability not included

New (31)

  • (anonymous) (cognitive 17) (lib/bullet/bullet_xhr.js)
  • Ambiguous naming for state checks. enable? likely checks if the gem is globally enabled, while start? likely checks if the current request cycle is active. However, start? is a non-standard name for 'is running' or 'is active', which can be confused with 'is enabled'.
  • Change coupling: association.rb ↔ counter_cache.rb (lib/bullet/detector/association.rb)
  • Duplicated block (110 lines × 5) (lib/bullet/active_record70.rb)
  • Duplicated block (12 lines × 4) (lib/bullet/mongoid4x.rb)
  • Duplicated block (154 lines × 5) (lib/bullet/active_record70.rb)
  • Duplicated block (16 lines × 2) (lib/bullet/mongoid7x.rb)
  • Duplicated block (21 lines × 2) (lib/bullet/notification/n_plus_one_query.rb)
  • Duplicated block (21–23 lines × 5) (lib/bullet/active_record70.rb)
  • Duplicated block (36 lines × 3) (lib/bullet/mongoid4x.rb)
  • Duplicated block (48 lines × 2) (lib/bullet/mongoid7x.rb)
  • Floating git dependency: rails
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • Hotspot: lib/bullet/rack.rb (lib/bullet/rack.rb)
  • Inconsistent state management verbs. pause/resume implies a temporary suspension of activity, while skip implies a one-time bypass for the current context. However, without seeing the implementation, skip might be confused with pause by users expecting a toggle-like behavior. More critically, there is no paused? check that is distinct from start? or enable? in the naming convention, although paused? exists. The inconsistency lies in the mix of lifecycle verbs (pause/resume) and action verbs (skip).
  • Medium: security finding (details withheld)
  • Medium: security finding (details withheld)
  • …and 11 more

Changes since last survey

  • 8 commits — 6 feature/other, 2 fixes

By area

  • (root) — 4 commits
  • (repo) — 3 commits
  • lib/bullet — 1 commit

Notable commits

  • fix: Fix has many through unused eager load false positives
  • fix: Merge pull request #777 from deivid-rodriguez/deivid-rodriguez/fix-has-many-through-false-positive
  • change: Bump version to 8.2.0
  • change: Drop no longer supported mongoid versions
  • change: Make Gemfile.mongoid-8.0 installable
  • change: Merge pull request #779 from deivid-rodriguez/deivid-rodriguez/drop-very-old-rails
  • change: Merge pull request #780 from deivid-rodriguez/deivid-rodriguez/mongoid-compat
  • change: rbx implementation is no longer maintained

Architecture

  • Containers 0 added · 0 removed · contexts 1 added · 0 removed · edges 0 added · 0 removed

Added bounded contexts (1)

  • bullet

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

flyerhzm/bullet was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 26 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit 805fc58df074aa0f7a61c1399c3f0468f2ed2059 — the exact code this score is about.
  • Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-d0929f7ac71f.