rigortype 0.4.0 → 0.4.1

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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -3
  3. data/docs/handbook/08-understanding-errors.md +3 -2
  4. data/docs/install.md +87 -15
  5. data/docs/manual/02-cli-reference.md +2 -2
  6. data/docs/manual/03-configuration.md +5 -0
  7. data/docs/manual/08-skills.md +4 -3
  8. data/docs/manual/12-caching.md +43 -4
  9. data/docs/manual/14-rails-quickstart.md +19 -11
  10. data/lib/rigor/analysis/check_rules/source_arity.rb +163 -59
  11. data/lib/rigor/analysis/check_rules.rb +118 -87
  12. data/lib/rigor/analysis/dependency_recorder.rb +200 -18
  13. data/lib/rigor/analysis/incremental_run_slot/write_guard.rb +266 -0
  14. data/lib/rigor/analysis/incremental_run_slot.rb +171 -0
  15. data/lib/rigor/analysis/incremental_session.rb +273 -49
  16. data/lib/rigor/analysis/plugin_fact_fingerprint.rb +24 -13
  17. data/lib/rigor/analysis/reachability/scan_cache.rb +2 -1
  18. data/lib/rigor/analysis/run_cache_key.rb +27 -8
  19. data/lib/rigor/analysis/run_stats.rb +2 -2
  20. data/lib/rigor/analysis/runner/diagnostic_aggregator.rb +1 -1
  21. data/lib/rigor/analysis/runner/pool_coordinator.rb +2 -2
  22. data/lib/rigor/analysis/runner/project_pre_passes.rb +21 -13
  23. data/lib/rigor/analysis/runner.rb +337 -46
  24. data/lib/rigor/analysis/shadow_harness.rb +27 -0
  25. data/lib/rigor/analysis/source_rbs_gate.rb +157 -0
  26. data/lib/rigor/analysis/template_unit_paths.rb +6 -4
  27. data/lib/rigor/analysis/template_units.rb +15 -5
  28. data/lib/rigor/analysis/worker_session.rb +4 -3
  29. data/lib/rigor/cache/descriptor.rb +40 -1
  30. data/lib/rigor/cache/file_digest.rb +28 -0
  31. data/lib/rigor/cache/incremental_snapshot.rb +70 -8
  32. data/lib/rigor/cache/store.rb +63 -3
  33. data/lib/rigor/cache/value_digest.rb +325 -0
  34. data/lib/rigor/cli/check_command.rb +83 -13
  35. data/lib/rigor/cli/doctor_command.rb +1 -1
  36. data/lib/rigor/cli/effects_report.rb +2 -2
  37. data/lib/rigor/cli/unused_command.rb +3 -3
  38. data/lib/rigor/cli.rb +1 -1
  39. data/lib/rigor/config_audit.rb +3 -2
  40. data/lib/rigor/config_path.rb +29 -0
  41. data/lib/rigor/configuration/severity_profile.rb +5 -0
  42. data/lib/rigor/configuration.rb +6 -5
  43. data/lib/rigor/effects/plugin_facts.rb +6 -6
  44. data/lib/rigor/environment/bundle_sig_discovery.rb +5 -3
  45. data/lib/rigor/environment/lockfile_resolver.rb +10 -1
  46. data/lib/rigor/environment/rbs_collection_discovery.rb +10 -1
  47. data/lib/rigor/environment/rbs_loader.rb +1 -1
  48. data/lib/rigor/environment/source_rbs_synthesis.rb +147 -0
  49. data/lib/rigor/environment.rb +13 -70
  50. data/lib/rigor/inference/block_parameter_binder.rb +29 -13
  51. data/lib/rigor/inference/captured_locals.rb +7 -1
  52. data/lib/rigor/inference/declaration_walk/context.rb +195 -0
  53. data/lib/rigor/inference/declaration_walk/errors.rb +18 -0
  54. data/lib/rigor/inference/declaration_walk/shadow.rb +147 -0
  55. data/lib/rigor/inference/declaration_walk/traversal.rb +441 -0
  56. data/lib/rigor/inference/declaration_walk.rb +7 -0
  57. data/lib/rigor/inference/def_node_resolver.rb +3 -2
  58. data/lib/rigor/inference/definer_resolution.rb +266 -0
  59. data/lib/rigor/inference/expression_typer.rb +136 -45
  60. data/lib/rigor/inference/external_ancestor_resolution.rb +13 -16
  61. data/lib/rigor/inference/guard_rebinding.rb +53 -12
  62. data/lib/rigor/inference/macro_block_self_type.rb +14 -2
  63. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +46 -26
  64. data/lib/rigor/inference/module_function_state.rb +213 -0
  65. data/lib/rigor/inference/multi_target_binder.rb +21 -16
  66. data/lib/rigor/inference/narrowing.rb +147 -17
  67. data/lib/rigor/inference/parameter_inference_collector.rb +10 -9
  68. data/lib/rigor/inference/scope_indexer/certainty.rb +176 -0
  69. data/lib/rigor/inference/scope_indexer/class_cvars_collector.rb +35 -0
  70. data/lib/rigor/inference/scope_indexer/def_nestings_collector.rb +47 -0
  71. data/lib/rigor/inference/scope_indexer/layered_def_nestings.rb +36 -0
  72. data/lib/rigor/inference/scope_indexer/member_layouts_collector.rb +61 -0
  73. data/lib/rigor/inference/scope_indexer/mixin_accumulator.rb +130 -0
  74. data/lib/rigor/inference/scope_indexer/superclasses_collector.rb +64 -0
  75. data/lib/rigor/inference/scope_indexer.rb +1443 -295
  76. data/lib/rigor/inference/singleton_hook_decline.rb +253 -0
  77. data/lib/rigor/inference/statement_evaluator.rb +80 -14
  78. data/lib/rigor/plugin/base.rb +28 -8
  79. data/lib/rigor/plugin/io_boundary.rb +82 -4
  80. data/lib/rigor/plugin/isolation.rb +1 -1
  81. data/lib/rigor/plugin/trust_policy.rb +3 -3
  82. data/lib/rigor/protection/discovery_seed.rb +18 -9
  83. data/lib/rigor/protection/mutation_cache.rb +3 -3
  84. data/lib/rigor/reflection/constant_ancestors.rb +96 -47
  85. data/lib/rigor/reflection/constant_path.rb +22 -7
  86. data/lib/rigor/reflection.rb +2 -3
  87. data/lib/rigor/scope/discovery_index.rb +218 -2
  88. data/lib/rigor/scope/resolution_chain/relevance.rb +165 -0
  89. data/lib/rigor/scope/resolution_chain.rb +884 -0
  90. data/lib/rigor/scope.rb +295 -322
  91. data/lib/rigor/sig_gen/alias_index.rb +1 -1
  92. data/lib/rigor/sig_gen/effect_annotation.rb +2 -2
  93. data/lib/rigor/sig_gen/generator.rb +22 -16
  94. data/lib/rigor/type/combinator.rb +25 -1
  95. data/lib/rigor/version.rb +1 -1
  96. data/plugins/rigor-ffi/lib/rigor/plugin/ffi.rb +10 -0
  97. data/sig/rigor/environment.rbs +2 -0
  98. data/sig/rigor/plugin/io_boundary.rbs +1 -0
  99. data/sig/rigor/scope.rbs +43 -1
  100. data/skills/rigor-project-init/SKILL.md +37 -11
  101. data/skills/rigor-project-init/references/02-configure.md +7 -2
  102. metadata +25 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 96e337b134c8bcb33bf20707e88ffbe16ff98b94513d483043e18432d9bf6328
