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.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +119 -0
  3. data/CHANGELOG.md +86 -0
  4. data/CODE_OF_CONDUCT.md +38 -0
  5. data/CONTRIBUTING.md +72 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +21 -0
  8. data/README.md +342 -0
  9. data/Rakefile +49 -0
  10. data/SECURITY.md +39 -0
  11. data/assets/heapscope-logo.png +0 -0
  12. data/assets/logo.svg +24 -0
  13. data/assets/wordmark.svg +18 -0
  14. data/docs/README.md +20 -0
  15. data/docs/ROADMAP.md +29 -0
  16. data/docs/adr/0001-evidence-over-certainty.md +24 -0
  17. data/docs/adr/0002-local-only-privacy.md +19 -0
  18. data/docs/adr/0003-runtime-adapters.md +25 -0
  19. data/docs/adr/README.md +7 -0
  20. data/docs/allocators.md +13 -0
  21. data/docs/api/overview.md +70 -0
  22. data/docs/changelogs/0.1.0.md +22 -0
  23. data/docs/changelogs/0.2.0.md +49 -0
  24. data/docs/changelogs/0.3.0.md +38 -0
  25. data/docs/changelogs/0.4.0.md +32 -0
  26. data/docs/changelogs/0.5.0.md +18 -0
  27. data/docs/changelogs/0.6.0.md +23 -0
  28. data/docs/cli.md +98 -0
  29. data/docs/diagnostics/HS001_persistent_class_growth.md +39 -0
  30. data/docs/diagnostics/HS002_high_retention_ratio.md +24 -0
  31. data/docs/diagnostics/HS003_thread_local_retention.md +24 -0
  32. data/docs/diagnostics/HS004_unbounded_collection.md +19 -0
  33. data/docs/diagnostics/HS005_callback_accumulation.md +14 -0
  34. data/docs/diagnostics/HS006_closure_retention.md +15 -0
  35. data/docs/diagnostics/HS007_poor_gc_recovery.md +18 -0
  36. data/docs/diagnostics/HS008_baseline_regression.md +15 -0
  37. data/docs/diagnostics/HS009_high_allocation_pressure.md +13 -0
  38. data/docs/diagnostics/HS010_native_memory_mismatch.md +19 -0
  39. data/docs/guides/ci-budgets.md +43 -0
  40. data/docs/guides/first-retention-experiment.md +25 -0
  41. data/docs/guides/production-safe.md +17 -0
  42. data/docs/index.md +38 -0
  43. data/examples/cache_vs_leak.rb +30 -0
  44. data/examples/closure_capture.rb +20 -0
  45. data/examples/healthy_churn.rb +16 -0
  46. data/examples/heapscope.yml +12 -0
  47. data/examples/import_leak.rb +19 -0
  48. data/examples/probe_and_session.rb +22 -0
  49. data/examples/thread_local_leak.rb +31 -0
  50. data/exe/heapscope +7 -0
  51. data/heapscope.gemspec +73 -0
  52. data/lib/heapscope/aging.rb +114 -0
  53. data/lib/heapscope/analyzer.rb +333 -0
  54. data/lib/heapscope/baseline.rb +77 -0
  55. data/lib/heapscope/branding.rb +98 -0
  56. data/lib/heapscope/budget.rb +108 -0
  57. data/lib/heapscope/capabilities.rb +42 -0
  58. data/lib/heapscope/catalog.rb +71 -0
  59. data/lib/heapscope/cli/color.rb +67 -0
  60. data/lib/heapscope/cli/commands/capture.rb +289 -0
  61. data/lib/heapscope/cli/commands/diffing.rb +157 -0
  62. data/lib/heapscope/cli/commands/meta.rb +244 -0
  63. data/lib/heapscope/cli/commands/reporting.rb +228 -0
  64. data/lib/heapscope/cli/completion.rb +72 -0
  65. data/lib/heapscope/cli/help.rb +226 -0
  66. data/lib/heapscope/cli/support.rb +126 -0
  67. data/lib/heapscope/cli.rb +165 -0
  68. data/lib/heapscope/closures.rb +102 -0
  69. data/lib/heapscope/collector.rb +167 -0
  70. data/lib/heapscope/config.rb +196 -0
  71. data/lib/heapscope/detectors.rb +131 -0
  72. data/lib/heapscope/diff.rb +130 -0
  73. data/lib/heapscope/dominators.rb +87 -0
  74. data/lib/heapscope/errors.rb +13 -0
  75. data/lib/heapscope/extrapolation.rb +51 -0
  76. data/lib/heapscope/findings.rb +149 -0
  77. data/lib/heapscope/globals.rb +108 -0
  78. data/lib/heapscope/graph.rb +218 -0
  79. data/lib/heapscope/growth.rb +108 -0
  80. data/lib/heapscope/middleware.rb +35 -0
  81. data/lib/heapscope/minitest.rb +47 -0
  82. data/lib/heapscope/monitor.rb +160 -0
  83. data/lib/heapscope/noise.rb +48 -0
  84. data/lib/heapscope/notifications.rb +79 -0
  85. data/lib/heapscope/pack.rb +55 -0
  86. data/lib/heapscope/paths.rb +64 -0
  87. data/lib/heapscope/rails.rb +71 -0
  88. data/lib/heapscope/report/html.rb +283 -0
  89. data/lib/heapscope/report/markdown.rb +78 -0
  90. data/lib/heapscope/report/text.rb +204 -0
  91. data/lib/heapscope/report.rb +308 -0
  92. data/lib/heapscope/retention.rb +91 -0
  93. data/lib/heapscope/rspec.rb +118 -0
  94. data/lib/heapscope/runtime/base.rb +130 -0
  95. data/lib/heapscope/runtime/jruby.rb +28 -0
  96. data/lib/heapscope/runtime/mri.rb +86 -0
  97. data/lib/heapscope/runtime/truffleruby.rb +40 -0
  98. data/lib/heapscope/runtime/windows_rss.rb +75 -0
  99. data/lib/heapscope/runtime.rb +33 -0
  100. data/lib/heapscope/schema.rb +28 -0
  101. data/lib/heapscope/scorecard.rb +85 -0
  102. data/lib/heapscope/session.rb +90 -0
  103. data/lib/heapscope/sidekiq_middleware.rb +36 -0
  104. data/lib/heapscope/snapshot.rb +165 -0
  105. data/lib/heapscope/suggest.rb +99 -0
  106. data/lib/heapscope/tables.rb +58 -0
  107. data/lib/heapscope/trend_store.rb +41 -0
  108. data/lib/heapscope/version.rb +6 -0
  109. data/lib/heapscope.rb +307 -0
  110. metadata +211 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f1ac0f631627ce36c708e8a675265170999f9692b5a3d1c883941c01338a814c
