rigortype 0.2.1 → 0.2.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 +4 -4
- data/README.md +41 -14
- data/docs/handbook/01-getting-started.md +311 -0
- data/docs/handbook/02-everyday-types.md +337 -0
- data/docs/handbook/03-narrowing.md +359 -0
- data/docs/handbook/04-tuples-and-shapes.md +321 -0
- data/docs/handbook/05-methods-and-blocks.md +339 -0
- data/docs/handbook/06-classes.md +305 -0
- data/docs/handbook/07-rbs-and-extended.md +427 -0
- data/docs/handbook/08-understanding-errors.md +373 -0
- data/docs/handbook/09-plugins.md +241 -0
- data/docs/handbook/10-sorbet.md +347 -0
- data/docs/handbook/11-sig-gen.md +312 -0
- data/docs/handbook/12-lightweight-hkt.md +333 -0
- data/docs/handbook/README.md +275 -0
- data/docs/handbook/appendix-elixir.md +370 -0
- data/docs/handbook/appendix-go.md +399 -0
- data/docs/handbook/appendix-java-csharp.md +470 -0
- data/docs/handbook/appendix-liskov.md +580 -0
- data/docs/handbook/appendix-mypy.md +370 -0
- data/docs/handbook/appendix-phpstan.md +338 -0
- data/docs/handbook/appendix-protocols-and-structural-typing.md +292 -0
- data/docs/handbook/appendix-rust.md +446 -0
- data/docs/handbook/appendix-steep.md +336 -0
- data/docs/handbook/appendix-type-theory.md +1662 -0
- data/docs/handbook/appendix-typeprof.md +416 -0
- data/docs/handbook/appendix-typescript.md +332 -0
- data/docs/install.md +189 -0
- data/docs/llms.txt +72 -0
- data/docs/manual/01-installation.md +342 -0
- data/docs/manual/02-cli-reference.md +569 -0
- data/docs/manual/03-configuration.md +152 -0
- data/docs/manual/04-diagnostics.md +206 -0
- data/docs/manual/05-inspecting-types.md +109 -0
- data/docs/manual/06-baseline.md +104 -0
- data/docs/manual/07-plugins.md +92 -0
- data/docs/manual/08-skills.md +143 -0
- data/docs/manual/09-editor-integration.md +245 -0
- data/docs/manual/10-mcp-server.md +539 -0
- data/docs/manual/11-ci.md +274 -0
- data/docs/manual/12-caching.md +116 -0
- data/docs/manual/13-troubleshooting.md +120 -0
- data/docs/manual/14-rails-quickstart.md +332 -0
- data/docs/manual/15-type-protection-coverage.md +204 -0
- data/docs/manual/16-rbs-extended-annotations.md +190 -0
- data/docs/manual/17-driving-improvement.md +160 -0
- data/docs/manual/README.md +87 -0
- data/docs/manual/ci-templates/README.md +58 -0
- data/docs/manual/plugins/README.md +86 -0
- data/docs/manual/plugins/rigor-actioncable.md +78 -0
- data/docs/manual/plugins/rigor-actionmailer.md +74 -0
- data/docs/manual/plugins/rigor-actionpack.md +80 -0
- data/docs/manual/plugins/rigor-activejob.md +58 -0
- data/docs/manual/plugins/rigor-activerecord.md +102 -0
- data/docs/manual/plugins/rigor-activestorage.md +74 -0
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +86 -0
- data/docs/manual/plugins/rigor-devise.md +70 -0
- data/docs/manual/plugins/rigor-dry-schema.md +56 -0
- data/docs/manual/plugins/rigor-dry-struct.md +60 -0
- data/docs/manual/plugins/rigor-dry-types.md +59 -0
- data/docs/manual/plugins/rigor-dry-validation.md +62 -0
- data/docs/manual/plugins/rigor-factorybot.md +76 -0
- data/docs/manual/plugins/rigor-graphql.md +89 -0
- data/docs/manual/plugins/rigor-hanami.md +83 -0
- data/docs/manual/plugins/rigor-mangrove.md +73 -0
- data/docs/manual/plugins/rigor-minitest.md +86 -0
- data/docs/manual/plugins/rigor-pundit.md +72 -0
- data/docs/manual/plugins/rigor-rails-i18n.md +92 -0
- data/docs/manual/plugins/rigor-rails-routes.md +94 -0
- data/docs/manual/plugins/rigor-rails.md +44 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +83 -0
- data/docs/manual/plugins/rigor-rspec-rails.md +72 -0
- data/docs/manual/plugins/rigor-rspec.md +86 -0
- data/docs/manual/plugins/rigor-shoulda-matchers.md +78 -0
- data/docs/manual/plugins/rigor-sidekiq.md +78 -0
- data/docs/manual/plugins/rigor-sinatra.md +61 -0
- data/docs/manual/plugins/rigor-sorbet.md +63 -0
- data/docs/manual/plugins/rigor-statesman.md +75 -0
- data/docs/manual/plugins/rigor-typescript-utility-types.md +71 -0
- data/exe/rigor +1 -1
- data/lib/rigor/analysis/incremental_session.rb +4 -2
- data/lib/rigor/analysis/run_stats.rb +13 -1
- data/lib/rigor/analysis/runner.rb +54 -12
- data/lib/rigor/cli/check_command.rb +1 -1
- data/lib/rigor/cli/docs_command.rb +248 -0
- data/lib/rigor/cli/skill_command.rb +103 -41
- data/lib/rigor/cli/skill_describe.rb +346 -0
- data/lib/rigor/cli/triage_command.rb +8 -2
- data/lib/rigor/cli/triage_renderer.rb +4 -0
- data/lib/rigor/cli.rb +25 -3
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +124 -32
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +37 -6
- data/lib/rigor/inference/scope_indexer.rb +87 -89
- data/lib/rigor/plugin/isolation.rb +5 -5
- data/lib/rigor/plugin/loader.rb +4 -2
- data/lib/rigor/triage/catalogue.rb +16 -1
- data/lib/rigor/triage.rb +30 -7
- data/lib/rigor/version.rb +1 -1
- data/skills/rigor-ask/SKILL.md +172 -0
- data/skills/rigor-doctor/SKILL.md +87 -0
- data/skills/rigor-editor-setup/SKILL.md +114 -0
- data/skills/rigor-mcp-setup/SKILL.md +117 -0
- data/skills/rigor-monkeypatch-resolve/SKILL.md +79 -0
- data/skills/rigor-next-steps/SKILL.md +113 -0
- data/skills/rigor-plugin-tune/SKILL.md +79 -0
- data/skills/rigor-protection-uplift/SKILL.md +133 -0
- data/skills/rigor-rbs-setup/SKILL.md +128 -0
- data/skills/rigor-upgrade/SKILL.md +79 -0
- metadata +90 -1
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
# CLI command reference
|
|
2
|
+
|
|
3
|
+
Every Rigor command is a subcommand of the single `rigor`
|
|
4
|
+
executable:
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
rigor <command> [options] [arguments]
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
`rigor help` prints the command list; `rigor version` prints
|
|
11
|
+
the installed version. An unknown command, or a malformed
|
|
12
|
+
option, exits `64` — the conventional "usage error" code.
|
|
13
|
+
|
|
14
|
+
Every command that loads your project configuration also
|
|
15
|
+
accepts `--config=PATH` to point at a specific config file
|
|
16
|
+
instead of auto-discovery (it is called out below only where it
|
|
17
|
+
has an additional effect).
|
|
18
|
+
|
|
19
|
+
## `rigor check`
|
|
20
|
+
|
|
21
|
+
Analyse Ruby source for type errors and report diagnostics.
|
|
22
|
+
This is the command you run day to day and in CI.
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
rigor check [paths...]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`paths` are files or directories; when omitted, Rigor checks
|
|
29
|
+
the `paths:` list from the configuration file.
|
|
30
|
+
|
|
31
|
+
| Option | Effect |
|
|
32
|
+
| --- | --- |
|
|
33
|
+
| `--config=PATH` | Use a specific config file instead of auto-discovery. |
|
|
34
|
+
| `--format=FORMAT` | Output format. Default `text`. Also `json` (structured stream), plus the CI-native renderings `sarif`, `github`, `gitlab`, `checkstyle`, `junit`, and `teamcity` — see [Running Rigor in CI](11-ci.md). |
|
|
35
|
+
| `--no-ci-detect` | Disable CI auto-detection — by default `text` output also emits the running CI's native annotations / hint (`RIGOR_CI_DETECT=0` does the same). See [Running Rigor in CI § auto-detection](11-ci.md). |
|
|
36
|
+
| `--explain` | Surface fail-soft fallback events as `info` diagnostics. |
|
|
37
|
+
| `--no-cache` | Skip the persistent cache for this run. |
|
|
38
|
+
| `--incremental` | Re-analyse only the files changed since the last run plus the files that depend on them, serving the rest from a cross-process disk snapshot (ADR-46). Diagnostics are identical to a full run; a config / gem / version change (or a file added or removed) transparently forces a full re-analysis. See [Caching](12-caching.md). |
|
|
39
|
+
| `--verify-incremental` | Acceptance gate: run the incremental analyzer against a full `--no-cache` run and assert the diagnostics are byte-identical, then exit (0 on match, 1 with the differing diagnostics on mismatch). Used in CI to guarantee `--incremental` never serves a stale result. |
|
|
40
|
+
| `--clear-cache` | Delete the cache directory before running. |
|
|
41
|
+
| `--cache-stats` | Print the on-disk cache inventory when finished. |
|
|
42
|
+
| `--[no-]stats` | Print a run summary (files, classes, memory, wall time) to stderr. Default on. |
|
|
43
|
+
| `--coverage` | Add a type-precision coverage block to the output (`coverage` object under `--format json`; a one-line summary in text mode). Off by default — it is a second precision pass over the analyzed files, the same scan [`rigor coverage`](#rigor-coverage) runs, so it is opt-in. |
|
|
44
|
+
| `--workers=N` | Dispatch analysis across `N` parallel worker processes (fork-based pool today; ADR-15). Default `0` (sequential). |
|
|
45
|
+
| `--baseline=PATH` | Load a baseline file, overriding config. |
|
|
46
|
+
| `--no-baseline` | Ignore any configured baseline. |
|
|
47
|
+
| `--baseline-strict` | Fail the run on any baseline drift — a CI gate. |
|
|
48
|
+
| `--treat-all-as-inline-rbs` | Force-load `rigor-rbs-inline` with `require_magic_comment: false`, so every analysed file is treated as inline-RBS without the `# rbs_inline: enabled` comment (ADR-32). |
|
|
49
|
+
| `--bleeding-edge[=ids]` | Adopt the bleeding-edge overlay for this run, overriding the configured [`bleeding_edge:`](03-configuration.md) selection (ADR-50 § WD2). Bare adopts every queued feature; `--bleeding-edge=a,b` adopts only the named feature ids. The overlay is empty in this release, so this is currently a no-op. Inspect it with [`rigor show-bleedingedge`](#rigor-show-bleedingedge). |
|
|
50
|
+
| `--no-bleeding-edge` | Ignore any configured `bleeding_edge:` selection for this run (adopt none). |
|
|
51
|
+
| `--tmp-file=PATH --instead-of=PATH` | Editor mode: analyse `PATH` using the buffer in `--tmp-file`. Both required together. |
|
|
52
|
+
|
|
53
|
+
Exit `0` when no error-severity diagnostics remain, `1` when
|
|
54
|
+
any are reported, `64` on a usage error.
|
|
55
|
+
|
|
56
|
+
## `rigor init`
|
|
57
|
+
|
|
58
|
+
Write a starter configuration file.
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
rigor init [--path=PATH] [--force]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Writes `.rigor.dist.yml` by default. `--path` chooses a
|
|
65
|
+
different target; `--force` overwrites an existing file.
|
|
66
|
+
Exit `1` if the file exists and `--force` was not given.
|
|
67
|
+
|
|
68
|
+
## `rigor annotate`
|
|
69
|
+
|
|
70
|
+
Reprint a file with every line tagged by the type of the
|
|
71
|
+
expression it evaluates to, as a trailing `#=>` comment. See
|
|
72
|
+
[Inspecting inferred types](05-inspecting-types.md).
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
rigor annotate [--[no-]color] [--[no-]bat] [--format=text|json] [--config=PATH] FILE
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`FILE` is required. Colour is auto-detected for a tty and
|
|
79
|
+
honours `NO_COLOR`; `--color` / `--no-color` override. When
|
|
80
|
+
colour is on and [`bat`](https://github.com/sharkdp/bat) is on
|
|
81
|
+
`PATH`, highlighting goes through bat (`--no-bat` opts out;
|
|
82
|
+
`--bat` warns if bat is missing and falls back to the built-in
|
|
83
|
+
colorizer). `--format=json` emits a `{ line => type }` map
|
|
84
|
+
instead of the annotated source. Exit `1` on a parse error or a
|
|
85
|
+
missing file.
|
|
86
|
+
|
|
87
|
+
## `rigor type-of`
|
|
88
|
+
|
|
89
|
+
Print the inferred type at one source position.
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
rigor type-of FILE:LINE:COL
|
|
93
|
+
rigor type-of FILE LINE COL
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Accepts the position as a single `file:line:col` triple or as
|
|
97
|
+
three arguments. `--format=json` emits a machine-readable
|
|
98
|
+
form; `--trace` records fail-soft fallbacks. The editor-mode
|
|
99
|
+
`--tmp-file` / `--instead-of` pair is accepted as on `check`.
|
|
100
|
+
|
|
101
|
+
## `rigor trace`
|
|
102
|
+
|
|
103
|
+
Replay HOW the engine typed a file, step by step, as a
|
|
104
|
+
terminal animation. It is a teaching probe over the same
|
|
105
|
+
inference `rigor check` runs.
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
rigor trace [--delay=SECONDS] [--line=N] [--verbose] [--format=json] FILE
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Each frame highlights the source range being evaluated next to
|
|
112
|
+
the scope's locals and describes one inference moment: a local
|
|
113
|
+
binding entering the scope (`bind`), branch types merging
|
|
114
|
+
(`union`), or a method call resolving — or fail-softening to
|
|
115
|
+
`Dynamic[top]` (`dispatch`). On a tty the replay steps on a key
|
|
116
|
+
press (`q` quits); `--delay` autoplays. `--verbose` adds every
|
|
117
|
+
expression enter/result frame, `--line=N` keeps only events on
|
|
118
|
+
one line, and `--format=json` dumps the raw event stream for
|
|
119
|
+
tooling or course material. See
|
|
120
|
+
[Inspecting inferred types](05-inspecting-types.md).
|
|
121
|
+
|
|
122
|
+
## `rigor type-scan`
|
|
123
|
+
|
|
124
|
+
Report `type_of` inference coverage across paths — a
|
|
125
|
+
diagnostic-of-the-diagnoser, useful when investigating why a
|
|
126
|
+
class infers poorly.
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
rigor type-scan PATH...
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`--limit=N` caps the printed examples (default 10),
|
|
133
|
+
`--show-recognized` includes fully-covered classes,
|
|
134
|
+
`--threshold=RATIO` makes the command exit non-zero when the
|
|
135
|
+
unrecognized-node ratio exceeds `RATIO`, and `--format=text|json`
|
|
136
|
+
selects the output format.
|
|
137
|
+
|
|
138
|
+
## `rigor explain`
|
|
139
|
+
|
|
140
|
+
Print the catalogue entry for a diagnostic rule, or list every
|
|
141
|
+
rule when called with no argument.
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
rigor explain [rule]
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`rule` is a rule ID (`call.undefined-method`), a legacy alias,
|
|
148
|
+
or a family wildcard (`call`, `flow`, `def`, `assert`, `dump`).
|
|
149
|
+
`--format=json` is available. Exit `64` for an unknown rule.
|
|
150
|
+
|
|
151
|
+
## `rigor diff`
|
|
152
|
+
|
|
153
|
+
Compare the current diagnostics against a saved baseline JSON
|
|
154
|
+
and report only what is new.
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
rigor diff <baseline.json> [paths...]
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`--current=PATH` compares against a saved diagnostics JSON
|
|
161
|
+
instead of running a fresh check. Exit `1` when new
|
|
162
|
+
diagnostics appear.
|
|
163
|
+
|
|
164
|
+
## `rigor sig-gen`
|
|
165
|
+
|
|
166
|
+
Emit RBS signatures inferred from your Ruby source. See
|
|
167
|
+
[handbook chapter 11](../handbook/11-sig-gen.md) for the
|
|
168
|
+
classification model and the `--params` policy.
|
|
169
|
+
|
|
170
|
+
```sh
|
|
171
|
+
rigor sig-gen [paths]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
| Option | Effect |
|
|
175
|
+
| --- | --- |
|
|
176
|
+
| `--print` | Write RBS to stdout. Default. |
|
|
177
|
+
| `--diff` | Write a unified diff against existing RBS. |
|
|
178
|
+
| `--write` | Write RBS to `sig/<path>.rbs` files. |
|
|
179
|
+
| `--overwrite` | Allow tighter-return updates to replace user-authored RBS. |
|
|
180
|
+
| `--include-private` | Emit private and protected methods too. |
|
|
181
|
+
| `--params=untyped\|observed\|observed-strict` | Parameter-typing policy. Default `untyped`. |
|
|
182
|
+
| `--observe=PATH` | Scan `PATH` for call-site observations. Repeatable. |
|
|
183
|
+
| `--new-files` / `--new-methods` / `--tighter-returns` | Emit only that classification. |
|
|
184
|
+
| `--format=text\|json` | Output format. |
|
|
185
|
+
|
|
186
|
+
## `rigor lsp`
|
|
187
|
+
|
|
188
|
+
Run the Language Server over stdio. See
|
|
189
|
+
[Editor integration](09-editor-integration.md).
|
|
190
|
+
|
|
191
|
+
```sh
|
|
192
|
+
rigor lsp [--transport=stdio] [--log=PATH] [--config=PATH]
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`stdio` is the only transport in v1. `--log=PATH` is accepted
|
|
196
|
+
but not yet wired in this release — it is reserved for routing
|
|
197
|
+
the server's wire log to a file; until then logging stays on
|
|
198
|
+
stderr.
|
|
199
|
+
|
|
200
|
+
## `rigor baseline`
|
|
201
|
+
|
|
202
|
+
Manage diagnostic baselines. See [Baselines](06-baseline.md)
|
|
203
|
+
for the file format and workflow.
|
|
204
|
+
|
|
205
|
+
```sh
|
|
206
|
+
rigor baseline <generate|regenerate|dump|drift|prune> [options]
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
| Subcommand | Purpose |
|
|
210
|
+
| --- | --- |
|
|
211
|
+
| `generate` | Write a fresh baseline from the current diagnostics. Refuses to overwrite without `--force`. |
|
|
212
|
+
| `regenerate` | Rewrite the baseline unconditionally — use after a quality pass. |
|
|
213
|
+
| `dump` | Print the baseline contents, filterable by `--rule` and `--file`. |
|
|
214
|
+
| `drift` | Audit how each bucket has drifted; filter with `--only=within\|over\|cleared\|reducible`. |
|
|
215
|
+
| `prune` | Drop buckets that no longer match any diagnostic. `--dry-run` previews. |
|
|
216
|
+
|
|
217
|
+
`generate` and `regenerate` accept `--output=PATH` and
|
|
218
|
+
`--match-mode=rule|message`; `dump`, `drift`, and `prune` accept
|
|
219
|
+
`--baseline=PATH` to read a non-default baseline file.
|
|
220
|
+
|
|
221
|
+
## `rigor triage`
|
|
222
|
+
|
|
223
|
+
Summarise a diagnostic stream — rule distribution, **class/method
|
|
224
|
+
selectors**, per-file hotspots, and heuristic "why" hints — instead
|
|
225
|
+
of dumping the raw list. See [Baselines](06-baseline.md).
|
|
226
|
+
|
|
227
|
+
```sh
|
|
228
|
+
rigor triage [paths]
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
`--top=N` sets the hotspot count (default 10); `--hints-only`,
|
|
232
|
+
`--selectors-only`, and `--no-hints` select which sections print.
|
|
233
|
+
`triage` is advisory and always exits `0` — it never gates a build.
|
|
234
|
+
|
|
235
|
+
By default the distribution, selectors, and hotspots sections count
|
|
236
|
+
only the **actionable** diagnostics (`error` + `warning`). `info`
|
|
237
|
+
diagnostics are excluded from these volume views — on a Rails project
|
|
238
|
+
they are dominated by plugin *recognition trace* (`Account.find
|
|
239
|
+
resolves to Account`, `users_path → GET /users`), positive "Rigor
|
|
240
|
+
resolved this" records that would otherwise bury the genuine signal
|
|
241
|
+
and skew the hotspot ranking toward the files with the most *working*
|
|
242
|
+
code. The summary line still reports the full `info` count, and
|
|
243
|
+
heuristic hints still see every diagnostic (so the `gem-without-rbs`
|
|
244
|
+
notice survives). Pass `--include-info` to route `info` into the
|
|
245
|
+
volume views as well.
|
|
246
|
+
|
|
247
|
+
The **`selectors`** section is the by-(class, method) axis: it
|
|
248
|
+
aggregates the structured `receiver_type` / `method_name` fields the
|
|
249
|
+
diagnostics carry into `{receiver, method, count, files, rules}`
|
|
250
|
+
rows, so you can ask "which method concentrates the diagnostics?"
|
|
251
|
+
without parsing message text. Under `--format json` the full list is
|
|
252
|
+
emitted, keyed on a normalised receiver class (literals fold to their
|
|
253
|
+
class), ready for a `jq` query:
|
|
254
|
+
|
|
255
|
+
```sh
|
|
256
|
+
# methods with diagnostics spread across ≥ 3 files (systemic clusters)
|
|
257
|
+
rigor triage --format json | jq '.selectors[] | select(.files >= 3)'
|
|
258
|
+
# everything Rigor flagged on String receivers, by method
|
|
259
|
+
rigor triage --format json | jq '[.selectors[] | select(.receiver == "String")]'
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The same `receiver_type` / `method_name` fields ride on each
|
|
263
|
+
diagnostic of `rigor check --format json`, for per-site (rather than
|
|
264
|
+
aggregated) grouping.
|
|
265
|
+
|
|
266
|
+
## `rigor coverage`
|
|
267
|
+
|
|
268
|
+
> For the value proposition and a workflow guide to the
|
|
269
|
+
> `--protection` tiers, see
|
|
270
|
+
> [Type-protection coverage](15-type-protection-coverage.md). This
|
|
271
|
+
> section is the flag reference.
|
|
272
|
+
|
|
273
|
+
Report type-precision coverage — the ratio of call sites that
|
|
274
|
+
resolve to a precise type versus those that fall back to
|
|
275
|
+
`Dynamic`. A quality gate for "how much is Rigor actually
|
|
276
|
+
inferring".
|
|
277
|
+
|
|
278
|
+
```sh
|
|
279
|
+
rigor coverage [paths]
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
`--format=text|json` selects the output format and
|
|
283
|
+
`--config=PATH` overrides config discovery. `--threshold=RATIO`
|
|
284
|
+
exits `1` when the precision ratio falls below `RATIO`
|
|
285
|
+
(`0.0`–`1.0`), making it a CI gate.
|
|
286
|
+
|
|
287
|
+
`--protection` switches to **type-protection coverage**: it
|
|
288
|
+
reports "if I introduce a bug, would Rigor catch it" rather than
|
|
289
|
+
"how precise are my types". Each dispatch site (a call with an
|
|
290
|
+
explicit receiver) is *protected* when the receiver types to a
|
|
291
|
+
concrete class (a site where Rigor's call rules can catch a
|
|
292
|
+
wrong method or argument) and *unprotected* when the receiver is
|
|
293
|
+
`Dynamic`. The report leads with the protected ratio, then a
|
|
294
|
+
ranked "add a type here" list (the methods most often called on
|
|
295
|
+
an untyped receiver), then the least-protected files;
|
|
296
|
+
`--threshold` and `--format=json` work the same. It is a sound
|
|
297
|
+
upper bound on real protection — a concrete receiver is necessary
|
|
298
|
+
but not sufficient for a diagnostic to fire.
|
|
299
|
+
|
|
300
|
+
Adding `--mutation` (with `--protection`) switches to the
|
|
301
|
+
**effectiveness** tier: it measures whether Rigor *does* catch a
|
|
302
|
+
bug, rather than whether it *could*. It introduces
|
|
303
|
+
type-visible breakages at each dispatch site — dropping a
|
|
304
|
+
call-argument to `nil`, swapping its type, renaming a call to a
|
|
305
|
+
missing method — re-analyses the mutated source against a clean
|
|
306
|
+
baseline, and reports the kill rate (caught breakages). It
|
|
307
|
+
defaults to the git-changed `.rb` files (whole-project is
|
|
308
|
+
minutes; pass explicit paths to widen), and leads with the
|
|
309
|
+
effectiveness ratio, then the breakages Rigor missed ("add a type
|
|
310
|
+
here"), then the least-effective files. `--threshold` gates on
|
|
311
|
+
the effectiveness ratio and `--format=json` carries `mode`,
|
|
312
|
+
`killed`, `survived`, `effectiveness_ratio`, per-file rows, and
|
|
313
|
+
`add_a_type_here`. It is the truth tier behind the static
|
|
314
|
+
`--protection` proxy, at the cost of many analyses — an opt-in CI
|
|
315
|
+
deep-dive, not an interactive check.
|
|
316
|
+
|
|
317
|
+
```sh
|
|
318
|
+
rigor coverage --protection --mutation [paths]
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Adding `--with-tests` (with `--protection --mutation`) turns
|
|
322
|
+
that into the **fused static∪dynamic** view: for each breakage
|
|
323
|
+
the type checker does *not* catch, it runs your test suite to see
|
|
324
|
+
whether a **test** catches it. Each site is then classified
|
|
325
|
+
`type-protected` (the type checker caught it), `test-protected`
|
|
326
|
+
(a test caught what the type checker missed), or `unprotected`
|
|
327
|
+
(neither — the actionable "add a type **or** a test here" list),
|
|
328
|
+
and the report names the cheaper missing axis. A type-killed
|
|
329
|
+
mutant never reaches the suite (a gradual short-circuit), so the
|
|
330
|
+
cost is proportional to the protection hole. `--format=json`
|
|
331
|
+
carries `mode` (`protection-fused`), `type_killed`,
|
|
332
|
+
`test_killed`, `unprotected`, `protected_ratio`, per-file rows,
|
|
333
|
+
and `add_protection_here`; `--threshold` gates on the fused
|
|
334
|
+
ratio.
|
|
335
|
+
|
|
336
|
+
`--test-command=CMD` is the runner hook (default
|
|
337
|
+
`bundle exec rake`). The suite must pass on clean code first, or
|
|
338
|
+
the run aborts — point it at a plain pass/fail runner (a coverage
|
|
339
|
+
floor that exits non-zero on a passing suite trips this). It runs
|
|
340
|
+
with Bundler's environment stripped, so a `bundle exec` command
|
|
341
|
+
resolves your project's bundle even when Rigor itself was
|
|
342
|
+
launched under its own, with no env wrapper needed. The command
|
|
343
|
+
runs **without a shell** (it is split into an argv and executed
|
|
344
|
+
directly), so shell constructs are not interpreted — including an
|
|
345
|
+
inline `BUNDLE_GEMFILE=… ` prefix. For a non-default Gemfile, set
|
|
346
|
+
it with `bundle config set --local gemfile PATH` (it persists in
|
|
347
|
+
`.bundle/config`) or wrap the command in `bash -c '…'`.
|
|
348
|
+
|
|
349
|
+
`--include-dynamic` extends the overlay to `Dynamic`-receiver
|
|
350
|
+
(untyped) sites, where a test is the only possible protection —
|
|
351
|
+
completing the map to *every* dispatch site rather than only the
|
|
352
|
+
ones Rigor can type-check. Every such site is a type-survivor, so
|
|
353
|
+
it runs the suite far more; it is an explicit opt-in.
|
|
354
|
+
|
|
355
|
+
`--limit=N` (with `--seed=N`, default `1`) caps the measurement
|
|
356
|
+
to a deterministic sample of `N` mutations per file, bounding the
|
|
357
|
+
cost on large files. Per-file ratios then become estimates, noted
|
|
358
|
+
on stderr so `--format=json` stdout stays clean.
|
|
359
|
+
|
|
360
|
+
```sh
|
|
361
|
+
rigor coverage --protection --mutation --with-tests \
|
|
362
|
+
--test-command "bundle exec rspec" --include-dynamic [paths]
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## `rigor mcp`
|
|
366
|
+
|
|
367
|
+
Run the Rigor MCP (Model Context Protocol) server over stdio,
|
|
368
|
+
so AI coding assistants can call Rigor tools directly. See
|
|
369
|
+
[MCP server](10-mcp-server.md).
|
|
370
|
+
|
|
371
|
+
```sh
|
|
372
|
+
rigor mcp [--transport=stdio] [--config=PATH]
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
`stdio` is the only transport. The server is a pure-Ruby
|
|
376
|
+
JSON-RPC 2.0 implementation exposing seven read-only tools:
|
|
377
|
+
`rigor_check`, `rigor_type_of`, `rigor_triage`,
|
|
378
|
+
`rigor_annotate`, `rigor_sig_gen`, `rigor_explain`,
|
|
379
|
+
`rigor_coverage`.
|
|
380
|
+
|
|
381
|
+
## `rigor lsp` vs `rigor mcp`
|
|
382
|
+
|
|
383
|
+
`lsp` speaks the Language Server Protocol to editors; `mcp`
|
|
384
|
+
speaks the Model Context Protocol to AI assistants. Both run
|
|
385
|
+
over stdio and wrap the same analysis engine.
|
|
386
|
+
|
|
387
|
+
## `rigor plugins`
|
|
388
|
+
|
|
389
|
+
Report the activation status of every plugin configured in
|
|
390
|
+
`.rigor.yml` — loaded, load-error (with reason), and each
|
|
391
|
+
plugin's declared extension surfaces. See [Plugins](07-plugins.md).
|
|
392
|
+
|
|
393
|
+
```sh
|
|
394
|
+
rigor plugins [--format=text|json] [--strict] [--capabilities] [--config=PATH]
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Without `--strict` the command always exits `0`; with
|
|
398
|
+
`--strict` it exits `1` when any plugin failed to load (a CI
|
|
399
|
+
gate).
|
|
400
|
+
|
|
401
|
+
`--capabilities` switches to the **extension-protocol
|
|
402
|
+
catalogue** ([ADR-37](../adr/37-plugin-interface-segregation.md)):
|
|
403
|
+
a focused, machine-readable map of what each loaded plugin
|
|
404
|
+
contributes — the AST node types its `node_rule`s match, the
|
|
405
|
+
receiver classes its `dynamic_return`s gate on, the methods its
|
|
406
|
+
`type_specifier`s narrow, and the facts it `produces` /
|
|
407
|
+
`consumes`. Combine with `--format=json` for tooling (an AI
|
|
408
|
+
agent can enumerate every plugin's behaviour without reading a
|
|
409
|
+
line of plugin source). The same narrow surfaces also appear in
|
|
410
|
+
the default full report. Not to be confused with the singular
|
|
411
|
+
`rigor plugin`.
|
|
412
|
+
|
|
413
|
+
## `rigor plugin`
|
|
414
|
+
|
|
415
|
+
Browse the on-disk source of the plugins bundled in the
|
|
416
|
+
toolchain, so you can read a real, working plugin as a worked
|
|
417
|
+
example when authoring your own.
|
|
418
|
+
|
|
419
|
+
```sh
|
|
420
|
+
rigor plugin <list|path|print|root> [name]
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
| Subcommand | Purpose |
|
|
424
|
+
| --- | --- |
|
|
425
|
+
| `list` | Table of every bundled plugin and example, name + absolute directory path (default when no subcommand given). |
|
|
426
|
+
| `path <name>` | One-line absolute path to the plugin's directory. |
|
|
427
|
+
| `print <name>` | A header (dir / lib / sig / README paths) followed by the plugin's main source body inlined. |
|
|
428
|
+
| `root` | The `rigortype` gem root and its key subdirectories. |
|
|
429
|
+
|
|
430
|
+
Paths resolve at runtime from the gem location (a documented
|
|
431
|
+
caveat for container / cross-filesystem setups).
|
|
432
|
+
|
|
433
|
+
## `rigor playground`
|
|
434
|
+
|
|
435
|
+
Start the browser playground (a CodeMirror editor with
|
|
436
|
+
real-time diagnostics). Requires the separate `rigor-playground`
|
|
437
|
+
gem; if it is not installed the command prints an install hint
|
|
438
|
+
and exits `64`.
|
|
439
|
+
|
|
440
|
+
```sh
|
|
441
|
+
rigor playground
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## `rigor skill`
|
|
445
|
+
|
|
446
|
+
List or print the bundled Agent Skills shipped inside the
|
|
447
|
+
`rigortype` gem, so an AI coding agent installed alongside
|
|
448
|
+
Rigor can discover and follow them without a project-side
|
|
449
|
+
source checkout. See [Skills](08-skills.md).
|
|
450
|
+
|
|
451
|
+
The positional slot is a skill *name*; alternative outputs are flags,
|
|
452
|
+
so a skill can never be shadowed by a verb.
|
|
453
|
+
|
|
454
|
+
```sh
|
|
455
|
+
rigor skill [<name>] [--path <name>] [--list] [--describe]
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
| Form | Purpose |
|
|
459
|
+
| --- | --- |
|
|
460
|
+
| (none) / `--list` | Table of every bundled skill (name + absolute path). |
|
|
461
|
+
| `<name>` | Print the `SKILL.md` body to stdout, with a header pointing at the skill's `references/` directory. |
|
|
462
|
+
| `--path <name>` | Print the single-line absolute `SKILL.md` path, suitable as input to a file-reading tool. |
|
|
463
|
+
| `--describe` | Probe the project's state (config / baseline / `sig/` / CI — presence only, never runs `rigor check`) and recommend the next skill to run. Also spelled `describe`; surfaced top-level as [`rigor describe`](#rigor-describe) below. |
|
|
464
|
+
|
|
465
|
+
The verb spellings `rigor skill list` / `print <name>` / `path <name>`
|
|
466
|
+
are **deprecated** (a one-line stderr notice; removed in v0.3.0) — use
|
|
467
|
+
the forms above. `describe` / `--describe` stay first-class.
|
|
468
|
+
|
|
469
|
+
## `rigor describe`
|
|
470
|
+
|
|
471
|
+
Top-level alias for [`rigor skill describe`](#rigor-skill) — the
|
|
472
|
+
onboarding entry point that recommends the next skill for this project.
|
|
473
|
+
A bare `rigor describe` is the intuitive guess most users reach for
|
|
474
|
+
first, so it is surfaced as its own command ([ADR-73](../adr/73-skill-driven-user-experience.md)
|
|
475
|
+
§ WD2).
|
|
476
|
+
|
|
477
|
+
```sh
|
|
478
|
+
rigor describe
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
It reports a presence-only project-state probe (does a `.rigor.yml`,
|
|
482
|
+
`.rigor-baseline.yml`, `sig/` directory, or CI integration exist?) and a
|
|
483
|
+
recommended next skill. It is read-only and side-effect-free — it never
|
|
484
|
+
runs `rigor check`. Identical output to `rigor skill describe`.
|
|
485
|
+
|
|
486
|
+
## `rigor docs`
|
|
487
|
+
|
|
488
|
+
Print the documentation bundled inside the `rigortype` gem
|
|
489
|
+
**offline**, so once Rigor is installed an AI coding agent (or you) can
|
|
490
|
+
read the drive-Rigor guidance the SKILL-driven UX routes to without the
|
|
491
|
+
network ([ADR-74](../adr/74-offline-doc-access-and-llms-txt.md)). It is
|
|
492
|
+
the doc twin of [`rigor skill`](#rigor-skill): the gem ships
|
|
493
|
+
`docs/install.md`, `docs/llms.txt`, and the full user-facing
|
|
494
|
+
[manual](README.md) and [handbook](../handbook/README.md); the
|
|
495
|
+
contributor-facing ADR / spec / notes corpus stays web-only on the site.
|
|
496
|
+
|
|
497
|
+
The positional slot is a doc *name*; alternative outputs are flags.
|
|
498
|
+
|
|
499
|
+
```sh
|
|
500
|
+
rigor docs [<name>] [--path <name>] [--list [<category>]]
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
| Form | Purpose |
|
|
504
|
+
| --- | --- |
|
|
505
|
+
| (none) | Print the bundled `llms.txt` offline doc index — the map of what `rigor docs <name>` can serve. |
|
|
506
|
+
| `<name>` | Print a doc page to stdout, prefixed with a provenance comment. Accepts a category-qualified path (`handbook/03-narrowing`), the chapter's prefixed name (`02-cli-reference`), its short name (`cli-reference`, when unique), or `install`. |
|
|
507
|
+
| `--path <name>` | Print the single-line absolute path of a doc, suitable as input to a file-reading tool. |
|
|
508
|
+
| `--list [<category>]` | Table of every bundled doc (name + absolute path); pass `manual` or `handbook` to filter. |
|
|
509
|
+
|
|
510
|
+
The verb spellings `rigor docs list` / `path <name>` are **deprecated**
|
|
511
|
+
(a one-line stderr notice; removed in v0.3.0) — use `--list` / `--path`.
|
|
512
|
+
|
|
513
|
+
The canonical web copy of the index is
|
|
514
|
+
<https://rigor.typedduck.fail/llms.txt>; `rigor docs` serves the same
|
|
515
|
+
pages from the installed gem with no HTTP request.
|
|
516
|
+
|
|
517
|
+
## `rigor show-bleedingedge`
|
|
518
|
+
|
|
519
|
+
Print the **bleeding-edge overlay** — the Rigor-maintained set of
|
|
520
|
+
the next major's queued diagnostic disciplines ([ADR-50](../adr/50-release-engineering-and-stability-strategy.md)
|
|
521
|
+
§ WD2) — and report which of them the project's
|
|
522
|
+
[`bleeding_edge:`](03-configuration.md) configuration adopts. Read-only:
|
|
523
|
+
it loads `.rigor.yml` to resolve the active selection but runs no
|
|
524
|
+
analysis.
|
|
525
|
+
|
|
526
|
+
```sh
|
|
527
|
+
rigor show-bleedingedge [--config PATH] [--format text|json]
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
| Flag | Purpose |
|
|
531
|
+
| --- | --- |
|
|
532
|
+
| `--config PATH` | Use this `.rigor.yml` instead of auto-discovery. |
|
|
533
|
+
| `--format text\|json` | Output format. Default `text`. |
|
|
534
|
+
|
|
535
|
+
The overlay is **empty in this release** — the mechanism is wired and
|
|
536
|
+
ready, but no discipline has been queued for a major yet, so the command
|
|
537
|
+
currently reports an empty set. When a feature is queued it appears here
|
|
538
|
+
with its stable id, the severity it would impose, and whether your config
|
|
539
|
+
adopts it. See [`docs/compatibility.md`](../compatibility.md) for how
|
|
540
|
+
bleeding-edge fits the stability model.
|
|
541
|
+
|
|
542
|
+
## Environment variables
|
|
543
|
+
|
|
544
|
+
Most behaviour is driven by flags and `.rigor.yml`; a few
|
|
545
|
+
operational knobs read the environment instead.
|
|
546
|
+
|
|
547
|
+
| Variable | Effect |
|
|
548
|
+
| --- | --- |
|
|
549
|
+
| `NO_COLOR` | Disable coloured output (honoured by `rigor annotate`; `--no-color` does the same). |
|
|
550
|
+
| `RIGOR_CI_DETECT=0` | Turn off CI auto-detection — the same as `--no-ci-detect`. See [Running Rigor in CI § auto-detection](11-ci.md). |
|
|
551
|
+
| `RIGOR_RACTOR_WORKERS=N` | Worker count for parallel analysis. Sits between the CLI flag and the config key in precedence: `--workers=N` > `RIGOR_RACTOR_WORKERS` > `parallel.workers:` > `0` (sequential). |
|
|
552
|
+
| `RIGOR_POOL_BACKEND=ractor` | Opt back into the (off-by-default) Ractor worker pool instead of the active fork-based pool ([ADR-15](../adr/15-ractor-concurrency.md)). Only relevant with a non-zero worker count; the fork pool is the supported backend. |
|
|
553
|
+
| `RIGOR_PLUGIN_ISOLATION=none\|process\|ruby_box` | How a plugin's direct calls into its target library are isolated. Default `process`. See [Using plugins § Isolation strategy](07-plugins.md). `RIGOR_BOX` is a legacy alias for `ruby_box`. |
|
|
554
|
+
|
|
555
|
+
Three further variables (`RIGOR_BUDGET_TRACE`,
|
|
556
|
+
`RIGOR_HEAP_PROFILE`, `RIGOR_HEAP_TRACE`) enable developer-facing
|
|
557
|
+
diagnostics about Rigor's own inference cutoffs and memory — see
|
|
558
|
+
[Troubleshooting § Advanced diagnostics](13-troubleshooting.md#advanced-diagnostics).
|
|
559
|
+
|
|
560
|
+
## Exit codes
|
|
561
|
+
|
|
562
|
+
| Code | Meaning |
|
|
563
|
+
| --- | --- |
|
|
564
|
+
| `0` | Success — no error-severity diagnostics. |
|
|
565
|
+
| `1` | Diagnostics found, or a per-command failure (parse error, missing file, new diagnostics on `diff`). |
|
|
566
|
+
| `64` | Usage error — unknown command, bad flag, malformed argument. |
|
|
567
|
+
|
|
568
|
+
`rigor triage` is the exception: it is advisory and always
|
|
569
|
+
exits `0`.
|