4
- data.tar.gz: e46a5af02a699ef2d0ad41e7b8b94e2d5eac02d1085d30fc03831df208ef930e
3
+ metadata.gz: c26e2df607ebe3e1ef3b0c34a329aea4b1b0c80ec311cf6d9a83c4a58a358dfa
4
+ data.tar.gz: 2c4097594c8abe73819197a867cbb9a7b7dc3de86d8a2f22a2a83b1f948fa63a
5
5
  SHA512:
6
- metadata.gz: cc7a7cadf53373e66de5ff268b2a44452d42972cbd9c1683825e2809480573bf195d9c26252d0522ddac2ae3f39f9dc665768d61cbb7c6e63ee6d60eaa17b87a
7
- data.tar.gz: 05b82b8662a6e5b0283a04eca851d0bb6aa1031f55fd1e99525c5b884e433a30b89d519486f6fceebca95e47a306f721766adecc13d4c68134c833e9e525304a
6
+ metadata.gz: d790e8fdb333983f82d85fb13036661ef87ca82d273b86955e1c7fa3191a65d027a04ea92fb4877edeb24f3df6bdae4dc03780791a79b15510ea5c7b494f23b6
7
+ data.tar.gz: b1258c842c5e656aea59b32eb91310cdda72a9dade402c87d2523bae3e4fa927f6607b0e2acd4250d24bfcba77e27df778aaf02c50c57300b6c27099c312c098
data/README.md CHANGED
@@ -91,8 +91,9 @@ It installs Rigor, then runs the bundled **`rigor-project-init`**
91
91
  [Agent Skill](https://agentskills.io/): it walks your `Gemfile`,
92
92
  proposes plugins matched to your stack (Rails, Sinatra, dry-rb, …),
93
93
  lets you pick an adoption mode — **baseline** (acknowledge existing
94
- diagnostics, work them down incrementally) or **strict**
95
- (zero-diagnostic gate from day one) — and commits a ready-to-use
94
+ diagnostics, work them down incrementally; the recommended
95
+ default) or **strict** (zero-diagnostic gate from day one, an
96
+ opt-in for users fluent in type theory and RBS) — and commits a ready-to-use
96
97
  configuration.