4
+ data.tar.gz: ccf46c30e092d097872925d3a5cfcf124f2a8dd4d252beaf7f5666f9d48d38d1
5
+ SHA512:
6
+ metadata.gz: 22906c262dd5681cde4b144388818220aa991084679fd709186720e7c50cb4455bb0f7a51a51044b37cc4cb91392364bf55dd9857ad613fe3c96e2f482e9bcc8
7
+ data.tar.gz: 246a6b67bb0d24839ac72320e458e2955a01d5452da4aca8b1a0f41aa43d7592d2082cd0546f38e371af5b63ec4204efd6f9ae50d4f9e3f277792483fd1ce63d
data/.rubocop.yml ADDED
@@ -0,0 +1,119 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.1
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+ Exclude:
6
+ - "vendor/**/*"
7
+ - "examples/**/*"
8
+ - "benchmark/**/*"
9
+ - "*.gemspec"
10
+
11
+ Style/StringLiterals:
12
+ EnforcedStyle: double_quotes
13
+
14
+ Style/Documentation:
15
+ Enabled: false
16
+
17
+ Style/MutableConstant:
18
+ Enabled: false
19
+
20
+ Naming/MethodParameterName:
21
+ Enabled: false
22
+
23
+ Metrics/MethodLength:
24
+ Max: 100
25
+ Exclude:
26
+ - "lib/heapscope/report/html.rb"
27
+ - "lib/heapscope/report/text.rb"
28
+
29
+ Metrics/ClassLength:
30
+ Max: 400
31
+
32
+ Metrics/ModuleLength:
33
+ Max: 400
34
+
35
+ Metrics/AbcSize:
36
+ Max: 250
37
+ Exclude:
38
+ - "lib/heapscope/report/text.rb"
39
+
40
+ Metrics/CyclomaticComplexity:
41
+ Max: 45
42
+ Exclude:
43
+ - "lib/heapscope/report/text.rb"
44
+
45
+ Metrics/PerceivedComplexity:
46
+ Max: 45
47
+ Exclude:
48
+ - "lib/heapscope/report/text.rb"
49
+
50
+ Metrics/ParameterLists:
51
+ Max: 15
52
+
53
+ Metrics/BlockLength:
54
+ Max: 40
55
+ Exclude:
56
+ - "heapscope.gemspec"
57
+ - "test/**/*"
58
+ - "Rakefile"
59
+
60
+ Metrics/BlockNesting:
61
+ Max: 4
62
+
63
+ Layout/LineLength:
64
+ Max: 180
65
+
66
+ Style/StringLiteralsInInterpolation:
67
+ Enabled: false
68
+
69
+ Style/EmptyStringInsideInterpolation:
70
+ Enabled: false
71
+
72
+ Lint/ShadowedException:
73
+ Enabled: false
74
+
75
+ Lint/NoReturnInBeginEndBlocks:
76
+ Enabled: false
77
+
78
+ Layout/EmptyLinesAfterModuleInclusion:
79
+ Enabled: false
80
+
81
+ Lint/AmbiguousBlockAssociation:
82
+ Enabled: false
83
+
84
+ Lint/DuplicateBranch:
85
+ Enabled: false
86
+
87
+ Lint/UselessConstantScoping:
88
+ Enabled: false
89
+
90
+ Style/NumericPredicate:
91
+ Enabled: false
92
+
93
+ Style/BlockDelimiters:
94
+ Enabled: false
95
+
96
+ Style/MultipleComparison:
97
+ Enabled: false
98
+
99
+ Style/FormatStringToken:
100
+ Enabled: false
101
+
102
+ Style/MultilineBlockChain:
103
+ Enabled: false
104
+
105
+ Style/SafeNavigationChainLength:
106
+ Enabled: false
107
+
108
+ Naming/PredicateMethod:
109
+ Enabled: false
110
+
111
+ Lint/AmbiguousOperatorPrecedence:
112
+ Enabled: false
113
+
114
+ Lint/UnusedMethodArgument:
115
+ AllowUnusedKeywordArguments: true
116
+ IgnoreEmptyMethods: true
117
+
118
+ Style/OptionalBooleanParameter:
119
+ Enabled: false
data/CHANGELOG.md ADDED
@@ -0,0 +1,86 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ Detailed release write-ups live in [`docs/changelogs/`](docs/changelogs/).
9
+
10
+ ## [Unreleased]
11
+
12
+ ## [0.6.0] — 2026-08-13
13
+
14
+ ### Added
15
+
16
+ - Budget presets: `rails_request`, `sidekiq_job`, `ci_strict` (`Budget.preset` / `HeapScope.budget_preset`)
17
+ - Finding priority ranking + dedupe (`Findings.rank_and_dedupe`, `Finding#priority`)
18
+ - Next-steps recommendations (`Suggest.next_steps`, `HeapScope.next_steps`, report sections)
19
+ - `heapscope watch` — monitor with anomaly alerts (RSS / live-slot spikes)
20
+ - Monitor `--alert` / `--rss-alert-bytes` / `--live-alert-slots`
21
+ - Slim snapshot JSON (`Snapshot#save(..., slim: true)`, `heapscope snapshot --slim`)
22
+ - `heapscope doctor --fix` + `--config-out` — write starter `heapscope.yml`
23
+ - `HeapScope.write_config!` / `ConfigLoader.write_starter!`
24
+ - Branding asset path helpers (`LOGO_SVG`, `WORDMARK_SVG`, `logo_svg_inline`)
25
+ - Examples package README with logo/wordmark
26
+ - Rake `docs:codes` task for diagnostic catalog generation
27
+
28
+ ### Changed
29
+
30
+ - Version **0.6.0** — cohesive professional product release
31
+ - `Probe` / `Scorecard` extracted from `session.rb` into `scorecard.rb`
32
+ - `ConfigLoader` moved from `noise.rb` into `config.rb`
33
+ - Framework ignore hints owned by `Noise::FRAMEWORK_HINTS` (Suggest reuses them)
34
+ - Analyzer / retention reports apply ranked, deduped findings
35
+ - CLI `suggest` prints next steps + ignore patterns; `--ignores-only` / JSON payload expanded
36
+ - HTML reports prefer packaged logo SVG when available; include Next steps
37
+ - README / docs / roadmap present a single current-product story (not stacked milestones)
38
+ - Supported versions table updated for 0.6.x
39
+
40
+ ## [0.5.0] — 2026-08-13
41
+
42
+ ### Added
43
+
44
+ - `.github/FUNDING.yml` with GitHub Sponsors (`theworker02`) and thanks.dev (`u/gh/theworker02`)
45
+ - GitHub Pages site under `site/` + `pages.yml` deploy workflow
46
+ - `HeapScope::Branding` — banner, funding URLs, report footers, `HeapScope.about` / `.branding`
47
+ - `HeapScope::Suggest` + `heapscope suggest` — recommended ignore patterns (never auto-applied)
48
+ - `HeapScope::Pack` + `heapscope pack` — local JSON+HTML+Markdown report bundles
49
+ - CLI `about` command; doctor/help/report footers include funding + docs links
50
+ - Gem metadata `funding_uri` / Pages `documentation_uri`
51
+ - Expansive CLI UX: global `--verbose` / `--quiet` / `--config` / `--json` / `--color` / `--no-color`
52
+ - Per-command help; modular CLI under `lib/heapscope/cli/`
53
+ - CLI commands: `probe`, `measure`, `retention`, `findings`, `scorecard`, `table`, `explain`,
54
+ `open`/`html`, `self-test`, `env`, `completion`, `man`; aliases `export`, `ignore-suggest`
55
+ - `Catalog.explain` / `Catalog.lookup` for diagnostic encyclopedia entries
56
+
57
+ ### Changed
58
+
59
+ - Version **0.5.0**
60
+ - Homepage / source URIs → `https://github.com/theworker02/heapscope`
61
+ - `Catalog` extracted from `session.rb` into `catalog.rb`
62
+ - Suggest reuses `Noise` defaults instead of duplicating framework regexes
63
+
64
+ ## [0.4.0] — 2026-08-13
65
+
66
+ Sessions, scorecards, schema validation, diagnostic catalog, GitHub templates.
67
+
68
+ ## [0.3.0] — 2026-08-12
69
+
70
+ Aging, globals, closures, fibers, dominators, trends, doctor.
71
+
72
+ ## [0.2.0] — 2026-08-12
73
+
74
+ Branding, detectors, richer HTML, eval harness, security/CoC.
75
+
76
+ ## [0.1.0] — 2026-08-12
77
+
78
+ Initial retention toolkit.
79
+
80
+ [Unreleased]: https://github.com/theworker02/heapscope/compare/v0.6.0...HEAD
81
+ [0.6.0]: https://github.com/theworker02/heapscope/releases/tag/v0.6.0
82
+ [0.5.0]: https://github.com/theworker02/heapscope/releases/tag/v0.5.0
83
+ [0.4.0]: https://github.com/theworker02/heapscope/releases/tag/v0.4.0
84
+ [0.3.0]: https://github.com/theworker02/heapscope/releases/tag/v0.3.0
85
+ [0.2.0]: https://github.com/theworker02/heapscope/releases/tag/v0.2.0
86
+ [0.1.0]: https://github.com/theworker02/heapscope/releases/tag/v0.1.0
@@ -0,0 +1,38 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in the
6
+ HeapScope community a harassment-free experience for everyone, regardless of age,
7
+ body size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual identity
10
+ and orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to a positive environment:
15
+
16
+ - Demonstrating empathy and kindness
17
+ - Being respectful of differing opinions
18
+ - Giving and accepting constructive feedback
19
+ - Focusing on what is best for the community
20
+
21
+ Examples of unacceptable behavior:
22
+
23
+ - Trolling, insulting or derogatory comments, and personal or political attacks
24
+ - Public or private harassment
25
+ - Publishing others’ private information without permission
26
+ - Other conduct inappropriate in a professional setting
27
+
28
+ ## Enforcement
29
+
30
+ Project maintainers are responsible for clarifying and enforcing standards.
31
+ Instances of abusive behavior may be reported to the maintainers via GitHub.
32
+
33
+ ## Attribution
34
+
35
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
36
+ version 2.1.
37
+
38
+ [homepage]: https://www.contributor-covenant.org
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,72 @@
1
+ # Contributing to HeapScope
2
+
3
+ Thanks for helping build retention-first Ruby diagnostics.
4
+
5
+ ## Principles
6
+
7
+ 1. Prefer **retention evidence** over allocation volume alone.
8
+ 2. Separate **facts**, **derived metrics**, **hypotheses**, and **suspected causes**.
9
+ 3. Never fabricate reachability roots or confidence percentages.
10
+ 4. Keep the core dependency set minimal (stdlib + `fiddle`).
11
+ 5. Optional integrations must not become required gems.
12
+ 6. Degrade safely when a runtime capability is missing.
13
+ 7. Treat privacy as a feature: no telemetry, no value dumps by default.
14
+
15
+ ## Setup
16
+
17
+ ```bash
18
+ bundle install
19
+ bundle exec rake test
20
+ bundle exec rubocop
21
+ bundle exec ruby benchmark/run.rb
22
+ bundle exec ruby benchmark/eval_harness.rb
23
+ ```
24
+
25
+ ## Project layout
26
+
27
+ | Path | Purpose |
28
+ |------|---------|
29
+ | `lib/heapscope/` | Library |
30
+ | `lib/heapscope/cli/` | Modular CLI |
31
+ | `test/` | Minitest suite |
32
+ | `examples/` | Demonstrations (+ README branding) |
33
+ | `docs/` | Guides + diagnostic encyclopedia |
34
+ | `assets/` | Logos / wordmark (canonical) |
35
+ | `site/` | GitHub Pages marketing site |
36
+ | `benchmark/` | Overhead + eval harness |
37
+
38
+ ## Pull requests
39
+
40
+ - Conventional commits: `feat:`, `fix:`, `docs:`, `test:`, `chore:`, `refactor:`
41
+ - Update `CHANGELOG.md` under `[Unreleased]`
42
+ - Add `docs/changelogs/X.Y.Z.md` when cutting a release
43
+ - Add/adjust diagnostic docs when introducing finding codes
44
+ - Keep PRs focused
45
+
46
+ ## Branding
47
+
48
+ Logo sources:
49
+
50
+ - `assets/logo.svg` — app mark
51
+ - `assets/wordmark.svg` — horizontal lockup
52
+ - `assets/heapscope-logo.png` — raster
53
+
54
+ Please don’t introduce purple-glow AI-slop aesthetics; HeapScope’s look is teal/slate, calm, technical.
55
+
56
+ ## Code of conduct
57
+
58
+ See [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md).
59
+
60
+ ## Security
61
+
62
+ See [`SECURITY.md`](SECURITY.md).
63
+
64
+ ## Release
65
+
66
+ Semantic versioning. Standard Bundler flow:
67
+
68
+ ```bash
69
+ # bump lib/heapscope/version.rb
70
+ # update CHANGELOG.md + docs/changelogs/
71
+ bundle exec rake release
72
+ ```
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ group :development, :test do
8
+ gem "minitest", "~> 5.20"
9
+ gem "rake", "~> 13.0"
10
+ gem "rubocop", "~> 1.60"
11
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 HeapScope Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,342 @@
1
+ <p align="center">
2
+ <img src="assets/wordmark.svg" alt="HeapScope" width="520"/>
3
+ </p>
4
+
5
+ <p align="center">
6
+ <strong>Ruby object retention, heap growth, and memory leak diagnostics</strong><br/>
7
+ <em>Not just “how much memory” — <strong>why</strong> the process is keeping it.</em>
8
+ </p>
9
+
10
+ <p align="center">
11
+ <a href="https://rubygems.org/gems/heapscope"><img alt="Gem version" src="https://img.shields.io/gem/v/heapscope?color=0f766e&style=for-the-badge"></a>
12
+ <a href="https://github.com/theworker02/heapscope/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/theworker02/heapscope/ci.yml?branch=main&style=for-the-badge&label=CI"></a>
13
+ <a href="LICENSE"><img alt="MIT" src="https://img.shields.io/badge/license-MIT-334155?style=for-the-badge"></a>
14
+ <a href="#ruby-compatibility"><img alt="Ruby" src="https://img.shields.io/badge/ruby-%3E%3D%203.1-CC342D?style=for-the-badge&logo=ruby&logoColor=white"></a>
15
+ <a href="#privacy"><img alt="Privacy" src="https://img.shields.io/badge/privacy-local%20only-0f766e&style=for-the-badge"></a>
16
+ <a href="#no-saas"><img alt="No SaaS" src="https://img.shields.io/badge/SaaS-none-64748b&style=for-the-badge"></a>
17
+ <a href="https://thanks.dev/u/gh/theworker02"><img alt="thanks.dev" src="https://img.shields.io/badge/thanks.dev-theworker02-0f766e&style=for-the-badge"></a>
18
+ <a href="https://theworker02.github.io/heapscope/"><img alt="Docs" src="https://img.shields.io/badge/docs-Pages-0f766e?style=for-the-badge"></a>
19
+ <a href="CHANGELOG.md"><img alt="Changelog" src="https://img.shields.io/badge/changelog-0.6.0-0f766e&style=for-the-badge"></a>
20
+ </p>
21
+
22
+ <p align="center">
23
+ <a href="https://theworker02.github.io/heapscope/">Website</a> ·
24
+ <a href="docs/index.md">Docs hub</a> ·
25
+ <a href="#quick-start">Quick start</a> ·
26
+ <a href="docs/cli.md">CLI</a> ·
27
+ <a href="#privacy">Privacy</a> ·
28
+ <a href="https://thanks.dev/u/gh/theworker02">Sponsor</a> ·
29
+ <a href="CHANGELOG.md">Changelog</a>
30
+ </p>
31
+
32
+ ---
33
+
34
+ ## What HeapScope is
35
+
36
+ **HeapScope** is a local, evidence-driven Ruby gem for diagnosing **object retention**,
37
+ **abnormal heap growth**, **allocation hot spots**, **long-lived objects**, and
38
+ **leak-shaped patterns** in long-running processes.
39
+
40
+ It is designed for Rails, Puma, Sidekiq, background jobs, CLIs, and CI — distinguishing
41
+ allocation pressure from retention, and intentional caches from suspicious growth.
42
+
43
+ > **No SaaS.** No uploads. No telemetry. Everything runs in-process on your machine.
44
+
45
+ Release notes: [`docs/changelogs/0.6.0.md`](docs/changelogs/0.6.0.md)
46
+
47
+ ---
48
+
49
+ ## Why HeapScope
50
+
51
+ Traditional tools often answer: *“How much memory is the process using?”*
52
+
53
+ HeapScope answers: *“Why is this Ruby process retaining more memory than expected?”*
54
+
55
+ Every finding separates **observed facts**, **derived behavior**, **hypothesis**, and
56
+ **suspected cause** — and never claims `"Memory leak confirmed"` without strong evidence.
57
+
58
+ ---
59
+
60
+ ## Installation
61
+
62
+ ```ruby
63
+ # Gemfile
64
+ gem "heapscope", "~> 0.6"
65
+ ```
66
+
67
+ ```bash
68
+ bundle add heapscope
69
+ # or
70
+ gem install heapscope
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Ruby compatibility
76
+
77
+ | Engine | Status |
78
+ |--------|--------|
79
+ | **MRI Ruby ≥ 3.1** | Primary target — full ObjectSpace / allocation tracing / memsize |
80
+ | JRuby | Adapter present; capabilities degrade safely |
81
+ | TruffleRuby | Adapter present; capabilities degrade safely |
82
+
83
+ ```ruby
84
+ puts HeapScope.capabilities
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Quick start
90
+
91
+ ```ruby
92
+ require "heapscope"
93
+
94
+ report = HeapScope.measure(force_gc: true) { perform_work }
95
+ puts report
96
+ report.save("report.json")
97
+ report.save_html("report.html")
98
+
99
+ # Ranked follow-ups
100
+ puts HeapScope.next_steps(report)
101
+
102
+ # CI gate
103
+ budget = HeapScope.budget_preset(:ci_strict)
104
+ HeapScope.check(budget: budget) { perform_work }
105
+ ```
106
+
107
+ ```bash
108
+ heapscope doctor --fix # write starter heapscope.yml
109
+ heapscope snapshot --slim -o before.json
110
+ heapscope diff before.json after.json --html report.html --fail-on-medium
111
+ heapscope suggest report.json # next steps + ignore hints
112
+ heapscope watch --duration 120 -o watch.json
113
+ heapscope about
114
+ ```
115
+
116
+ Full CLI: [docs/cli.md](docs/cli.md)
117
+
118
+ ---
119
+
120
+ ## Product surface
121
+
122
+ | Capability | How |
123
+ |------------|-----|
124
+ | Snapshots (lightweight / standard / deep / slim JSON) | `HeapScope.snapshot` / `heapscope snapshot` |
125
+ | Diff & compare | `HeapScope.compare` / `heapscope diff` |
126
+ | Block measure & multi-cycle retention | `measure` / `retention_test` |
127
+ | Ranked findings + next steps | analyzer + `Suggest` |
128
+ | Budget presets | `Budget.preset(:rails_request\|:sidekiq_job\|:ci_strict)` |
129
+ | Sessions & scorecards | `HeapScope.session` / `probe` |
130
+ | Watch / monitor with alerts | `heapscope watch` / `Monitor` |
131
+ | Report packs | `HeapScope.pack` / `heapscope pack` |
132
+ | Baselines & schema validation | `baseline` / `validate` |
133
+ | Rails / Rack / Sidekiq / RSpec / Minitest | optional require paths |
134
+
135
+ ---
136
+
137
+ ## Concepts
138
+
139
+ ### Ruby heap vs RSS
140
+
141
+ HeapScope records **both** Ruby heap populations and process RSS.
142
+ **RSS growth ≠ Ruby object leak** — native extensions, allocators, mmap, and CoW matter.
143
+
144
+ ### Allocated vs retained
145
+
146
+ ```text
147
+ 100,000 allocated + 99,500 freed → churn
148
+ 100,000 allocated + 20,000 live → retention
149
+ ```
150
+
151
+ ### Forced GC
152
+
153
+ Opt-in only (`force_gc: true`). Never enabled by surprise; refuse deep walks in `production_safe`.
154
+
155
+ ---
156
+
157
+ ## Budgets & CI
158
+
159
+ ```ruby
160
+ HeapScope::Budget.preset(:rails_request)
161
+ HeapScope::Budget.preset(:sidekiq_job)
162
+ HeapScope::Budget.preset(:ci_strict)
163
+
164
+ # or hand-tuned
165
+ HeapScope::Budget.new(
166
+ max_retained_objects: 1_000,
167
+ max_rss_growth: 30 * 1024 * 1024,
168
+ severity_threshold: :high
169
+ )
170
+ ```
171
+
172
+ ```bash
173
+ heapscope baseline create report.json -o baseline.json
174
+ heapscope compare baseline.json current.json --threshold 0.5
175
+ ```
176
+
177
+ Guide: [docs/guides/ci-budgets.md](docs/guides/ci-budgets.md)
178
+
179
+ ---
180
+
181
+ ## Monitoring
182
+
183
+ ```ruby
184
+ monitor = HeapScope::Monitor.start(interval: 10, mode: :lightweight, alert: true)
185
+ # ...
186
+ report = monitor.stop
187
+ ```
188
+
189
+ ```bash
190
+ heapscope watch --interval 10 --duration 600 -o monitor.json
191
+ ```
192
+
193
+ Alerts fire on RSS / live-slot spikes between samples (thresholds configurable).
194
+
195
+ ---
196
+
197
+ ## Diagnostics
198
+
199
+ | Code | Name |
200
+ |------|------|
201
+ | HS001 | persistent_class_growth |
202
+ | HS002 | high_retention_ratio |
203
+ | HS003 | thread_local_retention |
204
+ | HS004 | unbounded_collection |
205
+ | HS005 | callback_accumulation |
206
+ | HS006 | closure_retention |
207
+ | HS007 | poor_gc_recovery |
208
+ | HS008 | baseline_regression |
209
+ | HS009 | high_allocation_pressure |
210
+ | HS010 | native_memory_mismatch |
211
+
212
+ ```bash
213
+ heapscope codes
214
+ heapscope explain HS001
215
+ ```
216
+
217
+ Encyclopedia: [`docs/diagnostics/`](docs/diagnostics/)
218
+
219
+ ---
220
+
221
+ ## Configuration
222
+
223
+ ```ruby
224
+ HeapScope.configure do |config|
225
+ config.mode = :standard # lightweight | standard | deep | production_safe | development
226
+ config.track_allocations = false
227
+ config.ignore_patterns << /Zeitwerk/
228
+ config.inspect_values = false # privacy: off by default
229
+ end
230
+ ```
231
+
232
+ ```bash
233
+ heapscope doctor --fix --config-out heapscope.yml
234
+ heapscope --config heapscope.yml doctor
235
+ ```
236
+
237
+ Branding / funding URLs live in `HeapScope::Branding` (single source of truth).
238
+
239
+ ---
240
+
241
+ ## Reports
242
+
243
+ Text, Markdown, versioned JSON, and static HTML — all offline. HTML uses the same brand mark as the site and README. Reports include **NEXT STEPS** when findings warrant follow-up.
244
+
245
+ ```ruby
246
+ HeapScope.pack(report, "./pack")
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Integrations
252
+
253
+ ```ruby
254
+ require "heapscope/middleware" # Rack sample_rate
255
+ require "heapscope/rails" # request_retention helpers
256
+ require "heapscope/sidekiq_middleware"
257
+ require "heapscope/minitest"
258
+ require "heapscope/rspec"
259
+ ```
260
+
261
+ Core gem requires **stdlib only** (plus `fiddle` when available for Windows RSS).
262
+
263
+ ---
264
+
265
+ ## Privacy
266
+
267
+ <a id="privacy"></a>
268
+ <a id="no-saas"></a>
269
+
270
+ By default HeapScope:
271
+
272
+ - makes **no network calls**
273
+ - sends **no telemetry / analytics**
274
+ - does **not** serialize object values
275
+ - does **not** dump ENV, tokens, cookies, or request bodies
276
+
277
+ See [`SECURITY.md`](SECURITY.md).
278
+
279
+ ---
280
+
281
+ ## Examples
282
+
283
+ ```bash
284
+ bundle exec ruby examples/healthy_churn.rb
285
+ bundle exec ruby examples/import_leak.rb
286
+ bundle exec ruby examples/showcase.rb
287
+ ```
288
+
289
+ See [`examples/README.md`](examples/README.md).
290
+
291
+ ---
292
+
293
+ ## Architecture
294
+
295
+ ```text
296
+ lib/heapscope.rb Public API
297
+ lib/heapscope/runtime/* Engine adapters + RSS
298
+ lib/heapscope/collector.rb Snapshot capture
299
+ lib/heapscope/diff.rb Population diffs
300
+ lib/heapscope/analyzer.rb Findings & suspects
301
+ lib/heapscope/findings.rb Codes + ranking/dedupe
302
+ lib/heapscope/suggest.rb Next steps + ignore hints
303
+ lib/heapscope/budget.rb CI budgets + presets
304
+ lib/heapscope/scorecard.rb Probe + executive scorecard
305
+ lib/heapscope/session.rb Named artifact sessions
306
+ lib/heapscope/report/* Text / HTML / Markdown
307
+ lib/heapscope/cli/ Modular CLI commands
308
+ ```
309
+
310
+ ---
311
+
312
+ ## Roadmap
313
+
314
+ See [`docs/ROADMAP.md`](docs/ROADMAP.md). Current focus: deeper precision and optional CI marketplace packaging — not parallel product surfaces.
315
+
316
+ ---
317
+
318
+ ## Contributing
319
+
320
+ See [`CONTRIBUTING.md`](CONTRIBUTING.md) and [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md).
321
+
322
+ ```bash
323
+ bundle install
324
+ bundle exec rake test
325
+ bundle exec rubocop
326
+ gem build heapscope.gemspec
327
+ ```
328
+
329
+ ---
330
+
331
+ ## License
332
+
333
+ MIT © [@theworker02](https://github.com/theworker02) — see [`LICENSE`](LICENSE).
334
+
335
+ Sponsor: [GitHub Sponsors](https://github.com/sponsors/theworker02) · [thanks.dev/u/gh/theworker02](https://thanks.dev/u/gh/theworker02)
336
+
337
+ ---
338
+
339
+ <p align="center">
340
+ <img src="assets/logo.svg" alt="" width="72"/><br/>
341
+ <sub>When <code>top</code> says memory is growing but profiling won’t say why — reach for HeapScope.</sub>
342
+ </p>