Necropsy
Necropsy is a Ruby dead-code detector built around a unified call graph. It collects method definitions with Prism, adds call-edge evidence from static and optional dynamic analyzers, then runs reachability from framework and configured entry points.
The first implementation includes:
- Prism-based method collection for
def,define_method,attr_*, anddelegate - static name resolution, CHA, and RTA-style filtering over instantiated classes
- Rails route/callback/view-helper/component, plain Ruby, and test-suite entry point providers
unreachable,unused, andtest_only_reachableclassifications- confidence levels, JSON/YAML/human/SARIF/GitHub reports, baseline/check guardrails, quarantine suggestions, TracePoint recording, and a bench evaluator
Installation
Add the gem to the development/test group:
gem "necropsy", require: false
Usage
Create a baseline:
bundle exec necropsy baseline --root .
Run a report:
bundle exec necropsy analyze --root . --format human
Fail CI only for new high-confidence findings:
bundle exec necropsy check --root . --fail-on high
Record dynamic evidence from a Ruby script:
bundle exec necropsy record --root . --output tmp/necropsy_trace_point.yml -- script/runner.rb
bundle exec necropsy coverage --root . --output tmp/necropsy_coverage.yml -- script/runner.rb
Record Ruby Coverage while running an external command:
bundle exec necropsy coverage --root . --output tmp/necropsy_coverage.yml -- bundle exec rspec
Child Ruby processes inherit the collector and are merged into the same output for that run.
Evaluate against a gold standard:
bundle exec necropsy bench --root . --gold-standard gold.yml --ablation
Example configuration:
analyzers:
static: [name_resolution, cha, rta]
dynamic:
coverage:
source: tmp/necropsy_coverage.yml
min_observation_days: 30
coverband:
source: redis://prod-redis:6379/2?key=coverband
trace_point:
source: tmp/necropsy_trace_point.yml
custom:
- "MyCompany::GraphqlEntryAnalyzer"
cache:
enabled: true
path: .necropsy_cache/scan.yml
entry_points:
extra:
- "PublicApi::*"
ci:
fail_on: high
baseline: .necropsy_baseline.yml
quarantine:
days: 30
bench:
precision_threshold: 0.85
The scan cache is invalidated when scanned Ruby files or configuration values change.
Dynamic inputs may provide executed or nodes entries with method IDs,
edges with caller_id/callee_id, and an observation hash. SARIF and
GitHub Actions annotations are available via --format sarif and
--format github.
Coverband file, Redis string, and Redis hash exports are supported. Rails route
entry point detection covers common resources, resource, namespace,
scope, controller, concerns, draw, mount, root, and verb route
forms.
necropsy quarantine --write adds # necropsy:quarantine since=YYYY-MM-DD.
When the configured quarantine window expires and no alive evidence appears,
the finding is raised to certain.
Development
After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub.
License
The gem is available as open source under the terms of the MIT License.