97
98
 
98
99
  **This works in your language.** The prompt is plain natural
@@ -231,7 +232,7 @@ rigor docs --list # list every bundled page
231
232
 
232
233
  ## Status
233
234
 
234
- Current release: **`v0.4.0`** (2026-09-27) — opening the
235
+ Current release: **`v0.4.1`** (2026-10-08) — on the
235
236
  `0.4.x` line, continuing the evaluation era opened by `v0.2.0`, the first
236
237
  publicly-announced (general / evaluation) release. The line publishes
237
238
  an enumerated [compatibility surface](docs/compatibility.md) as a
@@ -114,8 +114,9 @@ mostly a question of *how much* you want to say:
114
114
 
115
115
  1. **`severity_profile:`** — the project's overall stance.
116
116
  `lenient` for a legacy codebase you are easing Rigor into,
117
- `balanced` for everyday work, `strict` for a project with
118
- no legacy noise.
117
+ `balanced` for everyday work, new projects included, and
118
+ `strict` only if you are ready to resolve inference gaps
119
+ through signatures and RBS yourself.
119
120
  2. **`severity_overrides:`** — one rule (or one family) at a
120
121
  different severity from the rest of the profile. The right
121
122
  layer when a rule is *useful but not blocking* for you.
data/docs/install.md CHANGED
@@ -10,19 +10,42 @@ skill (`rigor-project-init` for a project that has never run Rigor).
10
10
  **Do not add Rigor to the project's `Gemfile`** — Rigor is a
11
11
  standalone tool, not a library.
12
12
 
13
+ **Install the latest release, not whatever is already on the
14
+ machine.** A `rigor` already on PATH, or a version manager that
15
+ resolves to an older release, is not a reason to stop early: Rigor
16
+ changes quickly, and the skills this guide hands off to are written
17
+ for the current release. Step 1 looks up the latest version; Step 2
18
+ installs it and Step 3 checks it.
19
+
13
20
  ---
14
21
 
15
22
  ## Step 1 — Detect the environment
16
23
 
17
- Run these four checks and note which tools are available:
24
+ Run these checks and note which tools are available:
18
25
 
19
26
  ```sh
20
27
  which mise # preferred — see Step 2A
21
28
  which asdf # fallback — see Step 2B
22
29
  ruby --version 2>/dev/null | head -1 # is Ruby 4.0 already on PATH?
23
- which docker # last resort — see Step 2D
30
+ which docker # last resort — see "Last resort — Docker"
31
+ rigor --version 2>/dev/null # an existing install, if any
32
+ ```
33
+
34
+ Then look up the latest Rigor release on RubyGems:
35
+
36
+ ```sh
37
+ curl -fsS https://rubygems.org/api/v1/versions/rigortype/latest.json
24
38
  ```
25
39
 
