rigor-module-graph 0.1.1 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf3abcab20d49807ed210e09aedba79d88b5ef2bbb1d96c15a95d5d06cf8806d
4
- data.tar.gz: 5579a21f011ed0dddb58ed3c62dad92eb682920a3f5c92f5f9d63576d8b231ad
3
+ metadata.gz: 0ed5f8fe6226376ad089b013b8ad16cecc453da2202cbaf6b3a590e6b64d0c85
4
+ data.tar.gz: 47bdbc75a44a9887a58246783fcc3f57b5f1ad119b3c336c6673e72799678fe2
5
5
  SHA512:
6
- metadata.gz: df1406e30ec2d1efcbb8f7fb884435f320fdc4911746189c5d9063f2c02980a458f4765c8a6707f8b229e0d03c8475bc8d0a153a95ee6c4fc3580da7e2a9456a
7
- data.tar.gz: 0de9b8e511b698d3d8af731086a1df08890e72eda20254629d75f707ded01f367f5d536742fd8352269f2362f0b4a0f4ce295c6ab3de21b6b31a7ffd73f01c4f
6
+ metadata.gz: ae0a36d5c2107420b5a3577a2030c5417789f52ed0732f5d67669ac31444e73131135273d067e7f3fb6dfd7cafde845a7ef5183f4abd414bfae8ff446688d68d
7
+ data.tar.gz: 43ad7597db1d1fd945159afb81ee36339450b2ffa487bd94d21fc0da8ed0ae044af02a5b6c482044b510ee1ce0df56c2e215f72707307c8aef803ff0a9eab42e
data/CHANGELOG.md CHANGED
@@ -17,6 +17,122 @@ Categories:
17
17
 
18
18
  ## [Unreleased]
19
19
 
