flyerhzm/bullet
help to kill N+1 queries and unused eager loading
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 4d ago
- ✓25+ active contributors
- ✓MIT licensed
Show 3 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 59% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/flyerhzm/bullet)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/flyerhzm/bullet on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: flyerhzm/bullet
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/flyerhzm/bullet shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 4d ago
- 25+ active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 59% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live flyerhzm/bullet
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/flyerhzm/bullet.
What it runs against: a local clone of flyerhzm/bullet — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in flyerhzm/bullet | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 34 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of flyerhzm/bullet. If you don't
# have one yet, run these first:
#
# git clone https://github.com/flyerhzm/bullet.git
# cd bullet
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of flyerhzm/bullet and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "flyerhzm/bullet(\\.git)?\\b" \\
&& ok "origin remote is flyerhzm/bullet" \\
|| miss "origin remote is not flyerhzm/bullet (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "lib/bullet.rb" \\
&& ok "lib/bullet.rb" \\
|| miss "missing critical file: lib/bullet.rb"
test -f "lib/bullet/detector/n_plus_one_query.rb" \\
&& ok "lib/bullet/detector/n_plus_one_query.rb" \\
|| miss "missing critical file: lib/bullet/detector/n_plus_one_query.rb"
test -f "lib/bullet/detector/unused_eager_loading.rb" \\
&& ok "lib/bullet/detector/unused_eager_loading.rb" \\
|| miss "missing critical file: lib/bullet/detector/unused_eager_loading.rb"
test -f "lib/bullet/rack.rb" \\
&& ok "lib/bullet/rack.rb" \\
|| miss "missing critical file: lib/bullet/rack.rb"
test -f "lib/bullet/notification_collector.rb" \\
&& ok "lib/bullet/notification_collector.rb" \\
|| miss "missing critical file: lib/bullet/notification_collector.rb"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 34 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~4d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/flyerhzm/bullet"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Bullet is a Ruby gem that detects and alerts developers to N+1 query problems, unused eager loading, and missing counter caches in Rails/Mongoid applications. It hooks into ActiveRecord (4.0+) and Mongoid (4.0+) to monitor query patterns during development and surfaces performance anti-patterns through multiple notification channels (browser console, logger, Sentry, Honeybadger, Bugsnag, etc.). Modular detector architecture: lib/bullet/detector/ contains four specialized detector classes (association.rb, n_plus_one_query.rb, unused_eager_loading.rb, counter_cache.rb) that inherit from base.rb. Version-specific ActiveRecord integration lives in lib/bullet/active_record*.rb files (one per minor version). Core state & notifications managed in lib/bullet.rb, with ext/ containing monkey patches (object.rb) and browser integration (bullet_xhr.js).
👥Who it's for
Rails/Mongoid developers and their teams seeking to optimize database query performance during development. DevOps engineers and QA teams that need performance regression detection in staging environments. The gem is explicitly designed for non-production use (development, staging, or custom profiling environments).
🌱Maturity & risk
Highly mature and production-proven. The project has been actively maintained for 10+ years (original Rails community highlight from 2009), supports Rails 4.0 through 8.1 and Mongoid 4.0 through 9.0 via versioned Gemfiles. Strong CI/CD setup via GitHub Actions (main.yml workflow), comprehensive test suite structure, and active dependency management (Dependabot enabled). Actively developed with recent version targeting Rails 8.1.
Low risk overall, but single-maintainer dependency (flyerhzm). The gem's hook-based approach into ActiveRecord internals means breaking changes in major Rails versions require updates (hence the version-specific Gemfiles in lib/bullet/active_record*.rb, active_record81.rb exists but requires maintenance for Rails 9+). No package.json lock file visible, so Gemfile.lock management is critical.
Active areas of work
The project maintains active support for new Rails/Mongoid versions: Gemfile.rails-8.1 and Gemfile.mongoid-9.0 exist, indicating recent updates. CI via main.yml workflow, automated issue management (close_inactive_issues.yml). No visible PR list in file structure, but Dependabot.yml suggests active dependency tracking. The gem continues passive maintenance mode with focus on compatibility rather than new features.
🚀Get running
git clone https://github.com/flyerhzm/bullet.git
cd bullet
bundle install
bundle exec rspec
For Rails app integration: gem 'bullet', group: 'development' in Gemfile, then bundle exec rails g bullet:install to auto-generate config/environments/development.rb setup.
Daily commands:
Development: bundle exec rspec runs the test suite. For manual testing in a Rails app: config.after_initialize { Bullet.enable = true } in development.rb, then start Rails normally (rails s). Notifications appear in console, browser footer, or configured third-party service.
🗺️Map of the codebase
lib/bullet.rb— Entry point that initializes Bullet configuration, enables/disables the gem, and orchestrates all detection and notification logic.lib/bullet/detector/n_plus_one_query.rb— Core detector that identifies N+1 query patterns by tracking object instantiation against SQL queries, the primary use case for Bullet.lib/bullet/detector/unused_eager_loading.rb— Detects eager-loaded associations that are never accessed, preventing over-optimization and wasted memory.lib/bullet/rack.rb— Rack middleware that integrates Bullet into Rails request/response cycle, handles notifications, and injects JavaScript alerts.lib/bullet/notification_collector.rb— Collects and aggregates all detected query issues during a request, responsible for deduplication and final notification delivery.lib/bullet/registry/association.rb— Maintains the in-memory registry tracking which associations are loaded, unloaded, and instantiated per object for all detection logic.lib/bullet/active_record70.rb— Rails 7.0+ integration hooks that patch ActiveRecord callbacks to track query execution and object instantiation.
🛠️How to make changes
Add Detection for a New Query Anti-Pattern
- Create a new detector class inheriting from Detector::Base in lib/bullet/detector/my_pattern.rb (
lib/bullet/detector/base.rb) - Implement execute method to analyze queries and register issues with NotificationCollector (
lib/bullet/detector/n_plus_one_query.rb) - Create corresponding notification class in lib/bullet/notification/my_pattern.rb (
lib/bullet/notification/n_plus_one_query.rb) - Register the detector in Bullet.detectors in lib/bullet.rb (
lib/bullet.rb) - Write integration tests in spec/integration/ and unit tests in spec/bullet/detector/ (
spec/bullet/detector/n_plus_one_query_spec.rb)
Support a New Rails/ActiveRecord Version
- Create lib/bullet/active_recordXX.rb copying the previous version as template (
lib/bullet/active_record70.rb) - Update ORM hooks (after_find, instantiate callbacks) to match new ActiveRecord internals (
lib/bullet/active_record70.rb) - Add version check in lib/bullet/dependency.rb to load your adapter (
lib/bullet/dependency.rb) - Add new Gemfile variant (Gemfile.rails-X.Y) and test with CI (
Gemfile.rails-7.0)
Customize Notification Output or Delivery Channel
- Extend Bullet::Notification::Base or subclass a specific notification type (
lib/bullet/notification/base.rb) - Override format_body or add new methods to customize message formatting (
lib/bullet/notification/n_plus_one_query.rb) - Modify lib/bullet/rack.rb to call your custom notification handler instead of (or in addition to) built-in handlers (
lib/bullet/rack.rb) - Test with spec/bullet/notification/ and spec/bullet/rack_spec.rb (
spec/bullet/notification/n_plus_one_query_spec.rb)
🔧Why these technologies
- Ruby gem architecture — Bullet integrates as a library into existing Rails/Mongoid projects without requiring external services or infrastructure changes.
- Rack middleware — Allows transparent hook into request/response cycle to monitor queries and inject notifications without application code changes.
- Method patching on ORM callbacks — Enables query and object tracking at the lowest level (ActiveRecord instantiate, Mongoid document creation) across multiple ORM versions.
- In-memory registry with weak references — Tracks objects without keeping them alive longer than they should; allows garbage collection while maintaining query attribution.
⚖️Trade-offs already made
-
Multiple version-specific adapters (active_recordXX.rb, mongoidXx.rb)
- Why: ORM internals change significantly between versions, requiring bespoke hooks.
- Consequence: Maintenance burden: each Rails/Mongoid release requires testing and potential adapter updates.
-
In-memory state only (no persistence)
- Why: Bullet is development-only; persisting would add complexity and overhead.
- Consequence: Issues are lost on process restart; no cross-request trending or analytics.
-
Browser notification via Rack middleware injection
- Why: No external service dependency; works in any Rails app; immediate feedback.
- Consequence: Limited to development browsers; XSS risk if notifications contain user input (mitigated via escaping).
-
Call-stack-based N+1 detection
- Why: Pinpoints the exact line of code triggering the query.
- Consequence: Overhead for stack capture; requires post-processing to filter and beautify.
🚫Non-goals (don't propose these)
- Not a real-time database or cache layer—purely diagnostic.
- Does not execute queries; relies on existing ORM behavior.
- Not compatible with production environments (scope is development only).
- Does not auto-fix queries; provides recommendations and call stacks only.
- Not designed for async/background job monitoring (limited ActiveJob support).
- Does not persist or trend issues across sessions.
🪤Traps & gotchas
Version-specific Gemfiles (Gemfile.rails-, Gemfile.mongoid-) are required for testing; bundle install --gemfile=Gemfile.rails-7.0 must be used for version-specific test runs. The gem monkey-patches ActiveRecord internals, so it breaks silently on unsupported Rails versions (no graceful fallback). Bullet requires explicit enable = true in config; it does nothing by default even if loaded. The .rspec config file must exist for test discovery. Mongoid requires a MongoDB instance running for tests (not obvious from file list).
🏗️Architecture
💡Concepts to learn
- N+1 Query Problem — The core anti-pattern Bullet detects: loading a parent object, then executing one query per child record instead of eager-loading—Bullet's main detection logic in detector/n_plus_one_query.rb exists to catch this
- Eager Loading (SQL JOIN/include/preload) — The fix to N+1 queries; Bullet alerts when eager loading is unused (detector/unused_eager_loading.rb) or insufficient (detector/n_plus_one_query.rb)
- Counter Cache — Database optimization pattern where association counts are cached in a column instead of counting at query time; Bullet has detector/counter_cache.rb to recommend this pattern
- Ruby Monkey Patching & Instrumentation Hooks — Bullet hooks into ActiveRecord internals via version-specific patches (lib/bullet/active_record*.rb) to intercept query execution without modifying user code
- Query Plan Detection via Call Stack Analysis — Bullet tracks which associations are accessed per object by inspecting call stacks and method names; detector/base.rb contains this logic
- Multi-Channel Notification System — Bullet abstracts alerts to multiple backends (Rails logger, Sentry, Honeybadger, browser console) so teams can integrate with existing monitoring—critical for adoption
- Object Identity Tracking & Dependency Graphs — Bullet maintains a dependency.rb mapping of which objects loaded which associations to detect patterns across the request lifecycle; enables unused_eager_loading detection
🔗Related repos
amatsuda/kaminari— Pagination gem frequently used alongside Bullet to optimize queries on paginated results (preventing N+1 on pagination boundaries)hashrocket/rspec-rails-examples— RSpec best practices for Rails testing; Bullet integrations are often tested via RSpec matchers (Bullet uses .rspec config)bkeepers/dotenv— Common companion for configuring Bullet notification credentials (SENTRY_DSN, HONEYBADGER_API_KEY, etc.) in development.rbrack/rack-mini-profiler— Complementary performance profiler often paired with Bullet; rack-mini-profiler shows query timing while Bullet detects query patternspresidentbeef/brakeman— Rails security scanner; Bullet and Brakeman together form a complete code quality pipeline in Rails CI/CD
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for Mongoid 9.0 and Rails 8.0+ integrations
The repo has Gemfiles for Rails 8.0, 8.1 and Mongoid 9.0, but the detector modules (lib/bullet/detector/.rb) likely lack specific tests for these newer versions. Given the complexity of supporting multiple ORM versions (evidenced by lib/bullet/active_record.rb and lib/bullet/mongoid*.rb), adding integration tests that specifically validate N+1 detection and counter cache detection across these latest versions would catch version-specific regressions early.
- [ ] Create spec/bullet/detector/n_plus_one_query_rails8_spec.rb testing N+1 detection with Rails 8.0+ ActiveRecord behavior
- [ ] Create spec/bullet/detector/n_plus_one_query_mongoid9_spec.rb testing N+1 detection with Mongoid 9.0
- [ ] Create spec/bullet/detector/counter_cache_rails8_spec.rb validating counter cache detection with modern Rails
- [ ] Ensure tests run against both Gemfile.rails-8.0 and Gemfile.rails-8.1 in CI pipeline
Refactor version-specific ActiveRecord adapters into a unified strategy pattern
The lib/bullet/ directory contains 9 separate version-specific files (active_record4.rb through active_record81.rb) with likely duplicated logic. This violates DRY principles and makes maintenance difficult. A strategy pattern or adapter registry would reduce code duplication, make version support easier to add/remove, and improve test coverage by centralizing version-specific behavior.
- [ ] Create lib/bullet/adapters/active_record_adapter_strategy.rb defining a common interface for version-specific behavior
- [ ] Create lib/bullet/adapters/active_record_v4_v5_adapter.rb consolidating shared v4-v5 logic
- [ ] Create lib/bullet/adapters/active_record_v6_v7_adapter.rb and lib/bullet/adapters/active_record_v8_adapter.rb for newer versions
- [ ] Update lib/bullet.rb to use adapter registry pattern instead of direct requires
- [ ] Add specs in spec/bullet/adapters/ validating adapter selection and behavior per Rails version
Add detailed notification context to lib/bullet/notification/*.rb for better debugging
The notification system (lib/bullet/notification/base.rb, n_plus_one_query.rb, unused_eager_loading.rb, counter_cache.rb) currently lacks rich context about the source of the issue. Adding query call stack traces, detected at lib/bullet/registry/call_stack.rb, and the actual ORM objects involved would dramatically improve developer experience when investigating Bullet alerts.
- [ ] Enhance lib/bullet/notification/n_plus_one_query.rb to include full association chain (e.g., 'User -> Posts -> Comments') and query count delta
- [ ] Enhance lib/bullet/notification/unused_eager_loading.rb to show the eager-loaded association that wasn't used and suggest removal
- [ ] Add query fingerprint/normalization to help developers group similar N+1 patterns across different endpoints
- [ ] Add spec/bullet/notification/enhanced_context_spec.rb validating notification includes all debugging context needed
🌿Good first issues
- Add integration tests for Rails 8.1 with Mongoid 9.0 in CI—verify the new Gemfile.rails-8.1 and Gemfile.mongoid-9.0 actually pass spec suite (main.yml workflow doesn't visibly test this combination yet)
- Improve documentation in lib/bullet/detector/counter_cache.rb with concrete Rails-to-SQL examples—the file exists but README.md only mentions counter_cache in one sentence
- Add TypeScript types or JSDoc for bullet_xhr.js (lib/bullet/bullet_xhr.js) to clarify the browser console injection API—currently undocumented in README
⭐Top contributors
Click to expand
Top contributors
- @flyerhzm — 59 commits
- @vprigent — 10 commits
- @adiaz04 — 5 commits
- @dependabot[bot] — 3 commits
- @martingjaldbaek — 2 commits
📝Recent commits
Click to expand
Recent commits
8667044— Merge pull request #771 from martingjaldbaek/fix-add-eager-loadings-set-merge (flyerhzm)38cea31— Fix Set#<< corruption in UnusedEagerLoading#add_eager_loadings split branch (martingjaldbaek)8ae6eff— Add failing regression test for add_eager_loadings split branch (martingjaldbaek)4a6d5cf— 🔧 chore(release): bump version to 8.1.1 (flyerhzm)78fa0f4— Merge pull request #769 from PhilippeBo/rails_compatibility (flyerhzm)e758042— Fix ActiveRecord 8.1 patch-level method signature compatibility; test against Rails 8.1.3. (PhilippeBo)ec551da— 🐛 fix: handle string associations in safelist for Action Text (flyerhzm)d01d0ae— Merge pull request #767 from kazuki-hanai/patch-1 (flyerhzm)f5027a6— Update external links in README.md (kazuki-hanai)260791d— Merge pull request #765 from Abdelrhman-Yasser/improve-nplus1-stacktrace (flyerhzm)
🔒Security observations
The Bullet gem project has a moderate security posture. Primary concerns include: (1) Support for multiple outdated Rails and Mongoid versions that no longer receive security updates, (2) potential XSS risks in JavaScript notification display, (3) possible SQL injection risks if query data is imp
- Medium · Multiple Rails/Mongoid Version Gemfiles Without Pinned Dependencies —
Gemfile*, Gemfile.mongoid*, Gemfile.rails-*. The repository contains multiple Gemfile variants for different Rails and Mongoid versions (Gemfile.rails-4.2 through 8.1, Gemfile.mongoid-4.0 through 9.0). Without examining the actual dependency specifications, there is a risk of outdated or vulnerable dependencies being used. Rails versions 4.2, 5.0, 5.1, and older 6.x versions are no longer actively maintained and may contain known security vulnerabilities. Fix: 1) Review and upgrade to actively supported Rails versions (7.0+). 2) Implement dependency pinning with specific versions. 3) Runbundle auditregularly to identify vulnerable gems. 4) Set up automated dependency scanning in CI/CD pipeline (.github/workflows/main.yml). - Medium · Potential XSS Vulnerability in JavaScript Asset —
lib/bullet/bullet_xhr.js. The file 'lib/bullet/bullet_xhr.js' is a JavaScript asset that likely injects HTML into the DOM for displaying Bullet notifications. If not properly sanitized, this could introduce Cross-Site Scripting (XSS) vulnerabilities, especially when displaying query information or stack traces that may contain user-controlled or database-sourced data. Fix: 1) Audit the JavaScript code to ensure all DOM manipulation uses textContent or properly escapes HTML. 2) Avoid using innerHTML with unsanitized data. 3) Implement a Content Security Policy (CSP) header. 4) Use a templating engine with automatic escaping. - Medium · Potential SQL Injection via Query Tracking —
lib/bullet/detector/n_plus_one_query.rb, lib/bullet/detector/association.rb, lib/bullet/notification_collector.rb. The Bullet gem monitors and tracks SQL queries. The detector modules (lib/bullet/detector/*.rb) and notification collectors may process raw SQL query strings. If these are logged, displayed, or used without proper sanitization in notifications/reporting, there could be a risk of exposing or processing malicious SQL patterns. Fix: 1) Ensure all SQL query output is properly escaped before display. 2) Implement strict allowlisting for query patterns if needed. 3) Never log or transmit raw SQL to untrusted outputs. 4) Sanitize all stack traces and query metadata before including in notifications. - Low · Missing Security.md or Security Policy —
Repository root. The repository does not appear to have a SECURITY.md or security policy file visible in the file structure. This makes it difficult for security researchers to report vulnerabilities responsibly. Fix: Create a SECURITY.md file that includes: 1) Instructions for responsible vulnerability disclosure. 2) Security contact information. 3) Supported versions receiving security updates. 4) Process for releasing security patches. - Low · Insufficient Code Review in CI/CD Pipeline —
.github/workflows/main.yml. While the repository has GitHub Actions configured (.github/workflows/), the visible workflow configuration does not indicate security scanning tools like SAST, dependency checking, or code quality analysis are integrated. Fix: 1) Integrate SAST tools (e.g., Brakeman for Rails, Semgrep). 2) Add dependency vulnerability scanning (bundler-audit, Dependabot). 3) Implement code review requirements for PRs. 4) Consider adding container scanning if Docker is used. - Low · Broad File Globbing in Multiple Gemfile Variants —
Gemfile*, Gemfile.rails-*, Gemfile.mongoid-*. The large number of Gemfile variants increases maintenance burden and the risk of inconsistent security patches across different Rails/Mongoid versions. Some older versions may not receive security updates. Fix: 1) Drop support for unmaintained Rails versions (< 6.1). 2) Consolidate Gemfiles using version constraints. 3) Document minimum supported versions clearly. 4) Establish a clear deprecation policy for older version support.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.