40
+ It prints `{"version":"X.Y.Z"}`. Below, `<LATEST>` stands for that
41
+ `X.Y.Z`: replace it with the version you got, never type `<LATEST>`
42
+ literally. Without `curl`, `gem search --remote --exact rigortype`
43
+ gives the same answer once Ruby is available. If neither works, tell
44
+ the user you could not determine the latest version instead of
45
+ guessing one.
46
+
47
+ An existing `rigor` older than `<LATEST>` still goes through Step 2;
48
+ tell the user which version they have and which you are installing.
26
49
  Then proceed to the **first** matching case below.
27
50
 
28
51
  ---
@@ -40,23 +63,51 @@ that can be committed alongside the code. Other contributors — and CI
40
63
  — run `mise install` to restore those versions with no `Gemfile`
41
64
  involvement.
42
65
 
43
- Run in the project root:
66
+ First ask mise which Rigor version it would pick:
67
+
68
+ ```sh
69
+ mise latest gem:rigortype
70
+ ```
71
+
72
+ If that is older than `<LATEST>`, mise is holding the newer release
73
+ back — usually its `minimum_release_age` quarantine, which hides
74
+ releases for a while after they are published (`mise ls-remote
75
+ gem:rigortype` then warns `1 newer gem:rigortype release hidden by
76
+ minimum_release_age` on stderr). A bare `mise use gem:rigortype`
77
+ would install the older version with no error, so this is the step where agents
78
+ silently end up on a stale Rigor. The quarantine is a supply-chain
79
+ safeguard, so do not bypass it on your own: tell the user both
80
+ versions and ask which to install. `mise settings get
81
+ minimum_release_age` tells you whose choice it is: an error ("not
82
+ set") means mise's built-in default is in effect and you can recommend
83
+ `<LATEST>`; a value means the user configured it, so recommend
84
+ respecting it.
85
+
86
+ Then run in the project root, with the version the user agreed to:
44
87
 
45
88
  ```sh
46
89
  mise use ruby@4.0
47
- mise use --pin gem:rigortype
90
+ mise use --pin gem:rigortype@<LATEST>
48
91
  ```
49
92
 
50
93
  `mise use` installs the tools and writes their versions to `mise.toml`
51
- in one step. Commit `mise.toml` so the version is shared.
94
+ in one step. Commit `mise.toml` so the version is shared. Name the
95
+ version explicitly, as above: an explicit version is installed even
96
+ while the quarantine hides it from `mise latest`.
52
97
 
53
- `--pin` records the exact Rigor version (`"gem:rigortype" = "0.2.9"`).
98
+ `--pin` records the exact Rigor version (`"gem:rigortype" = "X.Y.Z"`).
54
99
  Without it mise writes `"gem:rigortype" = "latest"`, which every
55
100
  machine re-resolves to whatever is newest when it first installs — so
56
101
  a committed `latest` does not give the team one shared version. The
57
102
  trade-off: a pin will not move on its own, and `mise outdated` cannot
58
- report a pinned tool as behind. Upgrade with `mise upgrade --bump
59
- gem:rigortype`.
103
+ report a pinned tool as behind. Upgrade by running `mise use --pin
104
+ gem:rigortype@<version>` again with the newer version; `mise upgrade
105
+ --bump gem:rigortype` goes through the same quarantine as a bare
106
+ `mise use`.
107
+
108
+ A user-wide `~/.config/mise/config.toml` entry for `gem:rigortype`
109
+ keeps applying outside this project. Mention it if it names an older
110
+ version, but do not edit global config without the user's consent.
60
111
 
61
112
  Then verify:
62
113
 
@@ -88,7 +139,8 @@ gem is installed with `gem install` after setting the Ruby version.
88
139
  ```sh
89
140
  asdf install ruby latest:4.0
90
141
  asdf local ruby latest:4.0
91
- gem install rigortype
142
+ gem install rigortype -v <LATEST>
143
+ asdf reshim ruby
92
144
  ```
93
145
 
94
146
  Verify:
@@ -108,7 +160,7 @@ pinning; see <https://mise.jdx.dev/getting-started.html>.
108
160
  If `ruby --version` reports `ruby 4.0.*`, install the gem directly:
109
161
 
110
162
  ```sh
111
- gem install rigortype
163
+ gem install rigortype -v <LATEST>
112
164
  ```
113
165
 
114
166
  Verify:
@@ -152,6 +204,11 @@ and does not integrate well with editor LSP. Use it only when a
152
204
  host-side Ruby 4.0 is genuinely unavailable (for example, Windows
153
205
  without WSL). For all other environments, prefer Case A–D above.
154
206
 
207
+ With Docker there is no `rigor` on the host PATH, so Step 3 checks the
208
+ image instead: `docker run --rm ghcr.io/rigortype/rigor:latest rigor
209
+ --version`. The image can trail RubyGems by a release; report its
210
+ version to the user rather than treating a mismatch as a failure.
211
+
155
212
  ---
156
213
 
157
214
  ## Step 3 — Verify the installation
@@ -160,8 +217,23 @@ without WSL). For all other environments, prefer Case A–D above.
160
217
  rigor --version
