heapscope 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +119 -0
- data/CHANGELOG.md +86 -0
- data/CODE_OF_CONDUCT.md +38 -0
- data/CONTRIBUTING.md +72 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +342 -0
- data/Rakefile +49 -0
- data/SECURITY.md +39 -0
- data/assets/heapscope-logo.png +0 -0
- data/assets/logo.svg +24 -0
- data/assets/wordmark.svg +18 -0
- data/docs/README.md +20 -0
- data/docs/ROADMAP.md +29 -0
- data/docs/adr/0001-evidence-over-certainty.md +24 -0
- data/docs/adr/0002-local-only-privacy.md +19 -0
- data/docs/adr/0003-runtime-adapters.md +25 -0
- data/docs/adr/README.md +7 -0
- data/docs/allocators.md +13 -0
- data/docs/api/overview.md +70 -0
- data/docs/changelogs/0.1.0.md +22 -0
- data/docs/changelogs/0.2.0.md +49 -0
- data/docs/changelogs/0.3.0.md +38 -0
- data/docs/changelogs/0.4.0.md +32 -0
- data/docs/changelogs/0.5.0.md +18 -0
- data/docs/changelogs/0.6.0.md +23 -0
- data/docs/cli.md +98 -0
- data/docs/diagnostics/HS001_persistent_class_growth.md +39 -0
- data/docs/diagnostics/HS002_high_retention_ratio.md +24 -0
- data/docs/diagnostics/HS003_thread_local_retention.md +24 -0
- data/docs/diagnostics/HS004_unbounded_collection.md +19 -0
- data/docs/diagnostics/HS005_callback_accumulation.md +14 -0
- data/docs/diagnostics/HS006_closure_retention.md +15 -0
- data/docs/diagnostics/HS007_poor_gc_recovery.md +18 -0
- data/docs/diagnostics/HS008_baseline_regression.md +15 -0
- data/docs/diagnostics/HS009_high_allocation_pressure.md +13 -0
- data/docs/diagnostics/HS010_native_memory_mismatch.md +19 -0
- data/docs/guides/ci-budgets.md +43 -0
- data/docs/guides/first-retention-experiment.md +25 -0
- data/docs/guides/production-safe.md +17 -0
- data/docs/index.md +38 -0
- data/examples/cache_vs_leak.rb +30 -0
- data/examples/closure_capture.rb +20 -0
- data/examples/healthy_churn.rb +16 -0
- data/examples/heapscope.yml +12 -0
- data/examples/import_leak.rb +19 -0
- data/examples/probe_and_session.rb +22 -0
- data/examples/thread_local_leak.rb +31 -0
- data/exe/heapscope +7 -0
- data/heapscope.gemspec +73 -0
- data/lib/heapscope/aging.rb +114 -0
- data/lib/heapscope/analyzer.rb +333 -0
- data/lib/heapscope/baseline.rb +77 -0
- data/lib/heapscope/branding.rb +98 -0
- data/lib/heapscope/budget.rb +108 -0
- data/lib/heapscope/capabilities.rb +42 -0
- data/lib/heapscope/catalog.rb +71 -0
- data/lib/heapscope/cli/color.rb +67 -0
- data/lib/heapscope/cli/commands/capture.rb +289 -0
- data/lib/heapscope/cli/commands/diffing.rb +157 -0
- data/lib/heapscope/cli/commands/meta.rb +244 -0
- data/lib/heapscope/cli/commands/reporting.rb +228 -0
- data/lib/heapscope/cli/completion.rb +72 -0
- data/lib/heapscope/cli/help.rb +226 -0
- data/lib/heapscope/cli/support.rb +126 -0
- data/lib/heapscope/cli.rb +165 -0
- data/lib/heapscope/closures.rb +102 -0
- data/lib/heapscope/collector.rb +167 -0
- data/lib/heapscope/config.rb +196 -0
- data/lib/heapscope/detectors.rb +131 -0
- data/lib/heapscope/diff.rb +130 -0
- data/lib/heapscope/dominators.rb +87 -0
- data/lib/heapscope/errors.rb +13 -0
- data/lib/heapscope/extrapolation.rb +51 -0
- data/lib/heapscope/findings.rb +149 -0
- data/lib/heapscope/globals.rb +108 -0
- data/lib/heapscope/graph.rb +218 -0
- data/lib/heapscope/growth.rb +108 -0
- data/lib/heapscope/middleware.rb +35 -0
- data/lib/heapscope/minitest.rb +47 -0
- data/lib/heapscope/monitor.rb +160 -0
- data/lib/heapscope/noise.rb +48 -0
- data/lib/heapscope/notifications.rb +79 -0
- data/lib/heapscope/pack.rb +55 -0
- data/lib/heapscope/paths.rb +64 -0
- data/lib/heapscope/rails.rb +71 -0
- data/lib/heapscope/report/html.rb +283 -0
- data/lib/heapscope/report/markdown.rb +78 -0
- data/lib/heapscope/report/text.rb +204 -0
- data/lib/heapscope/report.rb +308 -0
- data/lib/heapscope/retention.rb +91 -0
- data/lib/heapscope/rspec.rb +118 -0
- data/lib/heapscope/runtime/base.rb +130 -0
- data/lib/heapscope/runtime/jruby.rb +28 -0
- data/lib/heapscope/runtime/mri.rb +86 -0
- data/lib/heapscope/runtime/truffleruby.rb +40 -0
- data/lib/heapscope/runtime/windows_rss.rb +75 -0
- data/lib/heapscope/runtime.rb +33 -0
- data/lib/heapscope/schema.rb +28 -0
- data/lib/heapscope/scorecard.rb +85 -0
- data/lib/heapscope/session.rb +90 -0
- data/lib/heapscope/sidekiq_middleware.rb +36 -0
- data/lib/heapscope/snapshot.rb +165 -0
- data/lib/heapscope/suggest.rb +99 -0
- data/lib/heapscope/tables.rb +58 -0
- data/lib/heapscope/trend_store.rb +41 -0
- data/lib/heapscope/version.rb +6 -0
- data/lib/heapscope.rb +307 -0
- metadata +211 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rake/testtask"
|
|
5
|
+
|
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
|
7
|
+
t.libs << "test"
|
|
8
|
+
t.libs << "lib"
|
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
10
|
+
t.warning = false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
begin
|
|
14
|
+
require "rubocop/rake_task"
|
|
15
|
+
RuboCop::RakeTask.new
|
|
16
|
+
rescue LoadError
|
|
17
|
+
# rubocop optional until bundle install
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
desc "Run benchmarks"
|
|
21
|
+
task :benchmark do
|
|
22
|
+
ruby "benchmark/run.rb"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc "Run fixture evaluation harness"
|
|
26
|
+
task :eval do
|
|
27
|
+
ruby "benchmark/eval_harness.rb"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
desc "Open HeapScope console"
|
|
31
|
+
task :console do
|
|
32
|
+
exec "ruby", "bin/console"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
desc "Print diagnostic code catalog"
|
|
36
|
+
task :codes do
|
|
37
|
+
require_relative "lib/heapscope"
|
|
38
|
+
puts HeapScope::Catalog.to_text
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
namespace :docs do
|
|
42
|
+
desc "Generate / print diagnostic code catalog for docs"
|
|
43
|
+
task :codes do
|
|
44
|
+
require_relative "lib/heapscope"
|
|
45
|
+
puts HeapScope::Catalog.to_text
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
task default: :test
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Privacy posture
|
|
4
|
+
|
|
5
|
+
HeapScope is a **local** diagnostics toolkit.
|
|
6
|
+
|
|
7
|
+
- No network calls in normal operation
|
|
8
|
+
- No telemetry, analytics, or automatic uploads
|
|
9
|
+
- No serialization of object values by default
|
|
10
|
+
- No dumping of `ENV`, credentials, tokens, cookies, or request bodies by default
|
|
11
|
+
|
|
12
|
+
Memory inspection is inherently sensitive. Treat snapshots and reports as **confidential** if they were captured in environments that handle personal or secret data — even when values are redacted, class names and allocation sites can still leak product structure.
|
|
13
|
+
|
|
14
|
+
## Supported versions
|
|
15
|
+
|
|
16
|
+
| Version | Supported |
|
|
17
|
+
|---------|-----------|
|
|
18
|
+
| 0.6.x | ✅ |
|
|
19
|
+
| 0.5.x | ✅ |
|
|
20
|
+
| 0.4.x | ✅ (security fixes when practical) |
|
|
21
|
+
| < 0.4 | ❌ |
|
|
22
|
+
|
|
23
|
+
## Reporting a vulnerability
|
|
24
|
+
|
|
25
|
+
Please open a GitHub Security Advisory or email the maintainers privately. Do **not** file a public issue that includes exploit details for unreleased flaws.
|
|
26
|
+
|
|
27
|
+
We aim to acknowledge reports within 7 days.
|
|
28
|
+
|
|
29
|
+
## Safe production use
|
|
30
|
+
|
|
31
|
+
Prefer:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
HeapScope.configure do |config|
|
|
35
|
+
config.mode = :production_safe
|
|
36
|
+
end
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Avoid deep heap walks, forced GC, and value inspection on multi-tenant production hosts unless you fully understand the pause and privacy impact.
|
|
Binary file
|
data/assets/logo.svg
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" role="img" aria-label="HeapScope">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" stop-color="#0f766e"/>
|
|
5
|
+
<stop offset="100%" stop-color="#334155"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
<linearGradient id="glass" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
8
|
+
<stop offset="0%" stop-color="#ecfdf5"/>
|
|
9
|
+
<stop offset="100%" stop-color="#99f6e4"/>
|
|
10
|
+
</linearGradient>
|
|
11
|
+
</defs>
|
|
12
|
+
<rect width="256" height="256" rx="48" fill="url(#bg)"/>
|
|
13
|
+
<!-- heap blocks -->
|
|
14
|
+
<rect x="52" y="150" width="36" height="36" rx="4" fill="#5eead4" opacity="0.95"/>
|
|
15
|
+
<rect x="94" y="132" width="36" height="54" rx="4" fill="#99f6e4" opacity="0.95"/>
|
|
16
|
+
<rect x="136" y="114" width="36" height="72" rx="4" fill="#ccfbf1" opacity="0.95"/>
|
|
17
|
+
<rect x="72" y="108" width="28" height="28" rx="3" fill="#2dd4bf" opacity="0.9"/>
|
|
18
|
+
<rect x="108" y="90" width="28" height="28" rx="3" fill="#5eead4" opacity="0.9"/>
|
|
19
|
+
<!-- scope / magnifier -->
|
|
20
|
+
<circle cx="156" cy="96" r="42" fill="none" stroke="url(#glass)" stroke-width="14"/>
|
|
21
|
+
<circle cx="156" cy="96" r="26" fill="none" stroke="#0f766e" stroke-width="4" opacity="0.35"/>
|
|
22
|
+
<line x1="186" y1="126" x2="214" y2="154" stroke="#f8fafc" stroke-width="14" stroke-linecap="round"/>
|
|
23
|
+
<line x1="186" y1="126" x2="214" y2="154" stroke="#99f6e4" stroke-width="6" stroke-linecap="round"/>
|
|
24
|
+
</svg>
|
data/assets/wordmark.svg
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 720 160" role="img" aria-label="HeapScope">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="mark" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" stop-color="#0f766e"/>
|
|
5
|
+
<stop offset="100%" stop-color="#334155"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<g transform="translate(8,16)">
|
|
9
|
+
<rect width="128" height="128" rx="28" fill="url(#mark)"/>
|
|
10
|
+
<rect x="26" y="78" width="18" height="18" rx="2" fill="#5eead4"/>
|
|
11
|
+
<rect x="48" y="68" width="18" height="28" rx="2" fill="#99f6e4"/>
|
|
12
|
+
<rect x="70" y="58" width="18" height="38" rx="2" fill="#ccfbf1"/>
|
|
13
|
+
<circle cx="78" cy="48" r="22" fill="none" stroke="#ecfdf5" stroke-width="8"/>
|
|
14
|
+
<line x1="94" y1="64" x2="110" y2="80" stroke="#ecfdf5" stroke-width="8" stroke-linecap="round"/>
|
|
15
|
+
</g>
|
|
16
|
+
<text x="160" y="98" font-family="IBM Plex Sans, Segoe UI, Helvetica, Arial, sans-serif" font-size="64" font-weight="650" fill="#0f172a" letter-spacing="-1.5">HeapScope</text>
|
|
17
|
+
<text x="164" y="128" font-family="IBM Plex Sans, Segoe UI, Helvetica, Arial, sans-serif" font-size="18" fill="#64748b" letter-spacing="0.5">Ruby retention & heap growth diagnostics</text>
|
|
18
|
+
</svg>
|
data/docs/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="../assets/wordmark.svg" alt="HeapScope" width="360"/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# HeapScope docs
|
|
6
|
+
|
|
7
|
+
Start at [`index.md`](index.md).
|
|
8
|
+
|
|
9
|
+
- [CLI](cli.md)
|
|
10
|
+
- [API](api/overview.md)
|
|
11
|
+
- [Guides](guides/)
|
|
12
|
+
- [Diagnostics](diagnostics/)
|
|
13
|
+
- [Roadmap](ROADMAP.md)
|
|
14
|
+
- [Changelogs](changelogs/)
|
|
15
|
+
|
|
16
|
+
Website: [theworker02.github.io/heapscope](https://theworker02.github.io/heapscope/) · Sponsor: [thanks.dev/u/gh/theworker02](https://thanks.dev/u/gh/theworker02)
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<img src="../assets/logo.svg" alt="" width="48"/>
|
|
20
|
+
</p>
|
data/docs/ROADMAP.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# HeapScope roadmap
|
|
2
|
+
|
|
3
|
+
## Current product (0.6)
|
|
4
|
+
|
|
5
|
+
One coherent retention diagnostics toolkit: snapshots, diffs, multi-cycle experiments,
|
|
6
|
+
ranked findings with next steps, budget presets, slim captures, watch alerts, sessions,
|
|
7
|
+
report packs, and a modular CLI — all local-only.
|
|
8
|
+
|
|
9
|
+
## Shipped history
|
|
10
|
+
|
|
11
|
+
| Version | Theme |
|
|
12
|
+
|---------|--------|
|
|
13
|
+
| 0.1–0.3 | Core toolkit, detectors, aging/closures/dominators |
|
|
14
|
+
| 0.4 | Sessions, scorecards, schema, GitHub polish |
|
|
15
|
+
| 0.5 | Funding, Pages site, pack/suggest, CLI expansion |
|
|
16
|
+
| **0.6** | Product consolidation — presets, ranking, watch, slim JSON, doctor --fix |
|
|
17
|
+
|
|
18
|
+
## Next
|
|
19
|
+
|
|
20
|
+
- Higher-fidelity dominators when runtime APIs allow
|
|
21
|
+
- Packaged GitHub Action for baseline compare
|
|
22
|
+
- Async/fiber-heavy runtime playbooks
|
|
23
|
+
- Optional heap-dump importers
|
|
24
|
+
|
|
25
|
+
## Non-goals
|
|
26
|
+
|
|
27
|
+
- SaaS APM
|
|
28
|
+
- “Confirmed leak” from noisy samples
|
|
29
|
+
- Secret dumping / telemetry
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# ADR 0001 — Evidence over certainty
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
Memory tools often collapse observations into “leak detected,” which trains developers to distrust the tool when false positives appear.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
Every HeapScope finding MUST separate:
|
|
14
|
+
|
|
15
|
+
1. Observed facts
|
|
16
|
+
2. Derived behavior
|
|
17
|
+
3. Hypothesis
|
|
18
|
+
4. Suspected cause (optional, evidence-gated)
|
|
19
|
+
|
|
20
|
+
Prefer severity categories (LOW/MEDIUM/HIGH) over unexplained confidence percentages.
|
|
21
|
+
|
|
22
|
+
## Consequences
|
|
23
|
+
|
|
24
|
+
Reports are longer and more careful. Users get fewer dramatic claims and more actionable investigation steps.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# ADR 0002 — Local-only privacy by default
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
Heap contents may include credentials, PII, and request payloads.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
- No network / telemetry in the gem
|
|
14
|
+
- No object value serialization by default
|
|
15
|
+
- Explicit opt-in + redaction hooks for value inspection
|
|
16
|
+
|
|
17
|
+
## Consequences
|
|
18
|
+
|
|
19
|
+
HeapScope cannot offer hosted dashboards without a separate product decision. Privacy becomes a marketable feature.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# ADR 0003 — Runtime adapters (MRI-first)
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Accepted
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
ObjectSpace APIs differ across MRI, JRuby, and TruffleRuby.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
Expose a capability matrix via adapters:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
HeapScope::Runtime::MRI
|
|
17
|
+
HeapScope::Runtime::JRuby
|
|
18
|
+
HeapScope::Runtime::TruffleRuby
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Never pretend unavailable features exist.
|
|
22
|
+
|
|
23
|
+
## Consequences
|
|
24
|
+
|
|
25
|
+
Slightly more code, much safer degradation, and a clear extension point for future engines.
|
data/docs/adr/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Architecture Decision Record index
|
|
2
|
+
|
|
3
|
+
| ADR | Title |
|
|
4
|
+
|-----|-------|
|
|
5
|
+
| [0001](0001-evidence-over-certainty.md) | Evidence over certainty |
|
|
6
|
+
| [0002](0002-local-only-privacy.md) | Local-only privacy by default |
|
|
7
|
+
| [0003](0003-runtime-adapters.md) | Runtime adapters for MRI-first design |
|
data/docs/allocators.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Allocator awareness
|
|
2
|
+
|
|
3
|
+
HeapScope reports Ruby heap and RSS separately on purpose.
|
|
4
|
+
|
|
5
|
+
| Allocator | Notes |
|
|
6
|
+
|-----------|--------|
|
|
7
|
+
| glibc malloc | Can retain free arenas; RSS may not fall after Ruby GC |
|
|
8
|
+
| jemalloc | Often smoother; still not equal to Ruby heap size |
|
|
9
|
+
| macOS allocator | Zone behavior can obscure release timing |
|
|
10
|
+
|
|
11
|
+
Fragmentation indicators (RSS vs heap pages vs live/free slots) are reported **conservatively** as potential fragmentation — never "confirmed fragmentation."
|
|
12
|
+
|
|
13
|
+
Copy-on-write after fork (Puma workers, prefork) can also change RSS without new Ruby object retention.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# API overview
|
|
2
|
+
|
|
3
|
+
Public entry points (see also the README and [`docs/index.md`](../index.md)):
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
HeapScope.snapshot
|
|
7
|
+
HeapScope.compare(before, after)
|
|
8
|
+
HeapScope.measure(...) { }
|
|
9
|
+
HeapScope.retention_test(...) { }
|
|
10
|
+
HeapScope.experiment(...) { }
|
|
11
|
+
HeapScope.repeat(n) { }
|
|
12
|
+
HeapScope.probe(title: "…") { } # scorecard + report
|
|
13
|
+
HeapScope.session("name") # .heapscope/sessions persistence
|
|
14
|
+
HeapScope.scorecard(report)
|
|
15
|
+
HeapScope.check_budget(budget:) { }
|
|
16
|
+
HeapScope.check(budget:) { } # raises BudgetExceededError
|
|
17
|
+
HeapScope.capabilities
|
|
18
|
+
HeapScope.doctor
|
|
19
|
+
HeapScope.overhead(mode: :lightweight)
|
|
20
|
+
HeapScope.codes
|
|
21
|
+
HeapScope.about
|
|
22
|
+
HeapScope.branding
|
|
23
|
+
HeapScope.suggest_ignores(report)
|
|
24
|
+
HeapScope.next_steps(report)
|
|
25
|
+
HeapScope.budget_preset(:ci_strict)
|
|
26
|
+
HeapScope.pack(report, "./out")
|
|
27
|
+
HeapScope.write_config!("heapscope.yml")
|
|
28
|
+
HeapScope.load_config!("heapscope.yml")
|
|
29
|
+
HeapScope.configure { |c| }
|
|
30
|
+
HeapScope.ignore_class(MyCache)
|
|
31
|
+
HeapScope.after_warmup { }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Key types:
|
|
35
|
+
|
|
36
|
+
| Class / module | Role |
|
|
37
|
+
|----------------|------|
|
|
38
|
+
| `Snapshot` | Point-in-time heap summary (`save(slim: true)`) |
|
|
39
|
+
| `Diff` | Before/after comparison (+ `to_table`) |
|
|
40
|
+
| `Report` | Findings + presentation (+ `scorecard`, `table`, `next_steps`) |
|
|
41
|
+
| `Scorecard` / `Probe` | Executive verdict / one-shot measure |
|
|
42
|
+
| `Session` | Named artifact folders |
|
|
43
|
+
| `Finding` / `Findings` | Evidence-structured diagnostic + ranking |
|
|
44
|
+
| `Budget` | CI gates + presets |
|
|
45
|
+
| `Suggest` | Next steps + ignore hints |
|
|
46
|
+
| `Monitor` | Sampling + optional anomaly alerts |
|
|
47
|
+
| `Branding` | URLs, banners, asset paths |
|
|
48
|
+
| `Budget` | CI thresholds |
|
|
49
|
+
| `Monitor` | Interval sampler |
|
|
50
|
+
| `TrendStore` | Historical samples |
|
|
51
|
+
| `RetentionSession` | Multi-cycle tracker |
|
|
52
|
+
| `Graph` | Bounded reachability |
|
|
53
|
+
| `Detectors` | Thread-local / collection classifiers |
|
|
54
|
+
| `Schema` | Report JSON validation |
|
|
55
|
+
| `Catalog` | HS001–HS010 catalog |
|
|
56
|
+
| `Branding` | Banner, funding, footers |
|
|
57
|
+
| `Suggest` | Ignore-pattern recommendations |
|
|
58
|
+
| `Pack` | Local report export bundles |
|
|
59
|
+
| `Tables` | ASCII / Markdown tables |
|
|
60
|
+
|
|
61
|
+
Optional requires:
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
require "heapscope/cli"
|
|
65
|
+
require "heapscope/middleware"
|
|
66
|
+
require "heapscope/rails"
|
|
67
|
+
require "heapscope/sidekiq_middleware"
|
|
68
|
+
require "heapscope/rspec"
|
|
69
|
+
require "heapscope/minitest"
|
|
70
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# HeapScope 0.1.0
|
|
2
|
+
|
|
3
|
+
**Release date:** 2026-08-12
|
|
4
|
+
**Theme:** First useful retention toolkit
|
|
5
|
+
|
|
6
|
+
## Why 0.1.0 exists
|
|
7
|
+
|
|
8
|
+
`top` and RSS charts tell you memory moved. HeapScope 0.1.0 tells you **which object populations moved**, whether they **survived GC**, and whether that looks like **churn or sticky retention** — without pretending to have a SaaS backend or magical leak certainty.
|
|
9
|
+
|
|
10
|
+
## Shipped
|
|
11
|
+
|
|
12
|
+
- Snapshots + diffs + measure + retention sessions
|
|
13
|
+
- Findings HS001–HS010 with evidence structure
|
|
14
|
+
- CLI + JSON/text/HTML reports
|
|
15
|
+
- Optional Rails/Sidekiq/RSpec/Minitest surfaces
|
|
16
|
+
- MRI-first runtime adapters with safe degradation
|
|
17
|
+
|
|
18
|
+
## Honest limits
|
|
19
|
+
|
|
20
|
+
- Deep reachability is bounded and approximate
|
|
21
|
+
- Remote process attach is not implemented
|
|
22
|
+
- Retained-size dominators are deferred to later milestones
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# HeapScope 0.2.0
|
|
2
|
+
|
|
3
|
+
**Release date:** 2026-08-12
|
|
4
|
+
**Theme:** Milestone 2 foundations — detectors, branding, documentation depth
|
|
5
|
+
|
|
6
|
+
## Highlights
|
|
7
|
+
|
|
8
|
+
HeapScope 0.2 turns the Milestone 1 toolkit into something you can show a team:
|
|
9
|
+
|
|
10
|
+
- Recognizable brand (logo + wordmark)
|
|
11
|
+
- A long, badge-rich README that documents real workflows
|
|
12
|
+
- Detectors that separate **cache plateaus** from **unbounded collections**
|
|
13
|
+
- Thread-local retention findings for Puma/Sidekiq-style thread reuse
|
|
14
|
+
- HTML reports that look like a product, not a debug dump
|
|
15
|
+
|
|
16
|
+
## Detectors
|
|
17
|
+
|
|
18
|
+
`HeapScope::Detectors` adds structured analysis on top of raw class series:
|
|
19
|
+
|
|
20
|
+
| Signal | Outcome |
|
|
21
|
+
|--------|---------|
|
|
22
|
+
| Thread keys with large/shallow suspicious names | HS003 |
|
|
23
|
+
| Monotonic Array/Hash/registry growth, no shrink | HS004 |
|
|
24
|
+
| Plateau after growth | Likely cache (low severity) |
|
|
25
|
+
|
|
26
|
+
## Documentation
|
|
27
|
+
|
|
28
|
+
- Expanded README (TOC, compatibility matrix, privacy, architecture)
|
|
29
|
+
- `SECURITY.md`, `CODE_OF_CONDUCT.md`
|
|
30
|
+
- Guides under `docs/guides/`
|
|
31
|
+
- This release note
|
|
32
|
+
|
|
33
|
+
## Upgrade notes
|
|
34
|
+
|
|
35
|
+
From 0.1.x:
|
|
36
|
+
|
|
37
|
+
```ruby
|
|
38
|
+
gem "heapscope", "~> 0.2"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
API remains compatible. New fields may appear on retention reports (`collections`, `thread_locals`).
|
|
42
|
+
|
|
43
|
+
## Verification
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
bundle exec rake test
|
|
47
|
+
bundle exec rubocop
|
|
48
|
+
gem build heapscope.gemspec
|
|
49
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# HeapScope 0.3.0
|
|
2
|
+
|
|
3
|
+
**Release date:** 2026-08-12
|
|
4
|
+
**Theme:** Fill every gap — aging, globals, closures, fibers, dominators, trends, doctor
|
|
5
|
+
|
|
6
|
+
## Why 0.3.0 is “crazy complete”
|
|
7
|
+
|
|
8
|
+
0.1 shipped the retention toolkit.
|
|
9
|
+
0.2 made it a product.
|
|
10
|
+
**0.3 fills the original blueprint gaps** so HeapScope feels like a full diagnostics system:
|
|
11
|
+
|
|
12
|
+
| Area | Added |
|
|
13
|
+
|------|-------|
|
|
14
|
+
| Aging | Coarse young/middle/long-lived buckets from multi-cycle survival |
|
|
15
|
+
| Globals | Global/constant registry inventory + growth findings |
|
|
16
|
+
| Closures | Opt-in Proc retained-size hypotheses (HS006) |
|
|
17
|
+
| Fibers | Fiber storage inventory |
|
|
18
|
+
| Dominators | Approximate top retainers from thread-locals |
|
|
19
|
+
| Fragmentation | Conservative RSS/heap ratio indicator |
|
|
20
|
+
| Noise | Framework noise defaults (Zeitwerk/Bootsnap/…) |
|
|
21
|
+
| Config | YAML loader (`heapscope.yml`) |
|
|
22
|
+
| Notifications | Optional AS::Notifications growth probe |
|
|
23
|
+
| Paths | Tree formatter for retention paths |
|
|
24
|
+
| Reproduction | Commands embedded in reports |
|
|
25
|
+
| Overhead | Self-profiling API + CLI |
|
|
26
|
+
| Doctor | Runtime/capability health CLI |
|
|
27
|
+
| Trends | `TrendStore` + `heapscope trends` |
|
|
28
|
+
| Reports | Markdown export |
|
|
29
|
+
| Matchers | Richer RSpec/Minitest helpers |
|
|
30
|
+
| Rails | `measure_action`, AR population helper |
|
|
31
|
+
|
|
32
|
+
## Upgrade
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
gem "heapscope", "~> 0.3"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Closure detection remains **off by default** (`detect_closures: false`) because Proc walks are expensive.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# HeapScope 0.4.0
|
|
2
|
+
|
|
3
|
+
**Release date:** 2026-08-13
|
|
4
|
+
**Theme:** Professional DX — sessions, scorecards, schema, GitHub polish
|
|
5
|
+
|
|
6
|
+
## Highlights
|
|
7
|
+
|
|
8
|
+
HeapScope 0.4 makes the project feel like a maintained open-source product:
|
|
9
|
+
|
|
10
|
+
### Product features
|
|
11
|
+
|
|
12
|
+
- **`HeapScope.probe`** — one-shot workload probe with executive scorecard
|
|
13
|
+
- **`HeapScope.session`** — named `.heapscope/sessions` artifact folders (JSON + HTML)
|
|
14
|
+
- **`Scorecard`** — compact CI/console verdict card
|
|
15
|
+
- **`Tables`** — ASCII/Markdown class-growth tables
|
|
16
|
+
- **`Schema`** — report JSON validation (`heapscope validate`)
|
|
17
|
+
- **`Catalog`** — `heapscope codes` diagnostic encyclopedia dump
|
|
18
|
+
- CLI: `sessions`, `history`, `validate`, `codes`
|
|
19
|
+
- `bin/console` + Rake `:console`, `:codes`, `:eval`
|
|
20
|
+
|
|
21
|
+
### Professional repo surface
|
|
22
|
+
|
|
23
|
+
- Issue / PR templates, Dependabot
|
|
24
|
+
- Docs hub (`docs/index.md`) + CLI reference
|
|
25
|
+
- Gem post-install message
|
|
26
|
+
- Expanded changelog / roadmap
|
|
27
|
+
|
|
28
|
+
## Upgrade
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
gem "heapscope", "~> 0.4"
|
|
32
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# HeapScope 0.5.0
|
|
2
|
+
|
|
3
|
+
Funding, Pages site, and packaging polish.
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
- **FUNDING.yml** — GitHub Sponsors + thanks.dev at `u/gh/theworker02`
|
|
8
|
+
- **GitHub Pages** — branded landing site at `site/` deployed via Actions
|
|
9
|
+
- **`heapscope about` / `HeapScope.about`** — docs + sponsor links
|
|
10
|
+
- **`heapscope suggest`** — ignore-pattern recommendations (manual review only)
|
|
11
|
+
- **`heapscope pack`** — offline JSON + HTML + Markdown report bundles
|
|
12
|
+
- Report footers and doctor output link to thanks.dev and the docs site
|
|
13
|
+
|
|
14
|
+
## Enable GitHub Pages
|
|
15
|
+
|
|
16
|
+
1. Push to `main` (or `master`)
|
|
17
|
+
2. Repo **Settings → Pages → Source: GitHub Actions**
|
|
18
|
+
3. Site URL: `https://theworker02.github.io/heapscope/`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# HeapScope 0.6.0 — Professional product release
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-08-13 · **Owner:** [@theworker02](https://github.com/theworker02)
|
|
4
|
+
|
|
5
|
+
0.6 folds the 0.4–0.5 DX work into one coherent product narrative: ranked findings,
|
|
6
|
+
actionable next steps, CI budget presets, slim snapshots, smarter watch/monitor alerts,
|
|
7
|
+
and a doctor that can write a local starter config — without stacking parallel “v2” APIs.
|
|
8
|
+
|
|
9
|
+
## Highlights
|
|
10
|
+
|
|
11
|
+
- **Budget presets** — `rails_request`, `sidekiq_job`, `ci_strict` via `Budget.preset` / `HeapScope.budget_preset`
|
|
12
|
+
- **Finding ranking & dedupe** — `Findings.rank_and_dedupe` applied in the analyzer and retention reports
|
|
13
|
+
- **Next-steps engine** — `Suggest.next_steps` / `HeapScope.next_steps` surfaces prioritized follow-ups in text, Markdown, HTML, and CLI `suggest`
|
|
14
|
+
- **`heapscope watch`** — monitor alias with anomaly alerts on RSS / live-slot spikes
|
|
15
|
+
- **Slim JSON snapshots** — `snapshot.save(..., slim: true)` / `heapscope snapshot --slim`
|
|
16
|
+
- **`heapscope doctor --fix`** — writes a starter `heapscope.yml` (local only)
|
|
17
|
+
- **Ownership cleanup** — `Probe`/`Scorecard` in `scorecard.rb`; `ConfigLoader` in `config.rb`; framework noise hints owned by `Noise`
|
|
18
|
+
|
|
19
|
+
## Links
|
|
20
|
+
|
|
21
|
+
- Gem: [rubygems.org/gems/heapscope](https://rubygems.org/gems/heapscope)
|
|
22
|
+
- Docs: [theworker02.github.io/heapscope](https://theworker02.github.io/heapscope/)
|
|
23
|
+
- Sponsor: [thanks.dev/u/gh/theworker02](https://thanks.dev/u/gh/theworker02)
|
data/docs/cli.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="../assets/wordmark.svg" alt="HeapScope" width="360"/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# CLI reference
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
heapscope [global options] <command> [options]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Global options
|
|
12
|
+
|
|
13
|
+
| Flag | Description |
|
|
14
|
+
|------|-------------|
|
|
15
|
+
| `--verbose` | Verbose HeapScope logging |
|
|
16
|
+
| `--quiet` | Suppress non-essential output |
|
|
17
|
+
| `--config PATH` | Load YAML/Ruby config before the command |
|
|
18
|
+
| `--json` | Prefer machine-readable JSON on key commands |
|
|
19
|
+
| `--no-color` / `--color` | Disable or force ANSI colors (also respects `NO_COLOR`) |
|
|
20
|
+
| `-h`, `--help` | Show help |
|
|
21
|
+
| `-v`, `--version` | Print version |
|
|
22
|
+
|
|
23
|
+
Per-command help: `heapscope help <command>` or `heapscope <command> --help`.
|
|
24
|
+
|
|
25
|
+
## Commands
|
|
26
|
+
|
|
27
|
+
| Command | Description |
|
|
28
|
+
|---------|-------------|
|
|
29
|
+
| `snapshot` | Capture heap snapshot JSON (`--slim` for compact) |
|
|
30
|
+
| `inspect` | Inspect current process or saved capture |
|
|
31
|
+
| `diff` | Diff two snapshots (scorecard + table + report) |
|
|
32
|
+
| `monitor` | Interval sampling (`--alert` for spikes) |
|
|
33
|
+
| `watch` | Monitor with anomaly alerts enabled |
|
|
34
|
+
| `trends` | Print monitor timeline |
|
|
35
|
+
| `report` | Render text / html / markdown / json |
|
|
36
|
+
| `baseline` | Create baseline from report |
|
|
37
|
+
| `compare` | Baseline vs current (CI exit codes) |
|
|
38
|
+
| `sessions` | List `.heapscope/sessions` |
|
|
39
|
+
| `history` | Recent session artifacts |
|
|
40
|
+
| `validate` | Validate report schema |
|
|
41
|
+
| `suggest` / `ignore-suggest` | Next steps + ignore_patterns (never auto-applied) |
|
|
42
|
+
| `pack` / `export` | Export local JSON+HTML+Markdown bundle |
|
|
43
|
+
| `probe` | Measure a `--file` / `--eval` workload → scorecard |
|
|
44
|
+
| `measure` | CLI wrapper around `HeapScope.measure` |
|
|
45
|
+
| `retention` | CLI wrapper around `HeapScope.retention_test` |
|
|
46
|
+
| `findings` | List/filter ranked findings |
|
|
47
|
+
| `scorecard` | Print scorecard only from a report |
|
|
48
|
+
| `table` | Print growth table from a report |
|
|
49
|
+
| `explain` | Diagnostic encyclopedia entry |
|
|
50
|
+
| `open` / `html` | Write HTML and print path |
|
|
51
|
+
| `self-test` | Built-in intentional retention demo |
|
|
52
|
+
| `env` | Print relevant environment variables |
|
|
53
|
+
| `completion` | Generate bash / zsh / powershell completion |
|
|
54
|
+
| `man` | Extended about + examples |
|
|
55
|
+
| `codes` | Print HS001–HS010 catalog |
|
|
56
|
+
| `doctor` | Runtime + config health (`--fix` writes starter YAML) |
|
|
57
|
+
| `overhead` | Snapshot overhead microbench |
|
|
58
|
+
| `config` | Load YAML/Ruby config |
|
|
59
|
+
| `about` | Branding, docs, and funding links |
|
|
60
|
+
| `capabilities` | Capability matrix |
|
|
61
|
+
| `version` | Print version |
|
|
62
|
+
| `help` | Global or per-command help |
|
|
63
|
+
|
|
64
|
+
## Exit codes
|
|
65
|
+
|
|
66
|
+
| Code | Meaning |
|
|
67
|
+
|------|---------|
|
|
68
|
+
| 0 | Success |
|
|
69
|
+
| 1 | Regression / finding above threshold (`--fail-on-*`) |
|
|
70
|
+
| 2 | Invalid input / configuration |
|
|
71
|
+
| 3 | Capability unavailable |
|
|
72
|
+
|
|
73
|
+
## Notable flags
|
|
74
|
+
|
|
75
|
+
- `snapshot`: `--slim`, `--mode`, `--force-gc`, `--track-allocations`
|
|
76
|
+
- `monitor` / `watch`: `--alert`, `--rss-alert-bytes`, `--live-alert-slots`
|
|
77
|
+
- `doctor`: `--fix`, `--config-out PATH`, `--force`
|
|
78
|
+
- `suggest`: `--json` (next_steps + ignore_patterns), `--ignores-only`
|
|
79
|
+
- Analysis commands: `--fail-on-high`, `--fail-on-medium`, `--fail-on LEVEL`
|
|
80
|
+
|
|
81
|
+
## Examples
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
heapscope about
|
|
85
|
+
heapscope doctor --fix
|
|
86
|
+
heapscope snapshot --slim -o before.json
|
|
87
|
+
heapscope diff before.json after.json --html out.html --fail-on-medium
|
|
88
|
+
heapscope watch --duration 120 -o watch.json
|
|
89
|
+
heapscope suggest report.json
|
|
90
|
+
heapscope pack report.json -o ./pack
|
|
91
|
+
heapscope explain HS001
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Sponsor: https://thanks.dev/u/gh/theworker02 · Site: https://theworker02.github.io/heapscope/
|
|
95
|
+
|
|
96
|
+
<p align="center">
|
|
97
|
+
<img src="../assets/logo.svg" alt="" width="48"/>
|
|
98
|
+
</p>
|