20
+ ## [0.1.3] — 2026-06-20
21
+
22
+ The first release that pairs the published gem with the
23
+ [interactive viewer](docs/how-it-works.md) the README has been
24
+ showcasing, plus the supply-chain hardening that justifies
25
+ shipping a vendored third-party JS file inside the gem.
26
+
27
+ ### Added
28
+
29
+ - **Interactive `view --output html` viewer.** Replaces the
30
+ static Mermaid embed with a [Cytoscape.js](https://js.cytoscape.org/)-based
31
+ page that renders 5k+ nodes, filters live by `kind` /
32
+ `confidence`, supports a name-substring search, and copies
33
+ `path:line` to the clipboard on node click. The Cytoscape
34
+ library is vendored into the gem at a sha256-pinned version
35
+ (`lib/rigor/module_graph/templates/vendor/cytoscape.min.js`);
36
+ no CDN, no npm, no Dependabot auto-bump.
37
+ See [`docs/plan.md`](docs/plan.md) "2D interactive viewer"
38
+ for the supply-chain rationale.
39
+ - `--path-mode {relative,absolute,none}` flag on `view` —
40
+ controls how node paths reach the viewer's click-through
41
+ metadata. `none` strips paths from the HTML artefact, which
42
+ is the right setting when sharing the file outside the
43
+ project (PR comment, gist, …).
44
+ - `--open-with vscode` flag on `view` — flips the node-click
45
+ action from clipboard copy to `vscode://file/<path>:<line>`
46
+ so the editor jumps straight to the source location.
47
+ - `bundle exec rake vendor:verify` task — recomputes sha256
48
+ for every file in `vendor/CHECKSUMS` and fails on mismatch.
49
+ Wired into pre-commit on any staged file under
50
+ `lib/**/templates/vendor/**`.
51
+ - `.github/dependabot.yml` — weekly Bundler + GitHub Actions
52
+ bumps; `vendor/**` is explicitly excluded so vendored
53
+ third-party JS never auto-updates.
54
+ - `bundle exec rake vendor:audit` — 4-source cross-check
55
+ (local sha256 / npm tarball `dist.integrity` /
56
+ tarball-internal copy / GitHub raw / every CDN). Reads
57
+ `lib/rigor/module_graph/templates/vendor/MANIFEST.yml` for
58
+ the provenance metadata. Use on bump PRs; not part of the
59
+ regular CI pipeline (network-using).
60
+ - CI now runs `rake vendor:verify` independently of
61
+ pre-commit so an unaudited bump can't land on `main` even
62
+ if local hooks were skipped.
63
+ - CI now regenerates `examples/billing/` via `script/
64
+ check_billing_drift.rb` and fails on drift between the
65
+ freshly-built artefacts and the committed copies.
66
+ Normalises the graphviz version banner so the runner's
67
+ apt-shipped version doesn't trigger a false positive.
68
+ - New `docs/security.md` consolidates the supply-chain story
69
+ (Bundler / Dependabot cooldown, vendored-JS sha256 +
70
+ 4-source audit, action SHA pinning, OIDC trusted
71
+ publishing).
72
+
73
+ ### Changed
74
+
75
+ - **`view --output html` semantics.** The flag now produces
76
+ the interactive viewer. The previous static Mermaid HTML
77
+ moves behind `--output mermaid-html` (still loads Mermaid
78
+ from a CDN, kept for back-compat).
79
+ - CI workflows read Ruby from `.ruby-version` instead of
80
+ pinning `"4.0.0"` inline, so future `.ruby-version` bumps
81
+ no longer need a `.github/workflows/` chase.
82
+ - RDoc dependency bumped from `~> 6.0` to `~> 7.0` (resolves
83
+ to 7.2.0). `gemspec.rdoc_options` corrected to `--markup
84
+ markdown` to match `.rdoc_options` and the Rakefile, fixing
85
+ the silent inconsistency left when the README rendering
86
+ fix landed in [0.1.2]. No code change; `rake rdoc` emits no
87
+ warnings under 7.x.
88
+ - README hero leads with the Cytoscape viewer screenshot
89
+ (the default output) and the Graphviz SVG follows.
90
+ `examples/billing/preview.png` resized from 1280x860 to
91
+ 720x483 so it fits the RDoc darkfish content pane on the
92
+ GitHub Pages site without overflow.
93
+ - README Documentation index re-ordered along the natural
94
+ reading flow: how-it-works → security → limitation →
95
+ development → plan.
96
+
97
+ ## [0.1.2] — 2026-06-20
98
+
99
+ First release that exercises the full automated pipeline end
100
+ to end — Trusted Publishing + GitHub Release + asset upload
101
+ all drive off a single `gh workflow run release.yml` after the
102
+ tag is pushed.
103
+
104
+ ### Added
105
+
106
+ - `view` and `collect` now emit step-level progress on stderr:
107
+ `==> Running rigor check ...`, post-step counts (`18 edge(s),
108
+ 16 node(s)`), and inline elapsed time (`done (428ms)`).
109
+ TTY-aware — the start / done halves render inline on a
110
+ terminal, on separate lines for redirected output, so logs
111
+ stay grep-friendly. `-q` / `--quiet` suppresses the progress
112
+ output for scripted use; the final `wrote N edge(s) to ...`
113
+ summary line stays. Driven by a new `StatusReporter` class
114
+ pinned by `test/rigor/module_graph/status_reporter_test.rb`.
115
+
116
+ ### Changed
117
+
118
+ - README restructured along the install → getting started →
119
+ usage → configuration flow. The "How it works" walkthrough
120
+ (pipeline diagram + the "not a call graph" framing) moves to
121
+ `docs/how-it-works.md` so the README stays focused on
122
+ "what do I type". Configuration section now notes that
123
+ `.rigor.yml` is required (rigor reads it to discover the
124
+ plugin), with a two-line minimum example up top and the
125
+ fully-elaborated default form below.
126
+
127
+ ### Fixed
128
+
129
+ - RDoc generation now parses Markdown instead of RDoc syntax,
130
+ so `![alt](path)` images in `README.md` / `CHANGELOG.md` /
131
+ `docs/*.md` actually render. `Rake::Task[:rdoc]` is enhanced
132
+ to copy `examples/billing/graph.svg` (and any future
133
+ `RDOC_ASSET_PATHS` entries) into `doc/` so the generated site
134
+ resolves the relative image references the README uses.
135
+
20
136
  ## [0.1.1] — 2026-06-20
21
137
 
22
138
  First Action-driven publish. The 0.1.0 release happened via the
@@ -134,6 +250,8 @@ spike through Phase 5 (UML class diagram).
134
250
  baseline and YJIT, and trailed baseline on Stats and
135
251
  CycleDetector — recommendation stays YJIT.
136
252
 
137
- [Unreleased]: https://github.com/nozomemein/rigor-module-graph/compare/v0.1.1...HEAD
253
+ [Unreleased]: https://github.com/nozomemein/rigor-module-graph/compare/v0.1.3...HEAD
254
+ [0.1.3]: https://github.com/nozomemein/rigor-module-graph/compare/v0.1.2...v0.1.3
255
+ [0.1.2]: https://github.com/nozomemein/rigor-module-graph/compare/v0.1.1...v0.1.2
138
256
  [0.1.1]: https://github.com/nozomemein/rigor-module-graph/compare/v0.1.0...v0.1.1
139
257
  [0.1.0]: https://github.com/nozomemein/rigor-module-graph/releases/tag/v0.1.0
data/README.md CHANGED
@@ -1,64 +1,37 @@
1
1
  # rigor-module-graph
2
2
 
3
+ [![Gem Version](https://img.shields.io/gem/v/rigor-module-graph.svg)](https://rubygems.org/gems/rigor-module-graph)
4
+ [![License: MIT](https://img.shields.io/github/license/nozomemein/rigor-module-graph.svg)](LICENSE.txt)
5
+ [![CI](https://github.com/nozomemein/rigor-module-graph/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/nozomemein/rigor-module-graph/actions/workflows/ci.yml)
6
+ [![Docs](https://github.com/nozomemein/rigor-module-graph/actions/workflows/docs.yml/badge.svg?branch=main)](https://github.com/nozomemein/rigor-module-graph/actions/workflows/docs.yml)
7
+
3
8
  Class/module/constant dependency graph for Ruby projects, built on
4
9
  [Rigor](https://rigor.typedduck.fail/). The class-level counterpart
5
10
  to Packwerk/Graphwerk: where those look at package boundaries, this
6
11
  looks at the Ruby nominal graph — inheritance, `include`/`prepend`/
7
12
  `extend`, and (later) constant references.
8
13
 
9
- ![billing example](examples/billing/graph.svg)
10
-
11
- The screenshot above is from `examples/billing/`. Open
12
- `examples/billing/index.html` for the live Mermaid version.
13
-
14
- ## What this actually does
15
-
16
- In principle this is a static-analysis tool that turns Ruby source
17
- into a graph whose **nodes are classes / modules / constants** and
18
- whose **edges are the references the language itself spells out**.
19
-
20
- The pipeline:
21
-
22
- 1. Rigor parses Ruby into an AST with Prism.
23
- 2. The plugin's `node_rule`s pick up `ClassNode` / `CallNode` /
24
- `ConstantReadNode` and friends.
25
- 3. Each interesting node becomes one or more edges:
26
- - `class A < B` `A -> B / inherits`
27
- - `include M` → `A -> M / include`
28
- - a `Money` constant reference → `A -> Money / const_ref`
29
- (Phase 2 and later)
30
- 4. `from` is the lexical owner, assembled by walking
31
- `context.ancestors` — so `class Billing::Invoice` produces
32
- `Billing::Invoice`, not just `Invoice`.
33
- 5. `to` is resolved through a confidence ladder: syntax →
34
- Zeitwerk convention → Rigor type information. Whatever we
35
- couldn't pin down stays visible in the `confidence` field
36
- rather than being dropped.
37
- 6. Every edge ships as a Rigor `:info` diagnostic. The `collect`
38
- subcommand filters them on `rule == "edge"` and writes JSONL.
39
- 7. DOT, SVG, Mermaid, and cycle detection are all derived from
40
- that JSONL.
41
-
42
- So we are not watching what Ruby *does at runtime*. We're reading
43
- Ruby's *named structure* and reconstructing, approximately, "which
44
- constants depend on which other constants".
45
-
46
- ### This is not a call graph
47
-
48
- We do not track who `foo.bar` resolves to at runtime. We track
49
- the fact that the `Billing::Invoice` name depends on the
50
- `ApplicationRecord` / `Auditable` / `Money` names. That is a
51
- **nominal dependency graph** — a compiler-front-end-style view
52
- of the project's syntactic and lexical structure, projected into
53
- edges with explicit confidence.
54
-
55
- Not re-implementing Ruby constant lookup is deliberate. For
56
- understanding a Rails codebase's shape, it's more useful to leave
57
- each edge tagged `syntax` / `zeitwerk` / `rigor_type` /
58
- `unresolved` than to fake a `resolved` answer and silently get it
59
- wrong.
60
-
61
- ## Installation
14
+ **Two ways to look at the same graph.** Static SVG via
15
+ Graphviz for committing into PRs and docs; interactive HTML
16
+ via Cytoscape.js for actually exploring a 1000+-node Rails
17
+ codebase. Both rendered from the same `edges.jsonl`
18
+ no second analysis pass.
19
+
20
+ ### Cytoscape (`--output html`, the default)
21
+
22
+ ![billing graph via Cytoscape](examples/billing/preview.png)
23
+
24
+ ### Graphviz (`--output svg`)
25
+
26
+ ![billing graph via Graphviz](examples/billing/graph.svg)
27
+
28
+ Both screenshots are from `examples/billing/`. Open
29
+ `examples/billing/index.html` directly to try the
30
+ interactive version pan, zoom, filter by `kind` /
31
+ `confidence`, search by name, click a node to copy
32
+ `path:line`.
33
+
34
+ ## Install
62
35
 
63
36
  Via Bundler:
64
37
 
@@ -71,87 +44,101 @@ gem "rigor-module-graph"
71
44
  bundle install
72
45
  ```
73
46
 
74
- Or globally:
47
+ Or system-wide:
75
48
 
76
49
  ```sh
77
50
  gem install rigor-module-graph
78
51
  ```
79
52
 
80
- Both paths pull in `rigortype` and `rbs ~> 4.0` transitively. The
81
- `rbs ~> 4.0` constraint is the key one: rigortype 0.2.x calls
82
- `RBS::Environment::ClassEntry#each_decl`, which only exists in
83
- rbs 4.x. The Ruby 4.0 stdlib bundles rbs 3.10 as a default gem,
84
- so installing `rigor-module-graph` (which depends on rbs 4.x)
85
- makes RubyGems activate the 4.x gem at run time and the
86
- analyzer stays alive.
87
-
88
- ## Configuration
53
+ Both paths pull in `rigortype` and `rbs ~> 4.0` transitively.
54
+ The `rbs ~> 4.0` constraint is the one that matters: rigortype
55
+ 0.2.x calls `RBS::Environment::ClassEntry#each_decl`, which
56
+ only exists in rbs 4.x. The Ruby 4.0 stdlib bundles rbs 3.10
57
+ as a default gem, so installing `rigor-module-graph` (which
58
+ depends on rbs 4.x) makes RubyGems activate the 4.x gem at
59
+ run time and the analyzer stays alive.
89
60
 
90
- Add the plugin to your project's `.rigor.yml`:
61
+ For the full pipeline you also want `graphviz` installed so
62
+ `view --output svg` and `dot -Tsvg` can render PNG / SVG from
63
+ the generated DOT:
91
64
 
92
- ```yaml
93
- target_ruby: '4.0'
94
- paths:
95
- - app
96
- - lib
97
- plugins:
98
- - gem: rigor-module-graph
99
- config:
100
- rails_zeitwerk: true
101
- autoload_paths:
102
- - app/models
103
- - app/controllers
104
- - app/services
105
- - app/jobs
106
- - lib
107
- concern_dirs:
108
- - app/models/concerns
109
- - app/controllers/concerns
110
- include_constant_refs: false
65
+ ```sh
66
+ brew install graphviz # macOS
67
+ apt-get install graphviz # Debian / Ubuntu
111
68
  ```
112
69
 
113
- Every key shown is the default. Set `include_constant_refs: true`
114
- to emit `const_ref` edges from constant references inside method
115
- bodies. Set `rails_zeitwerk: false` to keep every edge at
116
- `confidence: "syntax"` and skip path-based owner inference.
117
-
118
- ## Usage
70
+ A working `dot` on `$PATH` is optional text / Mermaid / HTML
71
+ output paths don't need it. See [How it works](docs/how-it-works.md)
72
+ for the pipeline overview.
119
73
 
120
- ### One-shot: `view`
74
+ ## Getting started
121
75
 
122
- The default subcommand analyses the current directory, writes a
123
- self-contained Mermaid HTML report under `.rigor/module_graph/`,
124
- and opens it in your browser. No flags needed for a Rails-shaped
125
- project.
76
+ The default subcommand analyses the current directory, writes
77
+ a self-contained Mermaid HTML report under
78
+ `.rigor/module_graph/`, and opens it in a browser:
126
79
 
127
80
  ```sh
128
81
  cd path/to/your/project
129
82
  bundle exec rigor-module-graph # same as: rigor-module-graph view
130
83
  ```
131
84
 
132
- Useful flags:
85
+ A `.rigor.yml` must exist in the project root — that's how
86
+ `rigor` knows to load this plugin. The minimal version is two
87
+ lines:
88
+
89
+ ```yaml
90
+ plugins:
91
+ - gem: rigor-module-graph
92
+ ```
93
+
94
+ That's enough for `view` to run with all defaults. Everything
95
+ else (`paths:`, `autoload_paths:`, …) goes in the
96
+ [Configuration](#configuration) section below, and every key
97
+ defaults to a sensible Rails-shaped value.
98
+
99
+ ## Usage
100
+
101
+ ### `view` — one-shot HTML / SVG / Mermaid
102
+
103
+ The default `html` output is an interactive
104
+ [Cytoscape.js](https://js.cytoscape.org/)-based viewer:
105
+ filter checkboxes for `kind` and `confidence`, live name
106
+ search, `fit` button, and node-click → copy `path:line` to
107
+ the clipboard. The Cytoscape library is vendored into the gem
108
+ at a sha256-pinned version, so the generated HTML opens
109
+ offline with no network round-trip.
133
110
 
134
111
  ```sh
135
112
  # Don't open the browser (just write the HTML)
136
113
  rigor-module-graph view --no-open
137
114
 
138
- # Pick a different output format html (default) opens a viewer
139
- # in the browser; everything else streams to stdout unless `-o`
140
- # is given.
115
+ # Pick a different output format. `html` is the interactive
116
+ # viewer; `mermaid-html` is the legacy static-Mermaid embed
117
+ # (loads Mermaid from a CDN, kept for back-compat). Everything
118
+ # else streams to stdout unless `-o` is given.
119
+ rigor-module-graph view --no-open --output mermaid-html > graph.html
141
120
  rigor-module-graph view --no-open --output mermaid > graph.mmd
142
121
  rigor-module-graph view --no-open --output dot > graph.dot
143
122
  rigor-module-graph view --no-open --output svg > graph.svg
144
123
  rigor-module-graph view --no-open --output class-diagram > class.mmd
145
124
  rigor-module-graph view --output svg -o graph.svg
146
125
 
147
- # Focus on what's around one or a few constants (Mermaid can't
148
- # render 1000+-node graphs cleanly this is the escape hatch)
126
+ # Click on a node opens the file in VSCode rather than copying
127
+ # path:line to the clipboard. `--path-mode none` strips the
128
+ # path metadata entirely — useful when sharing the HTML
129
+ # artefact outside the project.
130
+ rigor-module-graph view --open-with vscode
131
+ rigor-module-graph view --path-mode none # share-safe
132
+ rigor-module-graph view --path-mode absolute # cwd-resolved
133
+
134
+ # Focus on what's around one or a few constants
149
135
  rigor-module-graph view --from Article --depth 5
150
136
  rigor-module-graph view --from Article --depth 5 --direction out
151
137
  rigor-module-graph view --from Billing::Invoice,Billing::Payment --depth 2
152
138
 
153
139
  # Pick your own collapse list (default: auto-detect top-level
154
- # namespaces with ≥ 3 members)
140
+ # namespaces with ≥ 3 members; applies to mermaid / dot / svg
141
+ # outputs — the interactive html viewer ignores it).
155
142
  rigor-module-graph view --collapse Billing,Auth
156
143
  rigor-module-graph view --no-collapse
157
144
 
@@ -164,7 +151,7 @@ rigor-module-graph view --package
164
151
  rigor-module-graph view --package-root /path/to/repo
165
152
  ```
166
153
 
167
- `--direction` controls how the +--from+ walk follows edges:
154
+ `--direction` controls how the `--from` walk follows edges:
168
155
 
169
156
  | direction | meaning |
170
157
  |-----------|----------------------------------------|
@@ -179,17 +166,19 @@ rigor-module-graph view --package-root /path/to/repo
179
166
  | `cluster` | keep every edge whose endpoints both fall in the reachable set (default — good for "show me the Article neighbourhood as a cluster") |
180
167
  | `walk` | keep only the edges the BFS actually traversed (good for "show me what depends on Article and nothing else"; drops sibling edges like `Foo inherits ApplicationRecord` that just happen to share a base class with reachable nodes) |
181
168
 
182
- A 1-hop `--from Article --direction out --edge-scope walk` returns
183
- exactly the edges whose `from` is `Article`, never the sibling
184
- `inherits ApplicationRecord` of a reached node.
169
+ A 1-hop `--from Article --direction out --edge-scope walk`
170
+ returns exactly the edges whose `from` is `Article`, never the
171
+ sibling `inherits ApplicationRecord` of a reached node.
185
172
 
186
173
  ### Lower-level pipeline
187
174
 
188
- The pipeline `view` runs is also exposed as discrete subcommands
189
- when you want JSONL on disk or a pipeable text output:
175
+ The pipeline `view` runs is also exposed as discrete
176
+ subcommands when you want JSONL on disk or a pipeable text
177
+ output:
190
178
 
191
179
  ```sh
192
- # Run `rigor check` and write edges JSONL (default: .rigor/module_graph/edges.jsonl)
180
+ # Run `rigor check` and write edges JSONL
181
+ # (default: .rigor/module_graph/edges.jsonl)
193
182
  bundle exec rigor-module-graph collect
194
183
 
195
184
  # Render the graph
@@ -210,18 +199,19 @@ bundle exec rigor-module-graph class-diagram .rigor/module_graph/edges.jsonl > c
210
199
  bundle exec rigor-module-graph class-diagram --no-private --no-attributes edges.jsonl
211
200
  ```
212
201
 
213
- `collect` shells out to `rigor check --format json --no-cache` and
214
- filters diagnostics on `source_family == "plugin.module-graph"` +
215
- `rule == "edge"`, so re-running is deterministic and there's no
216
- on-disk side-effect from the plugin itself.
202
+ `collect` shells out to `rigor check --format json --no-cache`
203
+ and filters diagnostics on
204
+ `source_family == "plugin.module-graph"` + `rule == "edge"`,
205
+ so re-running is deterministic and there's no on-disk
206
+ side-effect from the plugin itself.
217
207
 
218
208
  `dot` / `mermaid` / `cycles` accept a file argument or read stdin.
219
209
 
220
210
  ### Filters and collapse
221
211
 
222
- All three reader subcommands accept the same filter flags. They
223
- prune the edge set before rendering / detecting; the JSONL on
224
- disk is untouched.
212
+ All reader subcommands accept the same filter flags. They prune
213
+ the edge set before rendering / detecting; the JSONL on disk is
214
+ untouched.
225
215
 
226
216
  ```sh
227
217
  # Drop noisy const_ref / unresolved edges
@@ -230,7 +220,8 @@ bundle exec rigor-module-graph dot --kind inherits,include,prepend,extend edges.
230
220
  # Only the edges we're sure about
231
221
  bundle exec rigor-module-graph dot --confidence syntax,zeitwerk,rigor_type edges.jsonl
232
222
 
233
- # Fold every Billing::* node into one cluster (Dot subgraph_cluster_; Mermaid subgraph)
223
+ # Fold every Billing::* node into one cluster
224
+ # (Dot: subgraph_cluster_; Mermaid: subgraph)
234
225
  bundle exec rigor-module-graph dot --collapse Billing,Auth edges.jsonl
235
226
  bundle exec rigor-module-graph mermaid --collapse Billing edges.jsonl
236
227
 
@@ -247,21 +238,45 @@ bundle exec rigor-module-graph mermaid --package-root /path/to/repo edges.jsonl
247
238
  bundle exec rigor-module-graph cycles --kind inherits,include edges.jsonl
248
239
  ```
249
240
 
250
- ## Edge format
241
+ ## Configuration
251
242
 
252
- Each edge in the JSONL file looks like:
243
+ `.rigor.yml` lives in the project root and is **required** —
244
+ `rigor` reads it to discover this plugin. `rigor init` scaffolds
245
+ a `.rigor.dist.yml` you can rename, or write it by hand. The
246
+ two-line minimum from [Getting started](#getting-started) is
247
+ enough; the full form below is for tuning.
253
248
 
254
- ```json
255
- {"from":"Billing::Invoice","to":"ApplicationRecord","kind":"inherits","path":"app/models/billing/invoice.rb","line":2,"column":3,"confidence":"syntax"}
249
+ ```yaml
250
+ target_ruby: '4.0'
251
+ paths:
252
+ - app
253
+ - lib
254
+ plugins:
255
+ - gem: rigor-module-graph
256
+ config:
257
+ rails_zeitwerk: true
258
+ autoload_paths:
259
+ - app/models
260
+ - app/controllers
261
+ - app/services
262
+ - app/jobs
263
+ - lib
264
+ concern_dirs:
265
+ - app/models/concerns
266
+ - app/controllers/concerns
267
+ include_constant_refs: false
256
268
  ```
257
269
 
258
- - `kind`: `inherits` / `include` / `prepend` / `extend` /
259
- `const_ref` (the last one is reserved for Phase 2).
260
- - `confidence`: `syntax` / `zeitwerk` / `rigor_type` /
261
- `unresolved`. MVP only emits `syntax`.
270
+ Every key shown is the default. Two switches worth knowing:
262
271
 
263
- The renderers dedup by `(from, to, kind, confidence)` so two
264
- `include Foo` on the same class across files collapse to one edge.
272
+ - `include_constant_refs: true` emit `const_ref` edges from
273
+ bare constant references inside method bodies. Off by default
274
+ because the volume of edges grows fast on a typical Rails app
275
+ and the noise can drown the structural picture.
276
+ - `rails_zeitwerk: false` — keep every edge at
277
+ `confidence: "syntax"` and skip the path-based owner
278
+ inference. Useful when the project doesn't follow Zeitwerk's
279
+ autoload convention.
265
280
 
266
281
  ## Compatibility
267
282
 
@@ -279,14 +294,22 @@ published to GitHub Pages on every push to `main`.
279
294
  built from `main`, mirrors the current source.
280
295
  - [API reference (RubyGems)](https://rubydoc.info/gems/rigor-module-graph) —
281
296
  the last released gem on rubydoc.info.
297
+ - [How it works](docs/how-it-works.md) — the static-analysis
298
+ pipeline (Prism → node rules → confidence ladder → JSONL →
299
+ renderers), and why this is a nominal dependency graph and
300
+ not a call graph.
301
+ - [Security](docs/security.md) — supply-chain controls
302
+ (Bundler cooldown, vendored-JS sha256 + 4-source audit,
303
+ action SHA pinning, trusted publishing) and the layered
304
+ pre-commit / CI gates that enforce them.
305
+ - [Known limitations](docs/limitation.md) — rough edges shipped
306
+ with the current release (visibility tracker gaps, the
307
+ bundled inflector, Mermaid 10.x quirks).
282
308
  - [Development guide](docs/development.md) — local setup, git
283
309
  hooks, CI / Release workflows, test suite layout.
284
310
  - [Design plan](docs/plan.md) — the decisions still
285
311
  load-bearing for the code (edge model, confidence ladder,
286
312
  output channel, owner resolution, architecture map).
287
- - [Known limitations](docs/limitation.md) — rough edges shipped
288
- with the current release (visibility tracker gaps, the
289
- bundled inflector, Mermaid 10.x quirks).
290
313
  - [Changelog](CHANGELOG.md) — per-version changes, formatted
291
314
  per [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
292
315
  with [Semantic Versioning](https://semver.org/spec/v2.0.0.html).