161
218
  ```
162
219
 
163
- A version string like `rigor 0.2.x` confirms a successful install.
164
- If the command is not found, revisit Step 2 for your case.
220
+ The reported version should be the one you installed in Step 2
221
+ (normally `<LATEST>`). If it is older, you are running a different
222
+ `rigor` than the one just installed. With mise, first check what the
223
+ project resolves to:
224
+
225
+ ```sh
226
+ mise exec -- rigor --version
227
+ mise which rigor
228
+ ```
229
+
230
+ If `mise exec` reports the new version, the shell's PATH is stale (a
231
+ non-interactive shell does not re-run mise's activation after `mise
232
+ use`); run `eval "$(mise hook-env)"`, or use `mise exec -- rigor` for
233
+ the remaining steps. Otherwise run `which -a rigor` to find the older
234
+ install. Do not uninstall anything to fix this without asking, and do
235
+ not continue on the older version without telling the user. If the
236
+ command is not found, revisit Step 2 for your case.
165
237
 
166
238
  ---
167
239
 
@@ -192,6 +264,6 @@ project is set up, re-run `rigor skill describe` for the step after
192
264
  that.
193
265
 
194
266
  If `rigor skill describe` is not recognised, your Rigor version predates
195
- it. Run `rigor --version` and upgrade with `mise upgrade --bump
196
- gem:rigortype` (or `gem update rigortype` for Case B/C); on an older
197
- version, run `rigor skill rigor-project-init` directly.
267
+ it: you are not on the version Step 1 found. Go back to Step 3. If
268
+ you are staying on an older version with the user's agreement, run
269
+ `rigor skill rigor-project-init` directly.
@@ -34,8 +34,8 @@ the `paths:` list from the configuration file.
34
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
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
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). |
37
+ | `--no-cache` | Skip the persistent cache for this run. With `--incremental` it is a cold full analysis: the incremental snapshot and the run-result cache are neither read nor written, so the next plain `--incremental` run still uses the snapshot it had before. |
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. A run with nothing changed is answered from the cache without starting the analyzer. See [Caching](12-caching.md). |
39
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
40
  | `--clear-cache` | Delete the cache directory before running. |
41
41
  | `--cache-stats` | Print the on-disk cache inventory when finished — on stdout under `--format text`, on stderr under every other format, so machine-readable output stays a parseable document. `--clear-cache`'s and `--verify-incremental`'s notes follow the same rule. |
@@ -21,6 +21,11 @@ discovery entirely.
21
21
 
22
22
  All relative paths in a config file resolve against that
23
23
  file's own directory.
24
+ A leading `~/` (or a bare `~`) in a path setting expands to your home directory; `~name` is an ordinary
25
+ directory called `~name`, not another user's home. This covers `paths:`, `signature_paths:`, `test_paths:`,
26
+ `pre_eval:`, `plugins_io.allowed_paths:`, `includes:`, `bundler.bundle_path:`, `bundler.lockfile:` and
27
+ `rbs_collection.lockfile:`. It does not apply to `cache.path:`, `baseline:` or `effects.snapshot.path:`, which stay
28
+ literal and relative to the working directory.
24
29
 
25
30
  ## Editor validation
26
31
 
@@ -60,9 +60,10 @@ is not repeated here.)
60
60
  - **`rigor-project-init`** — onboards a project from a cold start. It
61
61
  detects the stack (Rails, RSpec, dry-rb, …), proposes the matching
62
62
  [plugins](07-plugins.md), picks an adoption mode — a
63
- [baseline](06-baseline.md) snapshot for an existing codebase or a
64
- zero-diagnostic gate for a clean one — writes a `.rigor.dist.yml`, and
65
- generates the first baseline. Reach for it when setting Rigor up for
63
+ [baseline](06-baseline.md) snapshot by default, new projects
64
+ included, or an opt-in zero-diagnostic gate for users fluent in type
65
+ theory and RBS — writes a `.rigor.dist.yml`, and generates the first
66
+ baseline. Reach for it when setting Rigor up for
66
67
  the first time.
67
68
  - **`rigor-rbs-setup`** — installs community RBS for your gems
68
69
  (`rbs collection install`) so RBS-less dependencies stop typing as
@@ -135,7 +135,7 @@ CI detection that `auto` relies on.
135
135
 
136
136
  | Flag | Effect |
137
137
  | --- | --- |
138
- | `rigor check --no-cache` | Run without reading or writing the persistent cache. |
138
+ | `rigor check --no-cache` | Run without reading or writing the persistent cache. With `--incremental` this includes the snapshot: every file is analysed and the snapshot on disk is left untouched. |
139
139
  | `rigor check --clear-cache` | Delete the cache directory, then run. |
140
140
  | `rigor check --cache-stats` | Print the on-disk cache inventory when the run finishes (on stderr under every `--format` but `text`, so the document on stdout stays parseable). |
141
141
  | `rigor check --incremental` | Re-analyse only what changed; serve the rest from the incremental snapshot (see below). |
@@ -144,9 +144,12 @@ There is no config key to disable caching permanently — the
144
144
  flags are per-run toggles. To run without a persistent cache
145
145
  habitually, point `cache.path` at a disposable directory.
146
146
 
147
+ With `--incremental --no-cache` and an editor buffer (`--tmp-file` with `--instead-of`), the buffer is analysed on its own, as it is when no snapshot exists, and the note says that `--no-cache` skipped the snapshot rather than suggesting `rigor check --incremental`.
148
+
147
149
  ## Size and eviction
148
150
 
149
- A project's active cache set is small (around 2 MB). Entries
151
+ A project's active cache set is a few megabytes (about 10 MB
152
+ for a Rails application the size of Mastodon). Entries
150
153
  are content-keyed, so events like a gem upgrade or an `.rbs`
151
154
  edit write fresh entries and leave the old ones *orphaned* —
152
155
  nothing references them, and no run would otherwise delete
@@ -219,9 +222,45 @@ dependents of removed ones.) As with the rest of the cache, a
219
222
  missing or corrupt snapshot is simply a full run; it can never
220
223
  wedge analysis.
221
224
 
225
+ When nothing has changed since the last `--incremental` run, the
226
+ answer comes straight from the cache, without starting the
227
+ analyzer at all. Rigor first checks the inputs that answer was
228
+ computed from — your source files and view templates, your RBS,
229
+ your configuration and the files your plugins read — and runs the
230
+ ordinary incremental re-check the moment any of them differs. On
231
+ a Rails application the size of Mastodon, an unchanged
232
+ `--incremental` run takes about a quarter of a second. An
233
+ unchanged plain `rigor check` skips the analyzer the same way,
234
+ except when a plugin compiles your view templates, as
235
+ rigor-actionpack does.
236
+
237
+ The shortcut stands aside under `--workers=N` (or
238
+ `parallel.workers:`), `--explain`, `--cache-stats`, `--coverage`,
239
+ an editor buffer, and an `effects:` block, and when the cache
240
+ directory is on a different filesystem from the project; those
241
+ runs re-check as before. It also switches itself off, silently:
242
+
243
+ - when an input changes that the ordinary re-check does not look
244
+ at itself: an auto-detected `sig/` directory (one you did not
245
+ list under `signature_paths:`), a file a narrower
246
+ `rigor check --incremental DIR` only discovers from the rest of
247
+ your configured `paths:`, or a `pre_eval:` file outside the
248
+ analysed paths. The re-check may keep printing the answer from
249
+ before that change; the shortcut does not repeat it;
250
+ - when an `--incremental` run cannot record its answer safely:
251
+ after a run with `--workers=N` that re-analysed files, when a file or directory changes while a run is reading
252
+ it, after a CI cache is restored onto a fresh checkout, or when
253
+ two runs race.
254
+
255
+ Either way it stays off, and every run is an ordinary re-check,
256
+ until the next full analysis. The ordinary re-check never starts
257
+ one by itself: only a configuration, `Gemfile.lock` or Rigor
258
+ version change does, or `--clear-cache`. So the shortcut can stay
259
+ off indefinitely; run `rigor check --incremental --clear-cache`
260
+ once to turn it back on.
261
+
222
262
  `--incremental` is most useful for fast local re-checks and CI
223
- on a changed branch. For a one-shot run on an unchanged project,
224
- the ordinary cache already serves the whole result in one step.
263
+ on a changed branch.
225
264
 
226
265
  ## Concurrency
227
266
 
@@ -90,8 +90,9 @@ It runs eight phases in order:
90
90
  2. **Choose an adoption mode** — proposes either *acknowledge*
91
91
  (snapshot today's diagnostics into a baseline; catch
92
92
  regressions going forward) or *strict* (drive the project to
93
- zero and keep it there). It recommends acknowledge for
94
- codebases with more than ~100 initial diagnostics.
93
+ zero and keep it there). It recommends acknowledge for every
94
+ project, new ones included; strict is an opt-in for users
95
+ fluent in type theory and RBS.
95
96
  3. **Select plugins** — proposes the plugin set matching your
96
97
  detected stack; you confirm or trim the list.
97
98
  4. **Write `.rigor.dist.yml`** — the committed shared config,
@@ -151,14 +152,19 @@ source-of-truth copy is
151
152
 
152
153
  | Mode | When | What happens |
153
154
  | --- | --- | --- |
154
- | **Acknowledge** | Existing codebase with many diagnostics | Record today's diagnostics in a baseline; surface only new ones on each PR. |
155
- | **Strict** | New or small project | Zero outstanding diagnostics; no baseline. |
155
+ | **Acknowledge** | Recommended for every project, new ones included | Record today's diagnostics in a baseline; surface only new ones on each PR. |
156
+ | **Strict** | Opt-in, for users fluent in type theory and RBS | Zero outstanding diagnostics; no baseline. |
156
157
 
157
- If your first `rigor check` reports more than ~100 diagnostics,
158
- acknowledge mode is the natural starting point. You can tighten
159
- it later. In `.rigor.dist.yml` (Step 3) the mode maps to a
160
- `severity_profile:` — acknowledge → `lenient`, strict → `strict`
161
- (omit the key for the default `balanced`).
158
+ Start with acknowledge mode even on a brand-new project. Rigor's
159
+ inference still has gaps, so a zero-diagnostic gate meets
160
+ diagnostics on correct code, and clearing those means fixing
161
+ signatures or RBS rather than your code. Choose strict only if
162
+ you are comfortable doing that yourself. You can tighten later.
163
+
164
+ In `.rigor.dist.yml` (Step 3) the mode maps to a
165
+ `severity_profile:`. Acknowledge mode uses the default `balanced`
166
+ (omit the key), or `lenient` when the first `rigor check` reports
167
+ more than ~100 diagnostics; strict mode uses `strict`.
162
168
 
163
169
  ### Step 3 — Write .rigor.dist.yml
164
170
 
@@ -198,7 +204,7 @@ plugins:
198
204
  - rigor-rspec
199
205
  - rigor-factorybot
200
206
 
201
- severity_profile: lenient # "strict" for strict mode; omit for "balanced"
207
+ # severity_profile: lenient # only for >100 initial diagnostics; "strict" for strict mode
202
208
 
203
209
  # baseline: .rigor-baseline.yml # uncomment after Step 6 (acknowledge mode only)
204
210
  ```
@@ -288,7 +294,9 @@ first, then large clusters to record in a baseline.
288
294
 
289
295
  ### Step 6 — Generate a baseline (acknowledge mode)
290
296
 
291
- *Skip this step if you chose strict mode.*
297
+ *Skip this step if you chose strict mode.* Settle `severity_profile:`
298
+ first: changing it afterwards changes which rules fire and leaves the
299
+ baseline out of step.
292
300
 
293
301
  ```sh
294
302
  rigor baseline generate